EP147. “前台入口:第二个构建入口与 React 挂载”
🔒 登录后可标记已读📌 并入 EP146 的提醒:这一讲加载前台 JS 的写法(wp_enqueue_script() 只传 3 个参数),如果用的是传统主题没问题;但如果用的是新式 Block Theme,JS 可能会在页面/DOM 还没加载完时就执行,导致脚本找不到目标 HTML。解法是给 wp_enqueue_script() 补上第 4、5 个参数:wp_enqueue_script('attentionFrontend', ..., array('wp-element'), '1.0', true)——最后的 true 让 WordPress 把这个脚本放到页面底部(footer)加载,这样不管用传统主题还是 Block Theme 都能正常工作。
开始做 Quiz Block 的前台部分:新建一个独立的入口文件 frontend.js(区别于编辑器用的 index.js),要先把 @wordpress/scripts 的 build/start 命令配置成同时处理两个入口文件。前台渲染的思路是:PHP 只负责输出一个空的占位 <div>,真正的内容用前台 JS 里的 React(其实是 WordPress 包装过的同一份 React,不需要额外安装)把一个 Quiz 组件挂载到这个占位 div 里。同时确认了「只在真正用到这个 Block 的页面才加载前台资源」的实现技巧——把加载逻辑放进 render_callback 函数本身,而不是全局无条件加载。
涉及文件
wp-content/plugins/are-you-paying-attention/src/frontend.js(新建)wp-content/plugins/are-you-paying-attention/src/frontend.scss(新建,样式文件由课程直接提供下载,内容从略)wp-content/plugins/are-you-paying-attention/package.json(修改,build/start命令新增第二个入口)wp-content/plugins/are-you-paying-attention/index.php(修改)
代码实现
package.json:让构建命令同时处理两个入口文件:
"scripts": {
"build": "wp-scripts build src/index.js src/frontend.js",
"start": "wp-scripts start src/index.js src/frontend.js",
"test": "echo \"Error: no test specified\" && exit 1"
}
src/frontend.js(完整文件,先用占位文字确认渲染链路通了):
import React from 'react'
import ReactDOM from 'react-dom'
import "./frontend.scss"
const divsToUpdate = document.querySelectorAll(".paying-attention-update-me")
divsToUpdate.forEach(function(div) {
ReactDOM.render(<Quiz />, div)
div.classList.remove("paying-attention-update-me")
})
function Quiz() {
return (
<div className="paying-attention-frontend">
Hello from React
</div>
)
}
index.php:theHTML() 里按需加载前台资源、只输出一个占位 <div>:
function theHTML($attributes) {
if (!is_admin()) {
wp_enqueue_script('attentionFrontend', plugin_dir_url(__FILE__) . 'build/frontend.js', array('wp-element'));
wp_enqueue_style('attentionFrontendStyles', plugin_dir_url(__FILE__) . 'build/frontend.css');
}
ob_start(); ?>
<div class="paying-attention-update-me"></div>
<?php return ob_get_clean();
}
关键改动点:
@wordpress/scripts默认只认src/index.js一个入口,要处理第二个独立文件(frontend.js),得在package.json的build/start命令后面显式列出两个文件路径——这样编译产物会分别生成build/index.js(编辑器用)和build/frontend.js(前台用)两份独立的文件import React from 'react'/import ReactDOM from 'react-dom':即使从没执行过npm install react,也能直接这样导入——@wordpress/scripts的 Webpack 配置认识react/react-dom这两个包名,会自动转换成「去浏览器全局作用域找 WordPress 已经加载好的对应模块」(也就是wp.element背后的那份 React),而不是打包进产物、让访客重复下载一份- 前台渲染的核心两行:
document.querySelectorAll(".paying-attention-update-me")找出页面上所有本插件生成的占位<div>(一个页面可能有多个 Block 实例),.forEach()遍历后用ReactDOM.render(<Quiz />, div)把Quiz组件渲染进每一个占位元素——用 CSS class 选择器而不是 ID,正是因为要兼容「同一页面出现多个实例」的情况 - 渲染完成后用
div.classList.remove("paying-attention-update-me")把占位 class 去掉——这一步不是必须的,但为将来(比如懒加载场景下,新内容异步插入页面)区分「哪些 div 已经处理过、哪些还没处理」留了扩展空间 - 只在真正用到这个 Block 的页面才加载前台 JS/CSS 的实现技巧:不是在插件顶层无条件调用
wp_enqueue_script(),而是把加载逻辑写进render_callback(也就是theHTML())函数体内部——这个函数只有当前页面真的渲染到了这个 Block 的实例时才会被调用,所以借用它的调用时机来判断「现在需不需要加载前台资源」,比在全站范围判断「当前页面是否包含某个 Block」更简单直接 if (!is_admin())包住这两行——避免在后台编辑器页面(theHTML()callback 在编辑器预览时也可能被间接触发)重复加载前台专属的资源,前台资源只应该在真正面向公众的页面加载- WordPress 会自动去重:即使一个列表页同时显示 5、10 篇都用到这个 Block 的文章、
theHTML()被调用很多次,wp_enqueue_script()内部靠「短名」判断,同一个资源只会真正加载一次,不会重复加载 - 用打包产物的文件体积能验证「前台 JS 确实没有打包进 React/ReactDOM 完整副本」——作者提到自己编译出的
frontend.js只有 7KB 左右,而独立下载的 React + ReactDOM 有 100KB+,证明这份精简靠的正是复用 WordPress 已加载的wp-element
[截图:前台页面里 Quiz Block 占位 div 已被 React 替换成"Hello from React"文字,确认渲染链路打通]
Hook / Function 速查
| 名称 | 类型 | 用途 |
|---|---|---|
wp-scripts build/start <文件1> <文件2> | @wordpress/scripts 命令行参数 | 显式指定多个构建入口文件 |
is_admin() | WP 内建 function | 判断当前请求是否处于后台管理界面 |
ReactDOM.render(component, domElement) | React API(经 wp-element 提供) | 把一个 React 组件挂载渲染进指定的真实 DOM 元素 |
document.querySelectorAll(selector) | 浏览器原生 API | 选中所有匹配 CSS 选择器的元素,返回可遍历的 NodeList |
常见坑
- Block Theme 环境下前台 JS 加载时机过早、DOM 还没准备好——
wp_enqueue_script()第 5 个参数传true把脚本放到页面底部加载即可解决(EP146 已提醒) - 只在全局无条件加载前台资源,不管当前页面用没用到这个 Block——会让完全不相关的页面也白白加载额外的 JS/CSS,浪费访客带宽
- 前台渲染逻辑用
document.querySelector()(单数,只选中第一个)而不是querySelectorAll()——一个页面有多个 Block 实例时只会渲染第一个,其余的占位 div 会一直空着
延伸 / 后续讲座会用到
现在前台组件还只是显示占位文字,下一讲要打通「PHP 传下来的真实 attributes 数据」到「前台 React 组件」这条链路,让前台真正显示问题和答案选项。
Sources
Udemy:
- Become a WordPress Developer: Unlocking Power With Code — Section 25, EP147(含 EP146 提醒并入)