如何阻止esbuild重命名Spree命名空间/函数?
我太懂你这种头疼的感觉了——esbuild好好的把Spree这个全局命名空间改成了Spree2,结果整个前端直接报Uncaught ReferenceError: Spree is not defined,总不能真的把所有代码里的Spree都改成Spree2吧?咱们来试试这几个靠谱的解决办法:
方案1:把Spree明确挂载到全局window对象
Spree原本是作为全局变量存在的,esbuild之所以会重命名它,大概率是没识别到它的全局属性。你可以修改Spree的定义文件(也就是app/assets/javascripts/spree/frontend/main.js),在定义完Spree函数后,把它挂载到window上:
function Spree() {} // 新增这一行,告诉esbuild这个变量是全局的 window.Spree = Spree; // 后面的原有代码保持不变 Spree.ready = function(callback) { // ... 你的原有逻辑 }
这样esbuild就会明白这个变量属于全局环境,不会随便给它改名了。
方案2:在esbuild配置里声明Spree为全局变量
如果不想改动Spree的源码,直接在esbuild的构建配置里加规则,告诉它Spree是全局变量不能重命名。比如你的构建脚本可以这么写:
require('esbuild').build({ entryPoints: ['app/assets/javascripts/application.js'], bundle: true, outfile: 'dist/application.js', // 声明Spree对应window上的全局变量,禁止重命名 define: { 'Spree': 'window.Spree' }, // 配合你之前试过的keepNames: true,双重保险 keepNames: true, }).catch(() => process.exit(1))
要是你是把Spree作为全局模块导出的,还可以试试加上globalName: 'Spree'这个配置,效果会更稳妥。
方案3:把Spree相关文件排除在打包范围外
如果Spree的JS文件不需要被esbuild打包处理,直接把它设为外部依赖,让esbuild跳过对它的处理,保留原有的全局变量名:
require('esbuild').build({ entryPoints: ['app/assets/javascripts/application.js'], bundle: true, outfile: 'dist/application.js', // 把Spree的核心文件排除在打包流程外 external: ['./vendor/spree/frontend/main.js'], }).catch(() => process.exit(1))
用这个方法的话,记得要在HTML里先手动引入Spree的JS文件,再引入你打包好的application.js,这样Spree就能以原本的全局变量形式正常工作了。
关于你之前尝试的方法的小补充
- 你试过的
export function Spree () {}和export { Spree },会把Spree变成模块导出的变量,而不是原来的全局变量,所以其他依赖全局Spree的代码自然找不到它,这就是为啥会报错~ keepNames: true本身是保留变量名的,但如果esbuild觉得这个变量是局部的,还是可能会重命名,所以得配合全局声明一起用才靠谱。
另外,你提到的Import Uri from 'Jsuri'不好用的问题,可以试试在esbuild配置里加resolveExtensions: ['.js', '.jsx', '.ts'],或者确认一下Jsuri包已经正确安装在node_modules里,这样esbuild就能顺利找到它啦。
备注:内容来源于stack exchange,提问作者bjorn

