webpack項(xiàng)目中使用vite加速的兼容模式詳解
前言
隨著公司前端工程越來越大,啟動是無盡的等待,修改是焦急的等待。
vite 到現(xiàn)在生態(tài)也起來了,就有了把項(xiàng)目改造成 vite 的想法,但是項(xiàng)目后面可能要依賴 qiankun 改造成微前端項(xiàng)目,現(xiàn)在 qiankun 對 vite 還沒有好的解決方法,我就想采取一個折中的辦法,保留 webpack,再兼容 vite,兩條路都留著。
目的
- 可以用 vite 跑開發(fā)環(huán)境。
- 可以用 webpack 跑開發(fā)環(huán)境。
- 暫時用 webpack 打包,等后面有解決方案再全面轉(zhuǎn) vite。
要處理的問題
要走的是兼容模式,原來項(xiàng)目的代碼能不動的盡量不動。
- 共用 index.html(使用一個 index.html)。
- 共用配置(讓 webpack 和 vite 共用一些配置,減少每次配置都要兩邊看的情況)。
- 兼容環(huán)境變量(環(huán)境變量 vite 是 import.meta.env,webpack 是 process.env,不修改原來的 process.env 寫法還兼容 vite)。
- 自動導(dǎo)入(自動導(dǎo)入在 webpack 里面用 require.context,vite 里面無法使用)。
- 資源引入(原來使用 require 方式引入圖片資源的需要改動,"~xxx/dist/xxx.css" 以 ~ 開頭引入資源的方式兼容處理)。
- svg-sprite-loader 替代方案。
動手
共用 index.html
vite 中 index.html 是在根目錄放的,webpack 在 public 下面放的,我們把 index.html 放到外面。
下面是咱們 webpack 的開發(fā)模式和生產(chǎn)模式。
"dev": "vue-cli-service serve", "build": "vue-cli-service build",
我們可以利用 npm hook 做一點(diǎn)事情,這樣每次在 dev,build 這兩個命令運(yùn)行之前我們都可以先執(zhí)行自己的腳本。
"predev": "node ./command/html.js", "prebuild": "node ./command/html.js", "dev": "vue-cli-service serve", "build": "vue-cli-service build",
// ./command/html.js const path = require('path') const fs = require('fs') // 把 index.html 拷貝到 public 下 fs.copyFileSync(path.resolve('./index.html'), path.resolve('./public/index.html'))
vite 中的 index.html 需要一個這樣的標(biāo)簽來指定入口文件,但是我們在 webpack 中不需要,我們可以借助插件來處理。
<script type="module" src="...">
// vite.config.js import { defineConfig, loadEnv } from 'vite' import { createHtmlPlugin } from 'vite-plugin-html' export default defineConfig(({ mode }) => { // 加載環(huán)境變量,因?yàn)?vite 中不會加載以 VUE 開頭的,我們得自己指定下 const envPrefix = ['VUE'] const env = loadEnv(mode, process.cwd(), envPrefix) return { plugins: [ createHtmlPlugin({ minify: true, template: './index.html', entry: '/src/main.js', // 這個會幫我們注入入口 js 文件 inject: { data: { // 這是我們 index.html 用到的環(huán)境變量 ...env } } }) ] } })
共用配置
例如我 webpack 中 devServer 和 vite 中的 server 配置就可以公用,但是 vite 使用的是 es module 引入,webpack 用的是 commonjs 規(guī)范,我們也可以用命令來處理。
// config/index.js // server 配置文件 export default { host: '0.0.0.0', port: 12003, https: false, hotOnly: true, disableHostCheck: true, proxy: { '/v1': { target: 'xxx', changeOrigin: true } } }
// vite.config.js import server from './config/index.js' import { defineConfig } from 'vite' export default defineConfig(({ mode }) => { return { server, } })
// vue.config.js const path = require('path') const resolve = dir => path.join(__dirname, dir) // babel 編譯過的 js包了一層 const devServer = require(resolve('config_cm')).default module.exports = { devServer }
可以看到 vite 和 webpack 使用的 server 配置引入方式不一樣,因?yàn)槟K化規(guī)則不一樣,我們下面利用下 npm hook,每次打包前也會把我們 config 文件夾轉(zhuǎn)為 commonjs 規(guī)范,輸出到 config_cm 下。
"transformJs": "babel --plugins @babel/plugin-transform-modules-commonjs --presets=@vue/cli-plugin-babel/preset ./config -d ./config_cm",
"predev": "node ./command/html.js && npm run transformJs",
"prebuild": "node ./command/html.js && npm run transformJs",
兼容環(huán)境變量
我們項(xiàng)目中有很多 procsss.env.xxx 這種寫法,我們要想這種寫法在 vite 里面也生效,就得利用 vite 里面 define 這個配置,如下:
// vite.config.js import server from './config/index.js' import { defineConfig, loadEnv } from 'vite' export default defineConfig(({ mode }) => { const envPrefix = ['VUE'] const env = loadEnv(mode, process.cwd(), envPrefix) const define = { 'process.env.NODE_ENV': '"development"', 'process.env.BASE_URL': '"/"', 'process.env.VITE': true } for (const [key, value] of Object.entries(env)) { define[`process.env.${key}`] = `"${value}"` } return { define, } })
自動導(dǎo)入
// vue.config.js // 需要安裝 webpack-strip-block,作用是為了刪除某段代碼 module.exports = { configureWebpack() { return { module: { rules: [ { test: /\.(js|scss)$/, enforce: 'pre', exclude: /node_modules/, use: [ { loader: 'webpack-strip-block' } ] } ] } } } }
// VITE 變量是在 vite.config.js 配置的,webpack 中是不存在的 // develblock 開頭的注釋是因?yàn)?webpack 中不存在 import.meta.globEager,編譯會失敗,所以我們 // 需要對這種做特殊處理 if (process.env.VITE) { /* develblock:start */ componentsContext = import.meta.globEager('./**/index.vue') /* develblock:end */ } else { componentsContext = require.context('./', true, /index\.vue$/) } // autoImport 是我們自己寫的共用方法,主要根據(jù) process.env.VITE 判斷就可以實(shí)現(xiàn)兩種環(huán)境中的導(dǎo)入方式 const components = autoImport(componentsContext, 'component') for (const c of components) { Vue.component(c.name, c) }
資源引入
require('./xx.png') // 這樣 vite 和 webpack 中都可以使用 import xx from './xx.png'
在 webpack 打包中,我們樣式中可能會出現(xiàn)下面這種引入方式,引入某個包下面的文件,或者引入 @(src 的別名)下的資源文件。
@import "~@[包名稱]/dist/xx.css"; .xx { background-image: url("~@/views/integration/assets/images/btn_icon/stop_hover.png"); }
修改一下
// 下面得寫兩行引入,因?yàn)闉榱思嫒?webpack 和 vite。 /* develblock:start */ @import "@[包名稱]/dist/xx.css"; /* develblock:end */ @import "~@[包名稱]/dist/xx.css"; // 這個不用動 .xx { background-image: url("~@/views/integration/assets/images/btn_icon/stop_hover.png"); }
我們這個時候得去 vite 配置下別名,可以根據(jù)自己需求靈活配置。
// vite.config.js import { defineConfig } from 'vite' export default defineConfig(({ mode }) => { resolve: { alias: [ // 針對以 ~@/[包名稱]開頭的,替換為 node_modules/@[包名稱] { find: /^(~@)(?!\/)(.+)/, replacement: path.join('node_modules/@$2') }, // 針對以 ~@/ 開頭,替換為 src/ { find: /^~@\//, replacement: path.join(__dirname, 'src/') }, // 針對以 @/ 開頭的,替換為 src/ { find: /^@\//, replacement: path.join(__dirname, './src', '/') } ] }, })
svg-sprite-loader 替代方案
在 webpack 中使用了 svg-sprite-loader,vite 中需要使用 vite-plugin-svg-icons
// 原來 webpack 下引入 svg 文件的 js // 假設(shè) svg 文件夾下存放了我所有的 svg 文件,這樣兩種環(huán)境下都可以使用 if (!process.env.VITE) { const context = require.context('./svg', false, /\.svg$/) context.keys().forEach(context) }
// vite.config.js import { defineConfig } from 'vite' import { createSvgIconsPlugin } from 'vite-plugin-svg-icons' export default defineConfig(({ mode }) => { createSvgIconsPlugin({ // 存放 svg 文件的文件夾 iconDirs: [path.resolve(process.cwd(), 'src/common/icons/svg')], // 和 webpack 保持一致就行 symbolId: 'icon-[name]' }), })
其他
- 我項(xiàng)目中使用的是 Vue2,所以用的是 vite-plugin-vue2 這個插件,Vue3 也同理。
- 我之前調(diào)試的時候,根目錄和 public 下同時存在 index.html 的時候出現(xiàn)過一些緩存問題,所以利用 npm hook 在用 vite 啟動的時候把 public 下的 index.html 刪掉了,原理和上面使用的方法一樣。
- 我項(xiàng)目中使用的是 antd 1.x 的包,會因?yàn)?moment 導(dǎo)致錯誤,有一個 vite-plugin-antdv1-momentjs-resolver 可以解決,不用重復(fù)造輪子。
- 不升級為 Vue3 是覺得沒必要,項(xiàng)目中也使用了 @vue/composition-api 這個包,可以使用 Vue3 的 composition-api 寫法。
效果
左邊是 vite,右邊是 webpack,vite 命令啟動前我做了一些操作,所以 vite 啟動幾乎是秒開,而 webpack,是分鐘級別的。這還是在我的電腦上,公司機(jī)子更慢了去了。
在熱更新方面,webpack 大概幾秒鐘,vite 幾乎無感知。
vite 第一次啟動因?yàn)闆]有緩存,進(jìn)頁面稍微慢點(diǎn),后面就感覺不到了。
以上就是webpack項(xiàng)目中使用vite加速的兼容模式詳解的詳細(xì)內(nèi)容,更多關(guān)于webpack vite加速兼容模式的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue項(xiàng)目watch內(nèi)的函數(shù)重復(fù)觸發(fā)問題的解決
這篇文章主要介紹了vue項(xiàng)目watch內(nèi)的函數(shù)重復(fù)觸發(fā)問題的兩種解決方案,幫助大家更好的理解和學(xué)習(xí)使用vue,感興趣的朋友可以了解下2021-04-04vue車牌號校驗(yàn)和銀行校驗(yàn)實(shí)戰(zhàn)
這篇文章主要介紹了vue車牌號校驗(yàn)和銀行校驗(yàn)實(shí)戰(zhàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-01-01vue watch監(jiān)聽數(shù)據(jù)變化的案例詳解
監(jiān)聽數(shù)據(jù)變化,在Vue中是通過偵聽器來實(shí)現(xiàn)的,你也可以將它理解為監(jiān)聽器,時刻監(jiān)聽某個數(shù)據(jù)的變化,本文將通過代碼示例為大家詳細(xì)的介紹一下vue watch如何監(jiān)聽數(shù)據(jù)變化,需要的朋友可以參考下2023-07-07vue使用高德地圖實(shí)現(xiàn)添加點(diǎn)標(biāo)記和獲取點(diǎn)擊位置信息的示例代碼
這篇文章主要介紹了vue使用高德地圖實(shí)現(xiàn)添加點(diǎn)標(biāo)記和獲取點(diǎn)擊位置信息的示例代碼,文中補(bǔ)充介紹了高德vue-amap使用(一)標(biāo)記點(diǎn)位獲取地址及經(jīng)緯度,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧2024-01-01vue使用mint-ui實(shí)現(xiàn)下拉刷新和無限滾動的示例代碼
本篇文章主要介紹了vue使用mint-ui實(shí)現(xiàn)下拉刷新和無限滾動的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11ElementUI實(shí)現(xiàn)el-table列寬自適應(yīng)的代碼詳解
這篇文章給大家介紹了ElementUI實(shí)現(xiàn)el-table列寬自適應(yīng)的詳細(xì)步驟,文中通過代碼示例給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-01-01Vue渲染器如何對節(jié)點(diǎn)進(jìn)行掛載和更新
這篇文章主要介紹了Vue 的渲染器是如何對節(jié)點(diǎn)進(jìn)行掛載和更新的,文中通過代碼示例給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-05-05Vue監(jiān)聽數(shù)據(jù)渲染DOM完以后執(zhí)行某個函數(shù)詳解
今天小編就為大家分享一篇Vue監(jiān)聽數(shù)據(jù)渲染DOM完以后執(zhí)行某個函數(shù)詳解,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-09-09