likes
comments
collection
share

vue2.7+webpack迁移vite实践总结

作者站长头像
站长
· 阅读数 57

前言

众所周知,得益于大多数浏览器都支持了ES模块,Vite基于esbuild在开发环境有很不错的启动速度。随着我们项目文件越来越多,并且有多个工程经常需要切换、更换ip、更换用户token等,再加上webpack中每次更改这些内容都需要重新启动,而vite是热更新的,就很方便。为了提升开发效率的同时,不影响线上打包结果,决定将开发环境从webpack迁移至vite,打包依然使用webpack。

本文记录了迁移过程遇到的问题与解决办法。

迁移过程

npm i -D vite,安装vite,根目录创建vite.config.js文件。

@vitejs/plugin-vue2

项目是vue@2.7版本,需要安装@vitejs/plugin-vue2,2.7之前的版本安装vite-plugin-vue2

// vite.config.js
import vue from '@vitejs/plugin-vue2'

export default {
  plugins: [vue()]
}

为了兼容webpack,新建了一个index.vite.html文件作为入口,添加<script type="module" src="./main.js"></script>(后面配置了插件后删除了),在index.html 中的 URL 将被自动转换,移除使用到的 %PUBLIC_URL%等占位符。

添加启动脚本

 "scripts": {
    ...
    "dev": "vite --host",
  },

alias移植

webpack中使用到了alias别名,移植配置:

// vite.config.js 
import vue from '@vitejs/plugin-vue2' 
export default {
  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'src'),
      ...
      }
   }
  plugins: [vue()] 
}

vite-plugin-html

vite的index.html 默认在项目最外层需要重新指定,并且之前 webpack 的 HtmlWebpackPlugin 插件中配置了变量,需要借助vite-plugin-html指定入口与声明变量:

// vite.config.js 
import vue from '@vitejs/plugin-vue2' 
import { createHtmlPlugin } from 'vite-plugin-html'

const orderCdn = {
  js: [...],
  css: [...],
}

export default {
  ...
  plugins: [
    vue(),
    createHtmlPlugin({
      minify: true,
      inject: {
        data: {
          orderCdn: orderCdn
        },
      },
      // 注:指定entry后,不需要在index.html添加script标签,若添加了建议删除
      entry: 'src/projects/portal/main.js',
      template: 'src/projects/portal/index.vite.html',
    }),
  ] 
}
...

替换htmlWebpackPlugin变量

