一次 Webpack 升级 Vite 的失败之旅
一. 写在前面
负责的项目一直使用 Webpack 5
进行构建,开发时 热更新速度 和 打包速度 总体上还行,但是和 Vite
还是有些差距,因此特意花费时间来进行构建工具的升级
项目技术栈: Vue 2.7 + TS
二. 适配过程
2.1 Vue 功能支持
使用官方提供的插件即可
import vue from '@vitejs/plugin-vue2' ... plugins: [vue()] ...
2.2 less 全局变量
css: { preprocessorOptions: { less: { additionalData: '@import "./src/assets/css/var.less";', }, }, },
2.3 环境变量
项目使用 cross-env
设置环境变量,再通过构建工具暴露到全局变量中
define: { HTTP_ENV: JSON.stringify(process.env.http_env), },
2.4 xhtml 处理
项目的业务中使用 xhtml
作为模板文件,用于字符串的组装。在 webpack
中使用 loader
进行配置
{ test: /\.(xhtml)$/, type: 'asset/source', },
在 vite 中可以使用 ?raw
,但是每个导入的都需要加,很麻烦。所以我写了一个插件,可以直接进行转化
function xhtmlPlugin(): Plugin { return { name: 'xhtmlPlugin', transform(code, id, options?) { if (id.endsWith('.xhtml')) { let buf = fs.readFileSync(id).toString() // 过滤文本中存在的 `,${, 避免代码生成异常 if(buf.includes('`')) { buf = buf.replace(/`/g, '\\`') buf = buf.replace(/\${/g, '\\${') } return { code: `export default \`${buf}\`;`, }; } }, } }
2.5 Module Federation
迁移的难点主要在于 Module Federation
, 项目使用了 Webpack 5
的 Module Federation
作为组件库,因此需要 Vite
也进行支持
这里我使用了 vite-plugin-federation
import federation from '@originjs/vite-plugin-federation' ... federation({ name: 'remote-app', filename: 'remoteEntry.js', shared: { ...pkg.dependencies, }, remotes: { microFE: { external: federationUrl, format: 'var', from: 'webpack', }, }, }) ...
配置之后,在开发模式时,无法使用测试环境的 remote
,会产生跨域的问题,因此写了一个插件进行兼容
const adaptiveModuleFederationPlugin = function (federationConfig: Parameters<typeof federation>[0]) { const adpativePlugin = () => ({ name: 'adaptiveModuleFederation', config(config, { command }) { if (command === 'serve') { if (!config.server.proxy) { config.server.proxy = {} } const remotes = federationConfig.remotes! const remoteKeys = Object.keys(remotes) remoteKeys.forEach(key => { const urlConfig = remotes[key] let url = '' if (typeof urlConfig === 'string') { url = urlConfig } else if (typeof urlConfig === 'object') { url = urlConfig.external } const preffixUrl = url.substring(0, url.lastIndexOf('/')) const endUrl = url.substring(url.lastIndexOf('/')) const proxyPath = '/proxy' + key const reg = new RegExp(`^${proxyPath}`) config.server.proxy[proxyPath] = { target: preffixUrl, changeOrigin: true, rewrite: path => path.replace(reg, ''), } const updateUrl = proxyPath + endUrl if (typeof urlConfig === 'string') { federationConfig.remotes![key] = updateUrl } else if (typeof urlConfig === 'object') { federationConfig.remotes![key].external = updateUrl } }) } }, }) return [adpativePlugin(), federation(federationConfig)] }
插件原理很简单,将地址代理到本地,即可避免跨域
... plugins: [...adaptiveModuleFederationPlugin({...}),] ...
三. 运行效果
搞定完上面这些,就可以正常运行项目了。提升十分明显。 Webpack 5
热更新时间大概 1s 多, Vite
直接无感,使用十分流畅。
四. 滑铁卢
4.1 遇到问题
开发模式没有了问题,就开始进行打包。打包表现的很正常,得到构建后的文件后,开始本地运行。
What? 页面空白
打开 devtools, 报错了,无法从 Vue
中找到 defineComponent
. 随后便进行各种尝试,最终在去除掉 config
中的 shared
后,项目可以正常运行
... ...adaptiveModuleFederationPlugin({ shared: [] }) ...
查看了使用的公共组件,还是存在问题, element-ui
的组件无法进行渲染。
shared
配置当前服务的共享模块,作为 host
端不进行配置,无法保证公共组件的加载。
4.2 寻找答案
我在 vite-plugin-federation
的仓库中查找到了
https://github.com/originjs/vite-plugin-federation/issues/248#issuecomment-1260875464
组件库对于 vue
是配置了 singleton: true
,这可能是导致无法正常加载的主要原因
4.3 其他问题
除了上面这个问题,我在使用 @vitejs/plugin-legacy
,也遇到和 vite-plugin-federation
不兼容的情况, 具体可看这个
https://github.com/vitejs/vite/issues/6133
4.4 如何处理
最终,我放弃了。插件目前不支持 singleton
属性,除非我把组件库改成 Vite 构建的,这样的改动成本太大了。
五. 最后
最终我还是清除了 Vite
的依赖,如果只是为了优化热更新的时间,而配置两个构建工具,实在不太合适。在这个过程中,还是有收获的。比如一些 Webpack
功能的迁移, Vite
插件的编写。希望后续上面提到的问题能被解决,后面有时间我再继续进行折腾吧。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: Git 入门介绍
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论