Vue 2 系統(tǒng)如何快速遷移 Vite 作為開發(fā)工具
當前版本 vite@2.3.7
一. 適合什么項目遷移
- 使用 vue2 的系統(tǒng)
- 內(nèi)部系統(tǒng) - 無需大型流量場景:因為 vite 更迭較快,導致系統(tǒng)需要定期改動基礎功能,造成不穩(wěn)定
- 非 SSR 系統(tǒng) - SSR 還有很多問題,暫且等社區(qū)豐富起來
- 定期有人維護的系統(tǒng)
- 對開發(fā)有痛點而想要改進:比如打包慢,冷啟動慢,HMR 更新慢。。。。
- vite 生產(chǎn)環(huán)境用 rollup,但是改造成本大,提效不高,風險大,暫不建議使用。【本人愚見,大佬輕噴】
二.遷移步驟
將會以內(nèi)部系統(tǒng)作為案例改造, 開發(fā)用 vite,生產(chǎn)依舊保持 webpack。
- 簡單了解 vite 特性。有問題優(yōu)先看vite 官網(wǎng)排查是否有更新或解決方案!!
- npm i vite@2.3.7 vite-plugin-vue2@1.6.2 vite-plugin-html@2.0.7 -D
- package.json 添加一個 script -- "vite": "NODE_ENV=development vite"
- 關鍵在于配置 vite.config.js【默認叫做這個文件名,你可配置成其他的。?!?/li>
- import { defineConfig } from 'vite';
- import path from 'path';
- import fs from 'fs';
- import { createVuePlugin } from 'vite-plugin-vue2';
- import { injectHtml, minifyHtml } from 'vite-plugin-html';
- import { cjs2esmVitePlugin } from 'cjs2esmodule'
- import dotenv from 'dotenv'
- const config = require('./config')
- try {
- // 根據(jù)環(huán)境變量加載環(huán)境變量文件
- const file = dotenv.parse(fs.readFileSync(`./config/.env.${process.env.NODE_ENV}`), {
- debug: true
- })
- console.log(file)
- // 根據(jù)獲取的 key 給對應的環(huán)境變量賦值
- for (const key in file) {
- process.env[key] = file[key]
- }
- } catch (e) {
- console.error(e)
- }
- const API_LOCATION = process.env.API_LOCATION || '/api'
- function resolve(dir) {
- return path.join(__dirname, './', dir)
- }
- export default defineConfig({
- root: './', // 項目根目錄(index.html 文件所在的位置)可以是一個絕對路徑,或者一個相對于該配置文件本身的相對路徑。
- publicDir: 'public', // 作為靜態(tài)資源服務的文件夾.該值可以是文件系統(tǒng)的絕對路徑,也可以是相對于項目的根目錄的相對路徑。
- base: './', // 公共基礎路徑。改值可以是絕對路徑或空字符串
- mode: 'development',
- optimizeDeps: { // 要預構(gòu)建的第三方依賴
- include: []
- },
- resolve: {
- alias: {
- // 'vue': 'vue/dist/vue.esm.js', // 如果是模板解析的 - 使用這個 vue:內(nèi)部為正則表達式 vue 結(jié)尾的
- 'vendor': resolve('src/vendor'),
- '@': resolve('src'),
- '~@': resolve('src'),
- '~component': resolve('src/components'),
- '~config': resolve('config'),
- }
- },
- plugins: [
- cjs2esmVitePlugin(), // 將 commonjs 轉(zhuǎn)化為 es module: 有報錯
- createVuePlugin({
- jsx: true,
- jsxOptions: {
- injectH: false,
- },
- }),
- minifyHtml(), // 壓縮 HTML
- injectHtml({ // 入口文件 index.html 的模板注入
- injectData: { // 模板注入的數(shù)據(jù)
- htmlWebpackPlugin: {
- options: {
- isVite: true,
- shotcut: '/static/img/favicon.png',
- }
- },
- title: 'HMO 運營后臺',
- },
- }),
- ],
- define: {
- 'process.env': process.env
- },
- server: {
- host: 'liang.myweb.com',
- open: true, // 是否自動打開瀏覽器
- port: process.env.PORT || config.dev.port,
- proxy: {
- [API_LOCATION]: {
- target: 'http://127.0.0.1:8001',
- rewrite: (path) => path.replace(API_LOCATION, '')
- }
- }
- },
- });
三.常用問題【踩坑日記😄】
1. vite 目前要求入口文件必須是根目錄下的 index.html,如果之前的 webpack 入口文件同名,需要更改。解決方案:vite.config.js:
- import { injectHtml } from 'vite-plugin-html';
- export default defineConfig({
- plugins:[
- injectHtml({ // 入口文件 index.html 的模板注入
- injectData: { // 模板注入的數(shù)據(jù)
- htmlWebpackPlugin: { // 取和 webpack 插件同名的對象 key,即可
- options: {
- isVite: true,
- shotcut: '/static/img/favicon.png',
- }
- },
- title: 'HMO 運營后臺'
- },
- })
- ]
- })
webpack.xxx.js
- new HtmlWebpackPlugin({
- template: 'index.html',
- inject: true,
- isVite: false // 添加標識
- })
根目錄入口文件 index.html - ejs 模板
- <% if (htmlWebpackPlugin.options.isVite) { %>
- <script type="module" src="/src/main.js"></script>
- <%}%>
2. 新版本報 xx 錯:可切換舊版本,如 vite@2.2.3
3.沒有導出命名?
- Uncaught SyntaxError: The requested module '/config/index.js' does not provide an export named 'default'Uncaught SyntaxError: The requested module '/config/index.js' does not provide an export named 'default'

