Vite 是一個前端構(gòu)建工具,它以其快速的開發(fā)服務(wù)器和生產(chǎn)優(yōu)化的打包器而聞名前端界,今天的內(nèi)容,必須得嘮嘮 Vite 的關(guān)鍵能力,以下是 Vite 的核心組件分析,以及使用案例:
ESModule
語法的支持,在開發(fā)環(huán)境中不進行打包編譯,而是通過啟動本地 devServer
來提供服務(wù),從而顯著提高了啟動速度 。esbuild
進行依賴預(yù)構(gòu)建,將多種模塊化規(guī)范轉(zhuǎn)換為 ESM,并減少網(wǎng)絡(luò)請求 。es-module-lexer
和 magic-string
重寫模塊路徑 。Vite 的設(shè)計哲學(xué)是盡可能利用現(xiàn)代瀏覽器的能力,減少不必要的打包操作,從而提高開發(fā)效率。在生產(chǎn)環(huán)境中,Vite 使用 Rollup 進行打包,確保了最終產(chǎn)物的優(yōu)化和性能 。
Vite 的核心組件功能主要包括以下幾個方面:
esbuild
預(yù)先構(gòu)建依賴,將 CommonJS、UMD 等模塊化規(guī)范轉(zhuǎn)換為 ESM,減少網(wǎng)絡(luò)請求次數(shù),提高性能。es-module-lexer
和 magic-string
來解析和重寫模塊路徑,以適應(yīng)瀏覽器的模塊加載機制。下面 V 哥將一一介紹這些核心功能并結(jié)合案例講解。
開發(fā)服務(wù)器(Dev Server)是 Vite 的核心組件之一,它在開發(fā)過程中提供了快速的模塊加載和熱更新功能。以下是開發(fā)服務(wù)器的一個簡單案例和解析:
假設(shè)我們有一個簡單的 Vue 3 項目,我們希望使用 Vite 來啟動開發(fā)服務(wù)器。以下是項目的目錄結(jié)構(gòu)和關(guān)鍵文件:
/my-vue-app
|-- node_modules
|-- public
| |-- index.html
|-- src
| |-- main.js
| |-- App.vue
|-- vite.config.js
|-- package.json
public/index.html
): <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vite Vue App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
src/main.js
): import { createApp } from 'vue';
import App from './App.vue';
const app = createApp(App);
app.mount('#app');
src/App.vue
): <template>
<div>
<h1>{{ message }}</h1>
</div>
</template>
<script setup>
const message = 'Hello Vite!';
</script>
vite.config.js
): // vite.config.js
module.exports = {
// 配置選項...
};
package.json
): {
"scripts": {
"dev": "vite"
},
"dependencies": {
"vue": "^3.0.0"
},
"devDependencies": {
"vite": "^2.0.0"
}
}
在項目根目錄下,運行以下命令來啟動開發(fā)服務(wù)器:
npm run dev
這個命令會執(zhí)行 package.json
中定義的 "dev"
腳本,使用 Vite 啟動開發(fā)服務(wù)器。
npm run dev
時,Vite 會啟動一個本地開發(fā)服務(wù)器。index.html
中引用的 type="module"
腳本提供服務(wù)。/src/main.js
時,Vite 服務(wù)器會提供該文件的內(nèi)容,并按需解析和加載依賴的模塊(如 App.vue
)。App.vue
或其他依賴文件發(fā)生變化,Vite 會通過 WebSocket 推送更新到瀏覽器,實現(xiàn)熱更新,而無需刷新頁面。按需編譯是 Vite 的一個核心特性,它允許開發(fā)者在開發(fā)過程中只編譯那些被實際請求的模塊,而不是整個項目。以下是使用 Vite 進行按需編譯的案例和解析:
假設(shè)我們有以下項目結(jié)構(gòu):
/my-vue-app
|-- node_modules/
|-- public/
|-- src/
| |-- main.js
| |-- App.vue
| |-- SomeComponent.vue
|-- vite.config.js
|-- package.json
src/main.js
): import { createApp } from 'vue';
import App from './App.vue';
const app = createApp(App);
app.mount('#app');
src/App.vue
): <template>
<div>
<h1>Home Page</h1>
<button @click="loadComponent">Load Component</button>
</div>
</template>
<script>
import SomeComponent from './SomeComponent.vue';
export default {
methods: {
loadComponent() {
this.$forceUpdate();
this.$options.components.SomeComponent = SomeComponent;
}
}
}
</script>
src/SomeComponent.vue
): <template>
<div>
<h2>I'm a lazy-loaded component!</h2>
</div>
</template>
<script>
export default {
name: 'SomeComponent'
}
</script>
vite.config.js
): // vite.config.js
module.exports = {
// 配置選項...
};
package.json
): {
"scripts": {
"dev": "vite"
},
"dependencies": {
"vue": "^3.0.0"
},
"devDependencies": {
"vite": "^2.0.0"
}
}
在項目根目錄下,運行以下命令來啟動開發(fā)服務(wù)器:
npm run dev
main.js
和 App.vue
會被加載和編譯,因為它們是初始入口點。loadComponent
方法時,SomeComponent.vue
將被按需加載。由于 Vite 支持 ES 模塊,這個組件將通過動態(tài) import()
語法異步加載。SomeComponent.vue
被請求時,Vite 的開發(fā)服務(wù)器會捕獲這個請求,并編譯該模塊,然后將其發(fā)送給瀏覽器。SomeComponent.vue
在開發(fā)過程中被修改,Vite 將通過 HMR 更新瀏覽器中的組件,而不需要重新加載整個頁面。一句話,Vite 通過按需編譯,從而提供更快速的開發(fā)體驗和更高效的資源管理。
依賴預(yù)構(gòu)建是 Vite 的一個重要特性,它在項目啟動之前預(yù)先處理項目依賴,將非 ES 模塊轉(zhuǎn)換為 ES 模塊,以減少開發(fā)時的模塊請求次數(shù)和提高性能。以下是依賴預(yù)構(gòu)建的案例和解析:
假設(shè)我們有以下項目結(jié)構(gòu):
/my-vue-app
|-- node_modules/
| |-- some-pkg/
| |-- package.json
| |-- index.js
|-- src/
| |-- main.js
| |-- App.vue
|-- vite.config.js
|-- package.json
node_modules/some-pkg/index.js
- 一個 CommonJS 模塊): // CommonJS 模塊
exports.default = function() {
console.log('CommonJS package loaded');
};
src/main.js
): import { createApp } from 'vue';
import App from './App.vue';
import somePkg from 'some-pkg';
somePkg.default(); // 使用預(yù)構(gòu)建的依賴
const app = createApp(App);
app.mount('#app');
src/App.vue
): <template>
<div>
<h1>App Component</h1>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
vite.config.js
): // vite.config.js
module.exports = {
// 配置選項,例如別名 @ 指向 src 目錄
alias: {
'@': '/src',
},
// 其他配置...
};
package.json
): {
"scripts": {
"dev": "vite"
},
"dependencies": {
"vue": "^3.0.0",
"some-pkg": "1.0.0"
},
"devDependencies": {
"vite": "^2.0.0"
}
}
在項目根目錄下,運行以下命令來啟動開發(fā)服務(wù)器:
npm run dev
node_modules
目錄中的依賴,并使用 esbuild
這個高性能的 JavaScript 打包器來預(yù)構(gòu)建這些依賴。esbuild
會將其轉(zhuǎn)換為 ES 模塊,以便瀏覽器能夠通過 import
語句加載。node_modules/.vite
目錄中,這樣在開發(fā)過程中,只有當(dāng)依賴發(fā)生變化時,才會重新構(gòu)建,否則直接使用緩存。小結(jié)一下,Vite 能夠顯著提高大型項目的開發(fā)效率和性能,同時確保了代碼的兼容性和模塊的按需加載。
熱模塊替換(Hot Module Replacement)是 Vite 在開發(fā)過程中提供的一項功能,它允許開發(fā)者在不刷新整個瀏覽器頁面的情況下,替換、添加或刪除模塊。下面是 HMR 案例和解析,一起來看看:
假設(shè)我們有以下項目結(jié)構(gòu):
/my-vue-app
|-- node_modules/
|-- public/
|-- src/
| |-- main.js
| |-- Button.vue
|-- vite.config.js
|-- package.json
src/main.js
): import { createApp } from 'vue';
import Button from './Button.vue';
const app = createApp();
app.component('button-component', Button);
app.mount('#app');
src/Button.vue
): <template>
<button @click="count++">Count is: {{ count }}</button>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(0);
</script>
public/index.html
): <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vite HMR Demo</title>
</head>
<body>
<div id="app">
<button-component></button-component>
</div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
vite.config.js
): // vite.config.js
module.exports = {
// HMR 默認開啟,無需額外配置
};
package.json
): {
"scripts": {
"dev": "vite"
},
"dependencies": {
"vue": "^3.0.0"
},
"devDependencies": {
"vite": "^2.0.0"
}
}
在項目根目錄下,運行以下命令來啟動開發(fā)服務(wù)器:
npm run dev
Button.vue
的模板或腳本。Button.vue
組件,并使用 HMR 更新瀏覽器中的對應(yīng)模塊,而不需要重新加載整個頁面。Button.vue
中的 count
狀態(tài)會保持不變,即使組件被重新加載。用戶會看到按鈕上顯示的計數(shù)在點擊后繼續(xù)增加,而頁面不會刷新。小結(jié)一下,我們可以看到 Vite 的 HMR 功能使得開發(fā)更加高效,允許開發(fā)者快速迭代組件,同時保持應(yīng)用狀態(tài)和用戶體驗。
緩存機制在 Vite 中主要體現(xiàn)在兩個方面:HTTP 緩存和文件系統(tǒng)緩存。以下是緩存機制的案例和解析:
假設(shè)我們有以下項目結(jié)構(gòu):
/my-vue-app
|-- node_modules/
|-- public/
|-- src/
| |-- main.js
| |-- App.vue
|-- vite.config.js
|-- package.json
src/main.js
): import { createApp } from 'vue';
import App from './App.vue';
createApp(App).mount('#app');
src/App.vue
): <template>
<div>
<h1>{{ message }}</h1>
</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello, Vite!'
};
}
}
</script>
public/index.html
): <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vite Cache Demo</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
vite.config.js
): // vite.config.js
module.exports = {
// 配置選項...
};
package.json
): {
"scripts": {
"dev": "vite"
},
"dependencies": {
"vue": "^3.0.0"
},
"devDependencies": {
"vite": "^2.0.0"
}
}
在項目根目錄下,運行以下命令來啟動開發(fā)服務(wù)器:
npm run dev
Cache-Control
響應(yīng)頭,指定資源可以被瀏覽器緩存。node_modules/.vite
目錄下緩存預(yù)構(gòu)建的依賴。當(dāng)沒有發(fā)生變化時,Vite 會直接從這個緩存中讀取依賴,避免重復(fù)構(gòu)建。App.vue
中的 message
數(shù)據(jù)。保存文件后,Vite 會觸發(fā) HMR 更新,但不會重新構(gòu)建整個項目的依賴。main.js
),瀏覽器會根據(jù) HTTP 響應(yīng)頭中的緩存指令緩存這些資源。下次訪問相同的資源時,如果資源沒有更新,瀏覽器會使用本地緩存,而不是從服務(wù)器重新下載。ETag
或 Last-Modified
)。當(dāng)源文件有更新時,Vite 會更新這些標(biāo)記,瀏覽器會根據(jù)這些標(biāo)記判斷是否需要從服務(wù)器獲取新的資源。Vite 的緩存機制幫助提高開發(fā)效率的同時,減少不必要的資源加載和構(gòu)建過程,get到了沒。
Vite 在處理模塊路徑時,需要將基于 Node.js require.resolve
的路徑轉(zhuǎn)換為瀏覽器可識別的路徑。此外,Vite 還支持使用 @
符號作為 src
目錄的別名,這在 Vue 單文件組件(SFC)中尤為常見。來看一下這個案例和解析:
假設(shè)我們有以下項目結(jié)構(gòu):
/my-vue-app
|-- node_modules/
|-- public/
|-- src/
| |-- components/
| | |-- MyComponent.vue
| |-- views/
| | |-- Home.vue
| |-- main.js
|-- vite.config.js
|-- package.json
src/main.js
): import { createApp } from 'vue';
import Home from '@/views/Home.vue';
createApp(Home).mount('#app');
src/views/Home.vue
): <template>
<div>
<h1>Welcome to the Home page</h1>
<my-component />
</div>
</template>
<script>
import MyComponent from '@/components/MyComponent.vue';
export default {
components: {
MyComponent
}
}
</script>
src/components/MyComponent.vue
): <template>
<div>I'm a component!</div>
</template>
<script>
export default {
name: 'MyComponent'
}
</script>
vite.config.js
): // vite.config.js
module.exports = {
// 設(shè)置別名 @ 指向 src 目錄
alias: {
'@/': '/src/',
'vue': 'vue/dist/vue.esm.js'
}
};
package.json
): {
"scripts": {
"dev": "vite"
},
"dependencies": {
"vue": "^3.0.0"
},
"devDependencies": {
"vite": "^2.0.0"
}
}
在項目根目錄下,運行以下命令來啟動開發(fā)服務(wù)器:
npm run dev
vite.config.js
中,我們設(shè)置了 @
別名指向項目的 src
目錄。這樣,我們就可以使用 @/views/Home.vue
這樣的路徑來代替相對路徑或絕對路徑。Home.vue
被 main.js
引用時,瀏覽器會發(fā)送一個請求到 Vite 開發(fā)服務(wù)器,請求 @/views/Home.vue
。@/views/Home.vue
轉(zhuǎn)換為實際的文件路徑 /src/views/Home.vue
。es-module-lexer
來解析 import
語句,并根據(jù)瀏覽器對 ES 模塊的支持來重寫模塊路徑。.js
和 .css
(如果有)等不同的模塊,并單獨服務(wù)這些模塊。Vite 通過模塊路徑重寫支持別名和單文件組件的按需加載,從而提高開發(fā)效率和模塊化管理的便利性,有點意思。
構(gòu)建優(yōu)化是 Vite 在生產(chǎn)環(huán)境下的關(guān)鍵特性,它確保最終的靜態(tài)資源被壓縮、分割和優(yōu)化以提高應(yīng)用的性能。以下是構(gòu)建優(yōu)化的案例和解析:
假設(shè)我們有以下項目結(jié)構(gòu):
/my-vue-app
|-- node_modules/
|-- public/
|-- src/
| |-- main.js
| |-- App.vue
| |-- SomeLib.js
|-- vite.config.js
|-- package.json
src/main.js
): import { createApp } from 'vue';
import App from './App.vue';
import SomeLib from './SomeLib';
createApp(App).mount('#app');
// 使用庫函數(shù)
SomeLib.doSomething();
src/App.vue
): <template>
<div id="app">
<h1>My Vue App</h1>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
src/SomeLib.js
): export function doSomething() {
console.log('Library function called');
}
vite.config.js
): // vite.config.js
module.exports = {
build: {
// 配置生產(chǎn)環(huán)境構(gòu)建選項
minify: 'terser', // 使用 terser 進行代碼壓縮
sourcemap: true, // 生成 sourcemap 文件
rollupOptions: {
output: {
manualChunks: {
lib: ['src/SomeLib.js'], // 將 SomeLib.js 單獨打包成一個 chunk
}
}
}
}
};
package.json
): {
"scripts": {
"build": "vite build"
},
"dependencies": {
"vue": "^3.0.0"
},
"devDependencies": {
"vite": "^2.0.0",
"terser": "^5.0.0"
}
}
在項目根目錄下,運行以下命令來構(gòu)建項目:
npm run build
vite.config.js
中,我們配置了構(gòu)建選項,包括代碼壓縮工具 terser
和 sourcemap 生成。rollupOptions
中的 manualChunks
配置將 SomeLib.js
單獨打包成一個 chunk,這有助于按需加載和緩存。npm run build
后,Vite 會啟動構(gòu)建流程,根據(jù)配置進行代碼壓縮、分塊等操作。terser
,Vite 會壓縮 JavaScript 代碼,移除多余的空格、注釋,并進行一些優(yōu)化以減少文件大小。dist
目錄下生成優(yōu)化后的靜態(tài)資源,包括 JavaScript、CSS 和其他靜態(tài)資源文件。Vite在生產(chǎn)環(huán)境中進行構(gòu)建優(yōu)化,包括代碼壓縮、手動分塊、sourcemap 生成等,以確保應(yīng)用的性能和可維護性。
Vite 的插件系統(tǒng)允許開發(fā)者擴展 Vite 的功能,例如添加對特定類型文件的支持、優(yōu)化構(gòu)建流程等,來看一下:
假設(shè)我們有以下項目結(jié)構(gòu):
/my-vue-app
|-- node_modules/
|-- src/
| |-- main.js
| |-- App.vue
| |-- assets/
| |-- image.png
|-- vite.config.js
|-- package.json
src/main.js
): import { createApp } from 'vue';
import App from './App.vue';
import './assets/image.png';
createApp(App).mount('#app');
src/App.vue
): <template>
<div>
<img src="image.png" alt="Image">
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
vite.config.js
): // vite.config.js
import vue from '@vitejs/plugin-vue';
import path from 'path';
import imageTransformPlugin from './imageTransformPlugin'; // 假設(shè)我們創(chuàng)建了一個自定義插件
module.exports = {
plugins: [
vue(), // Vite 官方 Vue 插件,用于處理 Vue 單文件組件
imageTransformPlugin, // 使用自定義插件來處理圖像轉(zhuǎn)換
],
// 其他配置...
};
imageTransformPlugin.js
): // 自定義插件來處理圖像文件
export default {
name: 'image-transform-plugin',
transform(code, id) {
if (id.endsWith('.png')) {
// 假設(shè)我們對圖像進行某種轉(zhuǎn)換處理
const transformedCode = code.replace(/.png$/, '-transformed.png');
return {
code: transformedCode,
map: null, // 這里簡化處理,實際插件應(yīng)該生成 sourcemap
};
}
},
};
package.json
): {
"scripts": {
"dev": "vite",
"build": "vite build"
},
"dependencies": {
"vue": "^3.0.0"
},
"devDependencies": {
"@vitejs/plugin-vue": "^2.0.0",
"vite": "^2.0.0"
}
}
@vitejs/plugin-vue
,這是 Vite 官方提供的插件,用于支持 Vue 單文件組件。imageTransformPlugin
的自定義插件,用于處理圖像文件的轉(zhuǎn)換。vite.config.js
中,我們將這兩個插件添加到 plugins
數(shù)組中,這樣 Vite 在構(gòu)建時就會應(yīng)用這些插件。npm run dev
或 npm run build
時,Vite 會使用配置的插件來處理項目資源。@vitejs/plugin-vue
):
.vue
文件,將它們分解為 JavaScript、CSS 和模板代碼,并應(yīng)用 HMR。imageTransformPlugin
):
.png
結(jié)尾的文件請求,并對其進行了簡單的“轉(zhuǎn)換”(這里只是示例,實際中可能是更復(fù)雜的圖像處理邏輯)。transform
),允許插件在構(gòu)建過程中的不同階段介入和修改處理邏輯。Vite 插件系統(tǒng)允許開發(fā)者自定義構(gòu)建流程,增強 Vite 的功能,以適應(yīng)各種開發(fā)需求。
除了以上這些,Vite 還對 Vue 3 和 React 17+ 的官方支持,允許開發(fā)者使用這些前端框架進行開發(fā)。Vite 內(nèi)置了對 TypeScript 的支持,無需額外配置即可使用 TypeScript 開發(fā)。Vite能夠處理 CSS 文件和各種靜態(tài)資源,包括圖片、字體等,并支持 CSS 預(yù)處理器。Vite 能夠生成 Sourcemap,方便開發(fā)者在瀏覽器中調(diào)試源代碼。Vite 支持在構(gòu)建過程中注入環(huán)境變量,使得配置更加靈活。如果你還知道哪些關(guān)于 Vite 的能力,歡迎給 V 哥點撥一下,在此感謝。
這些核心組件功能共同構(gòu)成了 Vite 的強大能力,使它成為一個高效、靈活且易于使用的前端構(gòu)建工具,如果你還沒用上 Vite,那就抓緊搞起來吧。
更多建議: