esbuild 默认将导入的模块封装在独立作用域中,导致通过 import 加载的 jQuery 无法被全局依赖脚本(如传统 UMD/AMD 或无模块声明的 JS 文件)访问;需通过 inject、banner 或全局挂载等机制显式暴露全局变量。
esbuild 默认将导入的模块封装在独立作用域中,导致通过 import 加载的 jquery 无法被全局依赖脚本(如传统 umd/amd 或无模块声明的 js 文件)访问;需通过 `inject`、`banner` 或全局挂载等机制显式暴露全局变量。
在 esbuild 中,import 语句引入的模块默认处于严格模块作用域——即使你 import jQuery from './jquery-3.7.1.js',该 jQuery 变量也仅在当前模块内有效,不会自动挂载到 window 上。而像 otherFile.js 这类传统脚本(通常直接使用 jQuery.fn.xxx 或 $()),其运行时依赖的是全局 window.jQuery 和 window.$,因此会报错 "jQuery is not defined"。
✅ 正确解决方案不是“先 import 再手动赋值”,因为 ES 模块的执行顺序和作用域隔离可能导致 window.jQuery = jQuery 在 otherFile.js 执行前尚未生效(尤其当 otherFile.js 是非模块脚本且被动态加载或异步执行时)。推荐以下三种生产级方案:
inject 允许你将一个导出全局变量的模块“注入”到每个入口文件顶部,确保 jQuery 在任何依赖代码执行前已就绪:
// inject-jquery.jsimport jQuery from './jquery-3.7.1.js';window.jQuery = window.$ = jQuery;
构建命令:
esbuild src/index.js --bundle --inject:./inject-jquery.js --outfile=dist/bundle.js
此时 esbuild 会自动将 inject-jquery.js 的内容前置插入,等效于:
// 自动生成的 bundle 开头var jQuery = (() => { /* jquery source */ })();window.jQuery = window.$ = jQuery;// 后续你的其他 import...import './otherFile.js'; // ✅ 此时 window.jQuery 已存在
适用于 jQuery 已通过 CDN 引入,或你只需声明全局变量名(配合 --external:jquery):
esbuild src/index.js --bundle --banner:js="import jQuery from './jquery-3.7.1.js'; window.jQuery = window.$ = jQuery;" --outfile=dist/bundle.js
⚠️ 注意:banner 中的代码在 bundle 最顶端执行,但需确保 jquery-3.7.1.js 是可解析的本地模块(非外部 CDN)。
如项目允许混合加载,直接在 HTML 中优先加载 jQuery:
<script src="jquery-3.7.1.min.js"></script><script src="dist/bundle.js"></script> <!-- 此 bundle 中不再 import jQuery -->
并在 index.js 中移除 import jQuery,改为声明类型(避免 TS 报错):
// @ts-ignoredeclare const jQuery: any;// 或使用 declare global(TypeScript 环境)
总结:esbuild 的模块封闭性是设计使然,而非缺陷。要桥接传统脚本生态,必须主动、提前、可靠地暴露全局变量——inject 是最符合工程规范的解法。