錯誤原因:瀏覽器僅支持 esm,不支持 cjs vite.config.js
- import { cjs2esmVitePlugin } from 'cjs2esmodule'
- export default defineConfig({
- plugins: [
- cjs2esmVitePlugin(), // 將 commonjs 轉(zhuǎn)化為 es module
- ]
- })
如果有 require.xx 的按需加載寫法還可以修改成 import 的,案例如下:
- const subjectList = r => require.ensure( [], () => r(require('@/pages/xxx/subject/list.vue')), 'subject' );
- // 改為:Vue 動態(tài)組件 component: ()=>import()
- const subjectList = () => import(/* webpackChunkName: "subject" */ '@/pages/xxx/subject/list.vue')
- const arr = [
- {
- path: '/subject/list',
- name: 'subject/list',
- component: subjectList
- meta: {...}
- }
- ];
- export default arr;
4. proxy 使用 http-proxy。完整選項詳見 此處.案例:
- proxy: {
- '/rest': {
- target: 'http://my.web.com/',
- changeOrigin: true,
- bypass: (req, res, proxyOption) => {
- console.log(`當前請求代理:${req.url} -> ${proxyOption.target}`);
- },
- },
- }
5. ts 文件報錯?驗證是否配置了 vite 的 ts 處理
- "compilerOptions": {
- "types": ["vite/client"]
- }
6. 全局環(huán)境變量報錯?
- // const isProd = ENV === 'production'; // webpack - dev 環(huán)境變量
- // const isProd = import.meta.env.PROD; // vite - dev 環(huán)境變量
- // 可以避開上面👆🏻的,采用 NODE_ENV 來區(qū)分:
- const isProd = process.env.NODE_ENV === 'production';
- 那么我們啟動的時候:"dev": "NODE_ENV=development vite"
或者可以探索一下社區(qū)的 babel 插件:babel-preset-vite【包含以下兩個功能】babel-plugin-transform-vite-meta-envbabel-plugin-transform-vite-meta-glob
7. 看一些打印出來的日志&錯誤等?
cli --debug,或者 vite.config.js 配置打印相關參數(shù)
8. 引入文件,比如.vue 的時候,不可以省略擴展名?
是的!!!不是他們不會做,是他們不想做😭,就是這么設計的,具體請戳這里, 尤大佬推特解釋然后加上 resolve.extensions: ['.vue'] 直接在控制臺報錯:所以沒用。。。
- error: No loader is configured for ".vue"
害!老老實實加上擴展名!【在線🐶】 方便的全局加上擴展名方法如下:鏈接

9. less 文件找不到?
- [vite] Internal server error: '~@/styles/var.less' wasn't found.
(1)確定已經(jīng)支持 less:npm install -D less(2)別忘了 resolve.alias 也加上一個:'~@': resolve('src')
10. 如何支持 jsx?
vite.config.js
- import { createVuePlugin } from 'vite-plugin-vue2';
- createVuePlugin({
- jsx: true, // 配置 jsx
- jsxOptions: {
- injectH: false,
- },
- })
- Vue.component('my-component',{
- render () {
- return (<div>my template</div>)
- }
- })
11. 根據(jù)環(huán)境變量配置代理?
(1)cross-env 來跨平臺設置環(huán)境變量
1. 安裝 cross-envnpm i cross-env -D
(2)加載環(huán)境變量文件。它能將環(huán)境變量中的變量從 .env 文件加載到 process.env 中
2. 安裝 dotenvnpm i dotenv -D
(3)config/.env.development 配置變量
- NODE_ENV = development
- API_LOCATION = /api
- LOGOUT_PC_LOCATION = http://user.myweb.com/login
- CRM_ADDRESS = http://crm.myweb.com
(4)配置 vite.config.ts
- try {
- // 根據(jù)環(huán)境變量加載環(huán)境變量文件
- const file = dotenv.parse(fs.readFileSync(`./config/.env.${process.env.NODE_ENV}`), {
- debug: true
- })
- console.log(file)
- // 根據(jù)獲取的 key 給對應的環(huán)境變量賦值
- for (const key in file) {
- process.env[key] = file[key]
- }
- } catch (e) {
- console.error(e)
- }
- const API_LOCATION = process.env.API_LOCATION || '/api'
- ..... 此處省略
- export default defineConfig({
- server: {
- proxy: {
- [API_LOCATION]: {
- target: 'http://127.0.0.1:8001',
- rewrite: (path) => path.replace(API_LOCATION, '') // 根據(jù)環(huán)境變量配置代理
- }
- }
- }
- })
(5)package.json 啟動 script
- "vite": "cross-env NODE_ENV=development vite"
12. 環(huán)境變量報錯?
原來 webpack 使用的環(huán)境變量 process.env,vite 沒有這個,所以報錯
- Uncaught ReferenceError: process is not defined
vite 使用的時候import.meta.env, 但是我們老的代碼不想動怎么辦?其實 vite 也還是留了口子給我們定義全局變量[類型不能是 function]
- export default defineConfig({
- // ...
- define: {
- 'process.env': {}
- }
- })
13. anything else?
..... bug 無止境,很多都是非通用問題,都是引入 vite 后發(fā)現(xiàn)的系統(tǒng)本身的一些問題,這里就不一一舉例了。后續(xù)會追蹤更多通用問題