// index.vite.html 
...
-    <% if(htmlWebpackPlugin.options.orderCdn) { %> <%for(var css of
-    htmlWebpackPlugin.options.orderCdn.css){ %>
+    <% if(orderCdn) { %> <%for(var css of orderCdn.css){ %>
       <link rel="stylesheet" type="text/css" href="<%= css %>" />
     <% } %> <% } %>

resolve.extensions

使用webpack导入文件通常习惯省略后缀名,例如:import App from './App',vite启动会提示找不到文件,需要补全后缀名:import App from './App.vue'; 补全数量较多,可以配置resolve.extensions:导入时想要省略的扩展名列表,默认不包含.vue后缀。 注:官方不建议忽略自定义导入类型的扩展名(例如:.vue),因为它会影响 IDE 和类型支持。

// vite.config.js 
export default {
 resolve: {
    ...
    extensions: ['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json', '.vue'],
  },
  ... 
}

process.env

项目内使用了process.env.NODE_ENV判断环境,报错process未定义,配置define:定义全局常量替换方式。

 ...
 define: {
    'process.env': process.env
 }

vite-plugin-externals

webpack配置了externals,同步vite需要安装vite-plugin-externals

// vite.config.js
import { viteExternalsPlugin } from 'vite-plugin-externals'

export default {
  ...
  plugins: [
    ...
    viteExternalsPlugin({
      'orderHeader': 'orderHeader',
    }),
  ]
}

这里遇到了一个坑,配置完运行Vue.use(OrderHeader)依然提示找不到组件:

vue2.7+webpack迁移vite实践总结

插件转换前和转换后代码如下:

// source code
import OrderHeader from 'orderHeader'
// transformed
const OrderHeader = window['orderHeader']

输出打印一下OrderHeader,发现是有内容的,多包了一层default; vue2.7+webpack迁移vite实践总结

而webpack通过编译构建,会做兼容性处理。 这里可以通过打印输出结果看到OrderHeader被替换成了 orderHeader__WEBPACK_IMPORTED_MODULE_0___default.a,而orderHeader__WEBPACK_IMPORTED_MODULE_0___default函数实际执行的是getDefault() 源码如下:

vue2.7+webpack迁移vite实践总结

解决:判断process.env.NODE_ENV在开发环境中使用Vue.use(OrderHeader.default)

@vitejs/plugin-vue2-jsx

由于有部分.vue文件使用了JSX,需要单独安装插件@vitejs/plugin-vue2-jsx。(注:@vitejs/plugin-vue2不再处理特有的 JSX / TSX 转换,vite-plugin-vue2则可以直接配置)。配置完还是不行,排查后发现.vue文件中需要在 script 标签,添加 lang="jsx" , 例: <script lang="jsx"></script>

// vite.config.js
import vue from '@vitejs/plugin-vue2'
import vueJsx from '@vitejs/plugin-vue2-jsx'

export default {
  ...
  plugins: [
    vue(),
    vueJsx({})
    ...
  ]
}

由于文件较多,使用了vite-plugin-lang-jsx插件自动注入,不过实际使用的时候发现插件有bug会导致vite服务挂起白屏。查看了源码后发现,该插件内部实际实现了两个功能:

  • plugin1:为js文件添加lang=jsx后缀;
  • plugin2:为.vue文件添加 lang="jsx"

最后导出return [plugin1, plugin2];。经测试挂起是由于plugin1导致的,正好我们项目只需要用到plugin2,所以最后配置成:

// vite.config.js
import vue from '@vitejs/plugin-vue2'
import vueJsx from '@vitejs/plugin-vue2-jsx'
import langJsx from 'vite-plugin-lang-jsx'

export default {
  ...
  plugins: [
    // 必须写在vue、vueJsx之前
    langJsx()[1],
    vue(),
    vueJsx({})
    ...
  ]
}

server.proxy

页面接口没有正常转发,查询配置发现devServer.proxy需要设置成server.proxy,并且proxy的pathRewrite调整成rewrite:

server:{
    proxy:{
       '/api':{
          rewrite: (path) => path.replace(/^/\api/, ''),
       }
    }
{

vite-plugin-static-copy

main.js入口处读取的配置文件,提示404 Not Found。

vue2.7+webpack迁移vite实践总结

对比源代码与输出结果,vite将相对路径输出成绝对路径,但是没有对入口处读取配置文件代码内的地址做转换。

vue2.7+webpack迁移vite实践总结

vue2.7+webpack迁移vite实践总结

找到两个办法自动输出完整路径:

但是测试了下都不兼容webpack。

import rootConfig from './configs/root.config.json?url'

const jsonUrl = new URL('./configs/root.config.json', import.meta.url).href

// 输出
// rootConfig:
/src/projects/portal/configs/root.config.json 
// jsonUrl
http://localhost:5173/src/projects/portal/configs/root.config.json

root文件实际也引用了多个文件。针对这样的静态资源,最后使用了vite-plugin-static-copy处理,支持开发环境处理静态资源。(一开始配错地址,以为不支持开发环境,就跑偏了😅)

import { viteStaticCopy } from 'vite-plugin-static-copy'

export default {
  ...
  plugins: [
    ...
    viteStaticCopy({
      targets: [
        {
          src: `src/projects/portal/configs/**`,
          dest: 'configs'
        }
      ]
    }),
}

其他

迁移改造遇到的问题还是比较多的,查资料的过程中还看到有一些感觉比较常见,但是项目里还没遇到的问题,比如:代码里使用了commonJs规范的需要用到@originjs/vite-plugin-commonjs插件处理、全局变量、css module的处理等等等,后续遇到了再更新。

最后

至此,本项目基本实现了开发环境的vite迁移。测试下来,启动/热更新实现了秒开的提升,解决了等待编译过程带来的内耗🙉。不过,项目还是稍微动了main.js入口文件,最理想的是完全不改源代码。最后,希望上述内容对大家有帮助,欢迎沟通讨论。

转载自:https://juejin.cn/post/7249933985564000312
评论
请登录