好記性不如爛筆頭之Vite篇
一、基礎(chǔ)
搭建一個Vite項(xiàng)目
npm init vite@latest
2.配置文件
項(xiàng)目跟目錄下的配置文件為vite.config.js文件,當(dāng)以命令行方式運(yùn)行vite時,Vite會自動解析該文件,其基礎(chǔ)配置如下所示:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 使用defineConfig工具函數(shù),不用jsdoc注解也可以獲取類型提示
export default defineConfig({
plugins: [vue()]
})
3.情景配置
如果配置需要基于(dev/serve或build)命令或者不同的模式來決定選項(xiàng),則可以選擇導(dǎo)出如下函數(shù):
import {defineConfig} from 'vite';
import vue from '@vitejs/plugin-vue';
// 使用defineConfig工具函數(shù),不用jsdoc注解也可以獲取類型提示
export default defineConfig(({command, mode}) => {
console.log(command, mode); // 開發(fā)環(huán)境command值為serve,生產(chǎn)環(huán)境為build
if (command === 'serve') {
return {
plugins: [vue()]
};
} else {
return {
plugins: [vue()]
};
}
});
二、vite為什么快
拜讀了vite的官方文檔,其官方文檔已經(jīng)給了很明確的解釋https://vitejs.cn/guide/why.html#the-problems,總結(jié)下來主要是以下幾點(diǎn):
提升vite服務(wù)器啟動速度
類似于webpack這種打包器方式的構(gòu)建工具,其首先會打包所有資源為bundle,然后才啟動服務(wù),而vite將該過程后置并做了一些優(yōu)化來提升服務(wù)器的啟動速度,主要如下所示:
(1)通過esbuild預(yù)構(gòu)建依賴
依賴指的是在開發(fā)時不會變動的純JavaScript,主要包含node_modules下的文件,該內(nèi)容通常包含多種模塊化格式(CommonJS、UMD、ESM等),所以需要進(jìn)行轉(zhuǎn)換為原生的ES模塊,為了完成該轉(zhuǎn)換過程,引入esbuild進(jìn)行預(yù)構(gòu)建依賴,由于Esbuild使用go編寫,其構(gòu)建速度相比于JavaScript編寫的打包器構(gòu)建速度更快。
(2)現(xiàn)代瀏覽器支持ESM格式的代碼
由于瀏覽器支持ESM格式的代碼,所以瀏覽器可接管打包程序的部分工作,Vite只需要在瀏覽器請求源碼時進(jìn)行轉(zhuǎn)換并按需提供源碼。
基于 ESM 的開發(fā)服務(wù)器
加快更新速度
為了加快更新速度,Vite做了很多優(yōu)化,主要體現(xiàn)在以下幾點(diǎn):
(1)減少網(wǎng)絡(luò)請求
esbuild預(yù)構(gòu)建依賴時,將許多內(nèi)部模塊的ESM依賴關(guān)系轉(zhuǎn)換為單個模塊,從而減少網(wǎng)絡(luò)請求個數(shù),提高頁面加載性能
(2)緩存
源碼模塊的請求會根據(jù) 304 Not Modified 進(jìn)行協(xié)商緩存,而依賴模塊請求則會通過 Cache-Control: max-age=31536000,immutable 進(jìn)行強(qiáng)緩存,因此一旦被緩存它們將不需要再次請求
三、配置項(xiàng)
Vite為了方便用戶使用,提供了很多配置項(xiàng),主要包含7類:共享配置、開發(fā)服務(wù)選項(xiàng)、構(gòu)建選項(xiàng)、預(yù)覽選項(xiàng)、依賴優(yōu)化選項(xiàng)、SSR選項(xiàng)、Worker選項(xiàng),我個人認(rèn)為最重要的是前三類選項(xiàng),接下來一起來看看這前三個選項(xiàng)。
3.1 共享選項(xiàng)
共享選項(xiàng)指的是不管是開發(fā)環(huán)境還是生產(chǎn)環(huán)境vite均會執(zhí)行的配置項(xiàng),主要用來表征一些通用內(nèi)容,下面我列舉幾個自己認(rèn)為重要的來展示出來。
1.root
項(xiàng)目根目錄(即index.html文件)所在的位置,例如當(dāng)index.html文件及src文件夾在testRoot文件件下時,其配置如下所示:
export default defineConfig({
root: './testRoot',
plugins: [vue()]
});
2.base
用于設(shè)置公共文件路徑,例如按如下設(shè)置后在開發(fā)環(huán)境下可通過http://localhost:3000/testBase訪問到所需頁面:
export default defineConfig({
base: '/testBase/',
plugins: [vue()]
});
3.mode
用于指示本次的開發(fā)模式(development)還是生產(chǎn)模式(production),其會把serve和build時的模式都覆蓋掉,也可通過--mode選項(xiàng)來重寫:
export default defineConfig({
plugins: [vue()],
mode: 'production'
});
4.plugins
設(shè)置需要用到的插件數(shù)組,插件是用來解決純粹vite提供的開箱即用的功能無法滿足時所提供的一種能力,例如通過@vitejs/plugin-vue提供對Vue3單文件組件的支持:
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
export default defineConfig({
plugins: [vue()]
});
5.publicDir
該配置設(shè)置靜態(tài)資源服務(wù)的文件,該配置默認(rèn)是public文件件,該目錄中的文件在開發(fā)期間在/處提供,并在構(gòu)建期間復(fù)制到outDir的根目錄,如下是將靜態(tài)資源服務(wù)的文件設(shè)置到./testPublicDir下:
export default defineConfig({
plugins: [vue()],
publicDir: './testPublicDir'
});
6.resolve.alias
使用該配置用于設(shè)置文件系統(tǒng)路徑的別名,設(shè)置路徑是使用使用絕對路徑,使用相對路徑的別名值會原封不動的被使用:
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src')
}
}
});
7.envDir與envPrefix
有的時候需要設(shè)置一些環(huán)境變量在代碼中使用,通過envDir可以設(shè)置環(huán)境變量文件的目錄(默認(rèn)為根目錄),通過envPrefix可以設(shè)置暴露給環(huán)境變量的前綴(默認(rèn)為VITE_),設(shè)置好之后就可以通過import.meta.env在代碼中讀取該變量。該目錄下所能讀取的文件主要有以下幾種:
.env # 所有情況下都會加載
.env.local # 所有情況下都會加載,但會被 git 忽略
.env.[mode] # 只在指定模式下加載
.env.[mode].local # 只在指定模式下加載,但會被 git 忽略
文件中的內(nèi)容可按如下設(shè)置:
VITE_TEST=test // 可以被讀取
TEST=test // 不能被讀取
3.2 開發(fā)服務(wù)選項(xiàng)
在開發(fā)環(huán)境時除了要注意共享選項(xiàng),更要注意開發(fā)服務(wù)選項(xiàng),該選項(xiàng)直接表征我們?nèi)绾闻渲胿ite服務(wù)器,我認(rèn)為常用的選項(xiàng)如下所示:
export default defineConfig({
plugins: [vue()],
server: {
// 是否自動在瀏覽器中打開應(yīng)用程序
open: true,
// 指定服務(wù)器應(yīng)該監(jiān)聽哪個IP地址
host: '127.0.0.1',
// 指定開發(fā)服務(wù)器的端口號
port: 8080,
// 代理
proxy: {
'/api': {
target: 'http://127.0.0.1:8888',
changeOrigin: true,
rewrite: path => path.replace('^/api', '')
}
}
}
});
3.3 構(gòu)建選項(xiàng)
當(dāng)系統(tǒng)開發(fā)完畢之后肯定需要打包構(gòu)建,進(jìn)而發(fā)布,vite的打包構(gòu)建利用了rollup的能力,打包構(gòu)建的選項(xiàng)在構(gòu)建選項(xiàng)中,我認(rèn)為常用的選項(xiàng)如下所示:
export default defineConfig({
plugins: [vue()],
build: {
// 設(shè)置最終構(gòu)建的瀏覽器兼容目標(biāo)(默認(rèn)值是‘modules’)
target: 'es2015',
// 指定輸出路徑,默認(rèn)是dist
outDir: 'testOutDir',
// 指定生成靜態(tài)資源的存放路徑,默認(rèn)assets
assetsDir: 'public',
// 指定小于多少大小的內(nèi)容將內(nèi)聯(lián)為base64,減少請求次數(shù)(默認(rèn)4096,即4kb)
assetsInlineLimit: 4096,
// 構(gòu)建后是否生成source map文件,默認(rèn)為false
sourcemap: true,
// 自定義底層的Rollup配置(一般不需要配置)
rollupOptions: {
// 指定打包的入口文件
input: {
default: './index.html'
},
// 指定文件輸出的配置
output: {
// 用于從入口點(diǎn)創(chuàng)建的塊的打包輸出格式[name]表示文件名,[hash]表示該文件內(nèi)容hash值
entryFileNames: 'test/test-[name]-[hash].js',
// 用于命名代碼拆分時創(chuàng)建的共享塊的輸出命名
chunkFileNames: 'js/test-[name]-[hash].js',
// 用于輸出靜態(tài)資源的命名,[ext]表示文件擴(kuò)展名
assetFileNames: 'assets/test-[name]-[hash].[ext]'
}
},
// 是否產(chǎn)出mainfest.json文件,該文件包含了沒有被hash的資源名和hash后版本的映射
manifest: true
}
});
四、單頁應(yīng)用與多頁應(yīng)用配置
通過vite默認(rèn)生成的就是一個單頁面應(yīng)用的配置,但是如何配置一個多頁面應(yīng)用的?這個確實(shí)值得去琢磨一下,以如下的目錄結(jié)構(gòu)為例,如何進(jìn)行配置呢?
vite-project
├─ .env
├─ .gitignore
├─ README.md
├─ index.html
├─ package-lock.json
├─ package.json
├─ public
│ └─ favicon.ico
├─ src
│ ├─ page1
│ │ ├─ index.html
│ │ └─ src
│ │ ├─ App.vue
│ │ ├─ assets
│ │ │ └─ logo.png
│ │ ├─ components
│ │ │ └─ HelloWorld.vue
│ │ └─ main.js
│ └─ page2
│ ├─ index.html
│ └─ src
│ ├─ App.vue
│ ├─ assets
│ │ └─ logo.png
│ ├─ components
│ │ └─ HelloWorld.vue
│ └─ main.js
└─ vite.config.js
針對如上的頁面結(jié)構(gòu)應(yīng)該如何配置呢?讓我們一起來瞧一瞧。
export default defineConfig({
plugins: [vue()],
root: './src',
build: {
rollupOptions: {
input: {
page1: path.resolve(__dirname, './src/page1/index.html'),
page2: path.resolve(__dirname, './src/page2/index.html')
}
}
}
});