当同事在vue3 vite ts cesium项目中引入了jquery...又是帮同事擦屁屁的一次记录。点击异常文件链接
不会给同事擦屁屁的前端er,不是个好打工人。
问题分析
今天同事又甩给我一个bug,如下图:
SyntaxError: The requested module 'xxx' does not provide an export named 'default'
这是一个运行时的语法报错,意思是xxx文件没有提供一个默认的导出。正确的写法如下:
// 1.js
export default {
// 这里必须是export default,否则会报如上错误
// 如果是export let a = 1 需要 import { a } from './1.js' 或者 import { * as obj } from './1.js' 然后obj.a
name: 'jude',
age: 25
}
// 2.js
import { default as person1 } from './1.js'
import person2 from './1.js'
console.log(person1) // { name: 'jude', age: 25 }
console.log(person2) // { name: 'jude', age: 25 }
点击异常文件链接进入cesium.js?v=xxx
文件(我下面截图是通过网络面板的响应打开的,效果是一样的):
根据路劲提示找到项目中的jquery文件:
在这个IIFE
格式的插件包中遵循了CommonJS规范,用 module.export = sth
的方式向外提供接口,而不是通过ESM模块化方式使用export default
默认导出,报错无疑。
原因猜测
那为什么 cesium.js?v=xxx
会有这一行错误代码呢?
显然这个文件是vite打包之后的代码,它很可能是根据某些机制自动引入了这一行。
于是我猜测这个文件用到jQuery的全局变量,导致打包程序聪明得将依赖自动引入;
对猜测的验证:在 cesium.js?v=xxx
文件下搜索jQuery
,果然如此
(cesium文件中判断global下是否有jQuery变量,如果有则do somethings):
查找根源:
查看vite.config.js,发现:
同事引入了 vite-plugin-html 插件,在打包时该插件会扫描每个模块在此定义好的的全局变量,在需要的地方import对应的依赖文件:
注掉之后上面的vite.config.js中的配置代码后查看打包后的cesium.js?v=xxx
,果然这一行就没了:
问题解决
我:你的模块一定要用jq吗?
同事:对
然后我看了一下它的用jq的地方:
$.ajax({
type: 'POST',
url: conf.apiUrl,
data: JSON.stringify(data),
contentType: 'application/json',
dataType: 'json'
}).done(function (data) {
console.log('Got answer: ', data)
if (data.code) {
reject(data)
return
}
resolve(data)
}).fail(function (reason) {
reject(reason)
})
这为啥不能用axios?
但是都到这一步,还让人家动手改也不太好。
于是有以下几种解决方案:
1. 利用vite的裸模块导入机制,将cjs导出编译成esm导出,通过import函数引入:
// main.ts
import('jquery').then(res => {
window.$ = res
})
Vite官网上说明如下:
2. 配置@rollup/plugin-inject插件的include选项,只作用在指定文件中
// vite.config.ts
plugins: [
inject({
$: "jquery", // 这里会自动载入 node_modules 中的 jquery jquery全局变量
jQuery: "jquery",
"windows.jQuery": "jquery",
include :[
// 只包含videoPage.vue
'src/views/videoPage.vue'
]
})
]
插件文档说明如下:
解决。
总结
- 对于日常开发中的bug,我觉得敢于直面报错信息就能解决大部分了。
- 分析解决问题最好根据合适的方法论,有逻辑得排查和分析,再结合经验,从猜测到验证。
- 解决该问题的过程涉及到多方面的知识点:cjs和esm模块化、vite裸模块导入。希望能有机会学习一下vite的源码。
2023/04/15 补充:@rollup/plugin-inject 对cesium.js包体积的影响问题探究
除了上述问题外,还发现了配置该插件后,导致cesium.js的包体积达到63.4MB:
而当我注掉inject那段配置后,变成8.2M:
下面是两种情况的时间面板对比:
显然两次在等待服务器请求时间上存在巨大差距。那么是什么让cesium.js请求变这么慢,难道就是里面引入的jquery吗?在网络面板搜索jquery的脚本请求,发现它也就只占用了1.8MB、23ms。
通过查看插件源码发现,如果不配置sourceMap: false
或者sourcemap: false
那么就会生成源文件:
// node_modules\rollup-plugin-inject\src\index.js
const sourceMap = options.sourceMap !== false && options.sourcemap !== false;
// ...
return {
code: magicString.toString(),
map: sourceMap ? magicString.generateMap({ hires: true }) : null
};
所以,在配置项中添加:
// vite.config.ts
plugins: [
inject({
$: "jquery", // 这里会自动载入 node_modules 中的 jquery jquery全局变量
jQuery: "jquery",
"windows.jQuery": "jquery",
// include :[
// // 只包含videoPage.vue
// 'src/views/videoPage.vue'
// ],
sourceMap: false // 不生成sourcemap源文件
})
]
配置后恢复8.2MB大小:
转载自:https://juejin.cn/post/7220339259160756285