【實戰(zhàn)】從 Vue-cli 遷移到 Vite

背景
我最近將一些 Vue2 項目從vue-cli/webpack遷移到了 vite。
在第三次這樣做之后,我對遷移過程做了一些詳細(xì)的記錄,并將在這篇文章中進(jìn)行總結(jié), 希望對大家有所幫助。
文章目錄:
package.jsonindex.htmlvite.config.js測試用例Lint發(fā)布可視化 Bundle一些指標(biāo)結(jié)論
正文
package.json
devDependencies
刪除 @vue/cli-service 依賴項,并替換為 vite ??

npm un @vue/cli-service
npm i vite -D
你也可以刪除任何其他以 @vue/cli-plugin-xxx 開頭的開發(fā)依賴項,因為它們將不再起作用,例如:

npm un vue/cli-plugin-babel vue/cli-plugin-eslint vue/cli-plugin-unit-jest
如果你使用的是Vue2,我們還要補(bǔ)充vite-plugin-vue2, 這個會用在vite.config.js中:

npm i vite-plugin-vue2 -D
另外,如果你使用的是git hooks,則可能需要顯式安裝yorkie才能使所有內(nèi)容像以前一樣工作。

npm i yorkie -D
scripts
我們將 serve 在 vite 中用相應(yīng)的腳本替換 vue-cli 腳本:

當(dāng)然,你也可以保留 serve。
其他腳本,比如build, jest, lint, 之后也會講到。
index.html
繼續(xù),把 public/index.html 移至項目的根目錄。1??
我們還將添加vite需要的入口點:
<script type="module" src="/src/main.js"></script> 2??
最后,我們會從我們的替代路徑圖標(biāo)<%= BASE_URL %> favicon.ico(vite會在您的公用文件夾中為您找到該圖標(biāo))。3??

vite.config.js
我們需要將以前的版本轉(zhuǎn)換 vue.config.js 為新版本vite.config.js。
讓我們從以下幾行開始:
import { defineConfig } from 'vite'
import { createVuePlugin } from 'vite-plugin-vue2'
export default defineConfig({
plugins: [
createVuePlugin(),
],
})
遷移的時候, 對開發(fā)盡量保持透明,一些配置要和之前的保持一致, 比如端口:
import { defineConfig } from 'vite'
import { createVuePlugin } from 'vite-plugin-vue2'
export default defineConfig({
[...],
server: {
port: 8080,
}
})
你將在此處找到所有可能的配置選項:https://vitejs.dev/config/#config-file
'@'別名
如果你在webpack中使用了別名導(dǎo)入文件,則現(xiàn)在你需要重新創(chuàng)建它:
import { defineConfig } from 'vite'
import { createVuePlugin } from 'vite-plugin-vue2'
export default defineConfig({
[...],
resolve: {
alias: [
{
find: '@',
replacement: path.resolve(__dirname, 'src')
}
]
},
})
".vue" 導(dǎo)入路徑
使用 webpack 你可以忽略 .vue 文件后綴, 但是在 vite 中不行, 需要帶上。
// From
import DotsLoader from '@/components/DotsLoader'
// to
import DotsLoader from '@/components/DotsLoader.vue'
路由延遲加載簡化
在 Route 聲明中,你可以安全地刪除 webpackChunkName 可能有的任何注釋,例如該行:
{
path: '/links',
name: 'linksPage',
component: () => import(/* webpackChunkName: "links" */ './views/LinksPage.vue'),
},
簡化為:
{
path: '/links',
name: 'linksPage',
component: () => import'./views/LinksPage.vue'),
},
在這里我不是專家,但是如果您真的想自定義塊的名稱,則可以通過覆蓋匯總output.entryFileNames來實現(xiàn)。
另請參見 vite build.rollupOptions,了解如何直接將某些選項傳遞給 rollup.
環(huán)境變量
Vite 不識別 process.env, 取而代之的是:import.meta.env.
舉個例子:


需要注意的是,要確保NODE_ENV=production, 你需要在.env文件或生產(chǎn)環(huán)境變量中進(jìn)行設(shè)置。
參見官方文檔:https://vitejs.dev/guide/env-and-mode.html#env-variables-and-modes
至于自定義環(huán)境變量,我們不再需要像以前那樣為它們加上前綴VUE_APP,而是現(xiàn)在需要使用VITE。
任何以VITE_xxx開頭的變量都需要你在代碼中提供。

比如 .env.local 文件中的一個變量:
VITE_APP_BACKEND_URL=http://localhost:3001
測試用例
現(xiàn)在我們不能再使用 vue-cli-service test:unit了,讓我們重新配置。
首先,可以更新 test 腳本:

如果你的babel.config.js文件中包含類似內(nèi)容:
presets: ['@vue/cli-plugin-babel/preset'],
需要替換為:
presets: ['@babel/preset-env']
我也有與import.meta.env語句錯誤。
不幸的是,目前尚無針對單元測試的現(xiàn)成設(shè)置,但此評論對我有所幫助:
https://github.com/vitejs/vite/issues/1149#issuecomment-775033930
我的 babel.config.js 文件現(xiàn)在看起來是:
module.exports = {
presets: ['@babel/preset-env'],
// For Jest not to be annoyed by 'import.meta.xxx'
plugins: [
function () {
return {
visitor: {
MetaProperty(path) {
path.replaceWithSourceString('process')
},
},
}
},
],
}
或者,你可以使用此Babel插件,該插件也能解決import.meta在測試中的問題:https://github.com/javiertury/babel-plugin-transform-import-meta
在這里,可以關(guān)注有關(guān) vite 和 Jest 的一些討論:https://github.com/vitejs/vite/issues/1955
“regeneratorRuntime” error
49 | export const actions = {
> 50 | init: async ({ commit }, routeContext) => {
ReferenceError: regeneratorRuntime is not defined
regenerator-runtime 在我的setupTests.js中安裝并引用, 似乎已解決了該問題。
npm i regenerator-runtime -D
'jest.config.js':
module.exports = {
moduleFileExtensions: [
'js',
'json',
// tells Jest to handle `*.vue` files
'vue',
],
transform: {
// process `*.vue` files with `vue-jest`
'.*\\.(vue)$': 'vue-jest',
// process `*.js` files with `babel-jest`
'.*\\.(js)$': 'babel-jest',
},
setupFiles: ['./setupTests'],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
collectCoverage: false,
};
然后是我的“ setupTests.js”的第一行:
import 'regenerator-runtime/runtime';
Lint
只需要替換兩個與lint有關(guān)的腳本即可:

發(fā)布
在此示例中,我的應(yīng)用由S3 / CloudFront提供。
我有兩個生產(chǎn)環(huán)境:preprod 和 prod。
所以,我有兩個.env文件:
.env.preprod .env.prod
當(dāng)使用 rollup 構(gòu)建時,vite 將根據(jù)調(diào)用構(gòu)建腳本時使用的模式,用其值替換我們的環(huán)境變量。
這與 vue-cli 非常相似,因此更新我們的 package.json腳本就非常簡單直接:
有關(guān)此的更多詳細(xì)信息,請在此處進(jìn)行詳細(xì)說明:https://vitejs.dev/guide/env-and-mode.html#modes
Tips 還必須覆蓋“ vite.config.js ”中,最大包的大小:
import { defineConfig } from 'vite'
import { createVuePlugin } from 'vite-plugin-vue2'
export default defineConfig({
[...],
build: {
chunkSizeWarningLimit: 700, // Default is 500
},
})
可視化 Bundle
"build:report": "vue-cli-service build --report",
我使用 rollup-plugin-visualizer 來完成這個功能。
導(dǎo)入這個插件,并在我的vite.config.js中引用它:
import { defineConfig } from 'vite'
import { createVuePlugin } from 'vite-plugin-vue2'
import visualizer from 'rollup-plugin-visualizer'
export default defineConfig({
plugins: [
createVuePlugin(),
visualizer(),
],
[...],
})
打開新生成的stats.html文件時,這是我的結(jié)果:

這個和我們常用的 webpack-bundle-analyzer 是類似的。

一些指標(biāo)
啟動時間
用 vite 啟動: ?4秒(即使項目持續(xù)增長,它也應(yīng)該保持不變??)用 vue-cli/webpack啟動:大約 30秒(隨著我們向項目中添加更多文件,它將不斷增加??)
熱更新
vite:
簡單的更改(HTML標(biāo)記,CSS類...):立刻生效。
復(fù)雜的更改(重新命名JS函數(shù),添加組件…) :不確定,有時候我更喜歡自己刷新。
vue-cli/webpack:
簡單的的更改:?4sec??
更復(fù)雜的更改:我從不等待,而是手動刷新頁面。
首次頁面請求
當(dāng)vite啟動后, 第一次請求一個包含很多組件的復(fù)雜頁面,讓我們看一下 Chrome DevTools 中的network標(biāo)簽:
vite:?1430 JS文件請求, 在? 11秒內(nèi)完成 ??vue-cli/webpack:約23個JS文件請求, 在約 6秒內(nèi)完成 ??

在這個方面來看,可以采取一些優(yōu)化策劃, 比如組件懶加載等。
結(jié)論
總的來說,到目前為止,使用 vite 的開發(fā)體驗非常好,?? ?? ?? ?? ??
對于仍然使用 webpack 的項目,情況可能會變得越來越艱難。
