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