vite 與 react 的結合
vite,法語詞,快的意思. 讀音為 /vit/
先來看看之前的先驅: parcel,rollup,webpack.這些工具的目的便是為了打包,為了前端能有模組化. 為了前端能承擔更復雜的邏輯,不被後端瞧不起.為了證明js是宇宙第一的語言,為了.... 簡單總結下:
- 配置項
- parcel最方便,幾乎不需要任何配置,install之後build即可.
- webpack和rollup都需要指定entry,output,loaders,plugins,transformations等 -是rollup基於的是node的模組系統,可以直接使用import/output,這也是為什麼使用rollup需要在版本10以上的原因. 而且webpack不能
- webpack必須使用絕對路徑,這也是為什麼使用path.resolve的原因 rollup可以使用相對路徑
- tree-shaking
- parcel同時支援對commonjs以及es6的樹搖. 這是很大的優勢,因為npm上還有很多是commonjs的庫,而且parcel在樹搖時是平行搖的,可以充分利用好多核的優勢
- rollup靜態解析匯入的程式碼,自動排除未引入部分,配置較少
- webpack配置較為複雜,必須使用es6的語法,webpack4在生產環境預設啟用樹搖了,否則還需要配置uglifyPlugin外掛
- 程式碼分段 code-split
- webpack更優,一整套配置,可以較為精細化的控制,參見
- rollup使用瀏覽器內建的ES模組系統,由瀏覽器來進行控制
- parcel支援零配置的程式碼分段,是通過動態匯入語法
import()
來實現的,該函式返回一個promise
- 後兩者issue和bug的報告比較多,所以安全起見,webpack更為穩妥,在compile的時候也是webpack最快.
- webpack更優,一整套配置,可以較為精細化的控制,參見
- live reload 實時過載
- 不用多說,這是前端開發必備的功能 如果一個code的變化還需要我去按重新整理的話,估計我的command + R鍵會被按爆.
- parcel自帶有開發伺服器,但是在使用HTTP log hooks 和中介軟體的時候容易出問題
- rollup需要安裝
rollup-plugin-server
rollup-plugin-livereload
- webpack只需要安裝
webpack-dev-server
即可,就自定義性來說(配置鉤子,中介軟體),webpack碾壓其餘兩個
- HMR
- 這也是開發不可少的,特別是前端業務越來越重,每次都要回首頁重新點選簡直痛苦(論首屏時間的重要性),特別是在改css的時候(改一個字型大小你給我把整個頁面都刷了??)
- webpack簡單配置一下,在需要熱更新的地方加上module.accept即可,相比於其他兩者,更成熟,自由度更好
- parcel再一次內建了熱更新機制
- rollup需要
rollup-plugin-hotreload
外掛
- 模組轉換
- 將非js格式轉化為js格式(bundler只認js)
- webpack就是一堆loader的配置
- parcel再一次對常見的格式提供了內建的轉換和轉譯,無需配置和安裝外掛
總結來說 如果是一個demo或者功能是可預期的簡單(不是產品說的那種),使用parcel 如果是最小化的第三方匯入的一個庫,使用rollup 其餘的使用webpack
說了一堆沒用的
前端總是有更多更大的輪子被創造出來,挺好,百花齊放,百家爭鳴,百舸爭流,百依百順. 大佬總是很閒,無法理解底層搬磚的辛苦,尤大在vue3.0時著重提了一把,既然輪子都到眼前了,還是掄一掄.
首先看看vite的描述 開發環境下使用原生esm,生產環境使用Rollup打包 的一個網頁開發構建工具 很自然繼承了二者的優點:
-
esm的優點
- 即時熱模組替換(HMR)
-
Rollup的優點
- 按需編譯,更多特性參照前文
esm是基於瀏覽器的實現的,當然該標準在ES6中已經提出,相容性請參考 mdn,這裡僅僅簡單的提幾點:
- 原生模組的匯出和引用
test.mjs
export const test = () => {
console.log('test')
}
複製程式碼
index.js
import { test } from "./test.mjs";
test()
複製程式碼
index.html
<script src="./index.js" type="module"></script>
複製程式碼
上述程式碼不需要經過任何的babel或webpack,直接可以被瀏覽器執行並列印test
- 可以匯出函式,var,const,let,類
-
mjs
與js
均可,只是mdn官方推薦使用js先,因為很多伺服器的content-type
不認識mjs
,會導致解析出錯.所以沿用js
即可 - 動態載入模組,實現懶載入
btn.addEventListener('click',() => {
import('./someDynamicModule').then(module => {
// handleModule
})
})
複製程式碼
與webpack的比較:
- Vite沒有在開發階段進行打包的操作,原始碼中的ES匯入語法是直接從瀏覽器中實現的. 瀏覽器通過之前說的
<script type="module">
來例項化他們,每一個的匯入都是一個HTTP請求. - 開發環境需要做的事情就是攔截並進行程式碼轉換瀏覽器無法解析的格式,比如 '*.vue,*.jsx'等.相當於webpack的loader.但是僅僅只有loader的作用,其他的並不涉及
- 生產環境Vite依然使用了bundle,但用的是更輕量的rollup而不是webpack,具體這兩者的淵源請參見
這樣的好處是什麼呢?
- 不用打包,所以冷啟動很快
- 程式碼按需編譯,天然的樹搖和懶載入
- HMR從依賴整個模組的數量中解耦出來所以不會因為app的增大而導致HMR的速度降低,
第三點我想著重說一下,webpack的HMR之所以需要設定module.accept就是希望開發者能在真的需要熱更新的地方使用,因為一旦監聽,就會監聽這個模組以及這個模組關聯的所有依賴的變化,這是比較消耗資源的,而且一旦發現變化會將整個模組以及關聯的模組都重新編譯一次. 那麼你說是不是很耗時間和效能?如果可以對每個單獨的模組進行監聽和重編譯,是不是美滋滋?
不過也不是沒有缺點
- 在整個網頁重新載入的時候會比webpack慢,因為是基於原生es,需要在遍歷到
<script type="module">
的時候發一次網路請求,並且在那個模組中有可能還有其他的模組,還得繼續髮網絡請求.但是在首次之後就可以使用快取了,也不是不可以接受,而且也可以選擇在開發環境時使用rollup進行打包.
下面來實戰一下,因為vue的獨佔期,所以對vue的專案是無縫結合的,但是我在工作中更多的是應用到了react,以下程式碼為與react的結合
- 新建專案
yarn init -y
- 安裝依賴
yarn add @pika/react @pika/react-dom vite
@pika是esm模組的字首,也就是react和react-dom的esm模組形式 - 新增react的支援配置 vite.config.js
module.exports = {
jsx: 'react',plugins: [require('vite-plugin-react')]
}
複製程式碼
- 專案根目錄建立
index.html
,如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
複製程式碼
- 新建
src/main.tsx
,如下
import React from 'react'
import style from './index.module.scss'
export default function() {
const [count,setCount] = React.useState(1)
return (
<div>
hello world
<button className={style.button} onClick={() => setCount(count + 1)}>
count: {count}
</button>
</div>
)
}
複製程式碼
- 關於css的模組化和前處理器
實際上vite建議使用原生的css變數,因為他的目標是現代瀏覽器. 如果非要使用前處理器也可以,有三種方案,請參考這篇文章,決定採用生成d.ts的方案,因為這樣可以有程式碼提示,更香.於是選擇安裝
typed-scss-modules
以及sass
,加個"tsm": "tsm src -w"
即可.這裡要注意,使用模組化的引入,也就是import style from 'xxx.scss'
需要遵循vue中的命名規範,需要加一個module字尾,也就是必須命名為xxx.module.scss
可以看出整個專案的配置項是相當的少,很多都黑盒處理了,讓前端可以更關注業務,之後我會進一步研究其原始碼,敬請期待.
附上整個專案地址