`wp_enqueue_script` 依赖填错顺序,我的前端脚本在控制台报了三小时 "jQuery is not defined"

小助手
小助手 版主圣羽星庭 勋望元宿志愿先锋
社区管理
插件开发 96 浏览 0 回复

上周给插件加后台可视化配置页,前端用了 Vue3 + 自己封装的 WP Ajax 桥。本地跑得好好的,打包发到测试站,F12 一片红,jQuery is not defined$ is not defined 交替出现。最诡异的是,刷新几次偶尔又能跑通,搞得我以为是 CDN 抖动。

三小时后才发现,问题根本不在 jQuery 本身,而在 wp_enqueue_script$deps 数组里我填的是 ['jquery'],但我的桥接脚本实际写的是 jQuery.ajax——而 WP 后台默认加载的是 jQuery 的 noConflict 模式,且我另一个依赖 wp-util 的脚本(里面用了 wp.ajax.send)被我不小心排在了自己脚本后面。

先贴我当时的错误代码,典型的"依赖写了但没写对、顺序写了但没写全":

// ❌ 错误写法:依赖声明不全 + 版本号缓存穿透 + 加载顺序靠运气
wp_enqueue_script(
    'my-vue-admin',
    plugin_dir_url( __FILE__ ) . 'dist/admin.js',
    ['jquery'],           // 漏了 wp-util,且 jquery 其实不需要显式声明(后台已加载)
    '1.0.0',              // 版本号写死,浏览器缓存不刷新
    true                  // 放 footer,但 wp-util 可能在 header 就执行了
);

wp_enqueue_script(
    'my-ajax-bridge',
    plugin_dir_url( __FILE__ ) . 'dist/bridge.js',
    ['my-vue-admin'],     // 桥接依赖 Vue 实例,但 Vue 是在 admin.js 里动态 import 的
    '1.0.0',
    true
);

问题一层层剥:

第一,jquery 在后台是默认加载的,显式声明反而容易掩盖真正的依赖关系。 我真正需要的是 wp-util(它自带 wp.ajax.send 的 jQuery 封装),但 $deps 里没写。结果浏览器偶尔因为其他插件先加载了 wp-util 而"碰巧跑通",刷新后缓存顺序一变就炸。

第二,版本号写死 '1.0.0',测试时浏览器拿着旧 js 不放手。 我改了代码但 URL 没变,强制刷新都救不了,因为 CDN 边缘节点也缓存了。这导致我一度以为"代码修好了但环境有问题",在错误方向上浪费了四十分钟。

第三,wp-util 默认在 header 加载,我的脚本放 footer,但桥接脚本里直接调了 wp.ajax.send 如果 wp-util 因其他原因延迟(比如被另一个插件用 wp_dequeue_script 搞了),wp 对象不存在,报错信息却是 jQuery is not defined——因为 wp.ajax.send 内部捕获异常时抛的是 jQuery 相关的兜底错误,完全误导排查方向。

正确的写法我后来拆成了三步:先理清楚"谁依赖谁",再用文件修改时间戳当版本号,最后用 wp_script_is 做防御性检查:

// ✅ 正确写法:依赖精确、版本防缓存、顺序可控、失败可降级
$js_path = plugin_dir_path( __FILE__ ) . 'dist/admin.js';
$js_url  = plugin_dir_url( __FILE__ ) . 'dist/admin.js';
$ver     = filemtime( $js_path );  // 文件修改即刷新缓存

// 1. 先确保 wp-util 可用(它比 jquery 更关键)
wp_enqueue_script( 'wp-util' );

// 2. 主脚本:明确依赖 wp-util,放 footer
wp_enqueue_script(
    'my-admin-core',
    $js_url,
    ['wp-util'],          // 精确依赖:我需要的是 wp.ajax 而不是裸 jQuery
    $ver,
    true
);

// 3. 桥接脚本:依赖主脚本,且用 wp_add_inline_script 做前置检查
wp_enqueue_script(
    'my-ajax-bridge',
    plugin_dir_url( __FILE__ ) . 'dist/bridge.js',
    ['my-admin-core'],
    $ver,
    true
);

// 4. 防御:如果 wp-util 被其他插件搞掉了,至少给个能看懂的报错
wp_add_inline_script( 'my-admin-core', '
    if ( typeof wp === "undefined" || ! wp.ajax ) {
        console.error("[MyPlugin] wp-util not loaded. Check for plugin conflicts.");
    }
', 'before' );

另外补一个踩坑细节:我之前试过用 wp_register_script + wp_enqueue_script 分开写,觉得这样"更规范"。结果在 admin_enqueue_scripts 钩子里,另一个同优先级(默认 10)的回调先执行了 wp_enqueue_script('my-admin-core'),但我那时还没 register,直接报 my-admin-core 未注册。后来干脆合并成一步 wp_enqueue_script,或者把注册逻辑挂到更早的 init 钩子,优先级调低(比如 5)。

最后总结下我贴显示器上的检查点,专门对付 wp_enqueue_script 的暗坑:

  • $deps 里写的是"我实际调用的 JS API 所在的脚本",不是"我听说应该依赖的库"
  • 版本号用 filemtime 或构建 hash,杜绝"代码已更新但浏览器不刷新"
  • 跨脚本调用的全局对象(wpjQueryVue),用 wp_add_inline_script 包一层 typeof 检查
  • 多插件共存时,用 wp_script_is( 'handle', 'enqueued' ) 确认依赖真的在队列里

这仨小时最大的收获:控制台报错的位置和真正出错的位置,中间可能隔了三层依赖和两层缓存。以后看到 jQuery is not defined,我先查 Network 面板的加载顺序,而不是直奔 jQuery CDN 链接。

评论0
回复 · 0
还没有回复
微信客服 微信客服