前端構建工具vite進階系列(二) -- vite的依賴預構建與配置文件相關處理
theme: devui-blue highlight: solarized-light
前言
上一章前端構建工具vite進階系列(一) -- vite比webpack的優勢與開箱即用中,我們稍微體驗了一下使用vite
來打包資源,並且可以解決非相對/絕對路徑的資源引入導致的報錯問題,那麼這一章我們來講講vite
的本身處理。vite
之所以能夠比webpack
快幾十倍,依賴預構建起到了很大的作用,那麼這一章講講依賴預構建與環境變量相關的事情吧。
為什麼要依賴預構建
-
CommonJS 和 UMD 兼容性: 開發階段中,
Vite
的開發服務器將所有代碼視為原生ES
模塊。因此,Vite
必須先將作為CommonJS
或UMD
發佈的依賴項轉換為ESM
。當轉換
CommonJS
依賴時,Vite
會執行智能導入分析,這樣即使導出是動態分配的(如React
),按名導入也會符合預期效果:js // 符合預期 import React, { useState } from 'react'
-
性能:
Vite
將有許多內部模塊的ESM
依賴關係轉換為單個模塊,以提高後續頁面加載性能。一些包將它們的
ES
模塊構建作為許多單獨的文件相互導入。例如,lodash-es
有超過 600 個內置模塊!當我們執行import { debounce } from 'lodash-es'
時,瀏覽器同時發出600
多個HTTP
請求!儘管服務器在處理這些請求時沒有問題,但大量的請求會在瀏覽器端造成網絡擁塞,導致頁面的加載速度相當慢。通過預構建
lodash-es
成為一個模塊,我們就只需要一個HTTP
請求了!vite是怎麼解決路徑問題的
vite
啟動的時候,會執行bin
目錄下的vite.js
文件,在這個文件裏面我們會看到獲取了當前的電腦的絕對路徑
,如果不包含node_module
路徑,就需要引入source-map-support
這個包來處理,如果是相對路徑則會進行路徑補全,當然在dev
環境下都會有node_module
路徑,在prod
環境下,vite
會使用rollup
來進行打包。
進行路徑補全當然可以解決這個問題,但是
vite
一想,我既然是基於ESM
規範的,那麼如果用户使用了CommonJS
規範的導出包,那我還不是需要編譯成ESM
嗎?所以vite
就藉助了esbuild
庫(esbuild
是一個對js
語法處理的庫),對用户使用的CommonJS
規範的庫進行了轉換成ESM
,並且輸入在了node_module/.vite/deps
目錄下。
- 一來可以統一ESM
模塊,統一模塊規範。
- 二來可以解決路徑問題
,方便路徑重寫。
- 三來可以優化http多包傳輸
的性能問題。
為什麼原生ESM不支持node_module?:因為如果支持的話,那將會帶來非常大的網絡性能
問題,對於ESM
裏面具有其他依賴的ESM
來説,那瀏覽器將會無限制
的請求依賴庫,舉個例子當我們使用lodash-es
庫的時候,我們把不進行預構建的模塊寫在vite.config.json
裏面。
js
export default {
optimizeDeps:{
exclude:["lodash-es"] // 當遇到lodash-es的時候 不進行預構建
}
}
那麼就會產生如下多的數不清的文件。
所以vite
能夠把ESM
庫中的所有三方依賴全部集成,只生成一個
或者多個
文件(多個文件但是不是類似於上面這麼多。。。)這才能夠説明可以用來優化http多包傳輸
的性能問題,所以這上面也是vite
的依賴預構建做的事情。
- esbuild庫 : https://esbuild.github.io/
配置文件相關處理
- 語法提示的支持
- 類型註解
/** @type import('vite').UserConfig*/
- 類型註解
-
defineConfig
- 環境配置文件處理 ```js import {defineConfig} from 'vite'; import viteBaseConfig from './vite-base-config.js' import viteDevConfig from './vite-dev-config.js' import viteProdConfig from './vite-prod-config.js'
const handleEnv = {
"build":()=>{
// build的時候做的事情
return Object.assign({}, viteProdConfig, viteBaseConfig)
},
"serve":()=>{
// serve的時候做的事情
return Object.assign({}, viteDevConfig, viteBaseConfig)
}
}
export default defineConfig(({command})=>{
console.log(handleEnvcommand)
return handleEnvcommand
})
``
3. 環境變量處理
-
vite對環境變量的處理是藉助於第三方庫
dotenv實現的,執行命令的時候,
dotenv會去讀取
.env文件,然後注入到
process對象當中。當然用户配置大於默認,我們可以在
vite.config.js裏面配置
envDir去**指定環境變量的文件地址**。
- 為什麼
nodejs可以讀取
ESM規範的
vite.config.js呢?
-
vite在讀取
vite.config.js文件的時候,如果遇到
ESM規範,
node會去解析成
CommonJS規範。
- 如何解析:讀取文件的結果就是
字符串,通過替換
import成
require`的方式來進行規範轉換。
- 通過命令來獲取環境參數
js export default defineConfig(({command, mode})=>{ // mode 為執行指令環境 // npm run serve => mode:development // npm run build => mode:production console.log(handleEnv[command]()) return handleEnv[command]() })
通過上述代碼中的mode
,我們知道了只要我們敲命令,mode
會自動獲取到,所以我們可以手動設置.env,vite
給我們提供了一個loadEnv
方法來獲取環境變量。 ```js export default defineConfig(({command, mode})=>{ // mode 為執行指令環境 // npm run serve => mode:development // npm run build => mode:production
const env = loadEnv(mode, process.cwd(), '')
console.log('/////env', env)
console.log(handleEnvcommand)
return handleEnvcommand
})
我們新建`.env.production`和`.env.development`文件,分別注入`ENV = 10011`和`ENV = 10010`
js
// .env.production
ENV = 10011
BASE_URL = 'http://dev.api'
// .env.development
ENV = 10010
BASE_URL = 'https://api'
``
所以
npm run serve` 的結果是:
所以
npm run build
的結果是:
import.meta.env
這個是官方提供的一個變量對象,他能夠有效的讀取到當前環境變量,我們先來看一看官網。
可以在代碼中獲取到
import.meta.env
的內容,如果要想獲取到環境變量,則需要命名為VITE_*
,為前綴的值,否則vite
訪問不到,原因是因為vite
做了一層攔截,把沒有帶VITE
前綴的變量,不會注入到import.meta.env
中。
當然這是默認的,一切要遵循配置大於默認,所以我們可以在
vite.config.js
中去定製envPrefix:"ENV_"
,才可以。
- 多種環境配置
- 在實際項目中肯定會有
測試環境
、預發佈環境
等,那這裏我們就按照prepare
來指定一下預發佈環境。 .env.prepare
文件。js ENV_PREPARE = 10012 ENV_BASE_URL = https://prepare.api/
- 在實際項目中肯定會有
總結
本文主要講解了vite
的預構建與config
文件、環境變量的處理,我們看到了其實跟webpack
很類似,在這裏我們也預留了問題,dotenv
是怎麼去處理環境變量的?ESM
是怎麼去變成CommonJS
的,這些問題後期源碼閲讀的時候,都會得到解答,請戳 >>> 前端構建工具vite進階系列(三) -- 靜態資源與css模塊化的處理