再見了 Create React App! 從Webpack 到 Snowpack 搬家紀錄
過去開發新的 react 專案時,多是使用 create-react-app (CRA) 來快速完成初期建置,而使用 webpack 的 CRA 存在已下缺點:
- webpack 的啟動時間長
- webpack Hot Module Replacement (HMR) 需要重新整理網頁,無法保留 state
- 若要修改 webpack 設定,需靠 react-app-rewired 或 craco 等套件來實現
由於過去瀏覽器對 ES module (ESM) 支援度並不好,因此需要透過 webpack 打包成瀏覽器看得懂的語法,但隨著 ESM 逐漸被主流瀏覽器所支持(Can I Use),不需打包的 build tool 如 Snowpack、Vite 成為越來越多開發者的選擇,更多詳細的比較可以參考:
https://blog.logrocket.com/snowpack-vs-webpack/
本篇文章將告訴你如何將使用 CRA 的舊專案轉移至 Snowpack (原本是想選目前星星數比較多的 Vite,但轉換的過程感覺不是很穩定,也遇到了一些不知道怎麼解決的 error),以及過程中所遇到的問題。
開發環境
react-scripts@4.0.1
react@17.0.1
typescript@3.9.7
- 使用
craco
、eslint
轉換過程
建議可以先將官方的 react template 開著來對照。
1. 安裝 snowpack
先在 terminal 執行:
yarn add -D snowpack
接著改寫 package.json
的 scripts:
"scripts": {
- "start": "react-scripts start",
+ "dev": "snowpack dev",
- "build": "react-scripts build",
+ "build": "snowpack build",
...
},
...
然後執行 yarn dev
,接下來就完成了🎉🎉!感謝大家的收看!
如果是有一定開發規模的專案,這時候應該會被 error 噴個滿臉。
2. 新增 snowpack 所需檔案
- snowpack.config.js:在和
package.json
的資料夾(根目錄)新增檔名為snowpack.config.js
之設定檔,內容可以去抄官方的 template。 - index.html:將原本放在
public/index.html
的檔案加入<script type="module" src="/src/index.js"></script>
。由於路徑會自動 rebase 至專案根目錄,因此可以將所有的%PUBLIC_URL%
刪除。
3. 排除 error
會遇到的 error 因專案而異,這邊僅紀錄這次所遇到的問題,有沒列到的也歡迎留言補充。
- polyfillNode:import 的 npm package 並不一定能直接在瀏覽器使用,Snowpack 提供了一個簡單的解決方法,只需將
packageOptions.polyfillNode
設為 true 即可。 - 路徑:ESM import 的路徑開頭只能是
/
、./
、和../
,所以如果以前有寫import XX from 'path/to/XX'
這類的程式碼,就會被解讀成為 npm package 而導致 error。可以透過在前面加上./
,或是透過 path alias 來解決。 - path alias:蠻多開發者會習慣用
@
代表src
,在 Snowpack 只需要在snowpack.config.js
的 alias ,以及 tsconfig.json 的 path 做好相對應的設定即可。
// snowpack.config.js
// https://www.snowpack.dev/reference/configuration#alias
{
alias: {
'@': './src',
},
...
}
// tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
},
...
}
}
- 環境變數:原本 node.js 下的環境變數是靠
process.env.XXX
來讀取,在 ESM 下則會揭露於import.meta.env.XXX
。另外需注意變數名稱需為SNOWPACK_PUBLIC_*
之格式,若是寫在.env
檔案內的需要安裝 plugin-dotenv 才能正常讀取,詳細請見官方教學。 - 型別宣告缺失:在使用
import.meta.XXX
時會出現沒有定義 ImportMeta 屬性的 error,這時只需要安裝@types/snowpack-env
即可將缺少的型別補上。 - proxy:開發時會需將 api request proxy 至正確的 api server,在 webpack 會以
setupProxy.js
來做設定,Snowpack 則可以參考官方教學。 - static assets:使用 typescript 在 import png、svg 等靜態資源時會出現
Cannot find module
的 error,可能以前 CRA 默默的幫我們處理好了,只需要在xxx.d.ts
(放在自己覺得合適的地方)宣告以下型別即可:
declare module '*.png' { export default '' as string; }
// jpg, svg 依此類推
4. 開啟 Hot Module Replacement (HMR)
終於結束了枯燥乏味的 debug 過程,這時候專案應該可以正常的開起來了,不過搬來 Snowpack 的主要原因就是為了更快的開發速度,這時超快速,可以保留 state,不需要 refresh 的 HMR 正式當場啦!其實官方的教學已經寫得很簡單了,不過為了讓文章看起來更豐富一點,我還是將內容再濃縮一下放上來,不用謝不用謝~
首先先將 HMR 模式打開
// src/index.ts...
if (import.meta.hot) {
import.meta.hot.accept();
}
再來灌需要的 package
yarn add -D @snowpack/plugin-react-refresh
最後 snowpack.config.js
中使用
{
plugins: ['@snowpack/plugin-react-refresh'],
...
}
恭喜!這次真的可以開心的開始開發了🎉!
Production 環境
Snowpack 可以自行選擇打包工具,預設為 esbuild
,可以透過修改 config 中的 optimize
來調整打包的行為:
// snowpack.config.js
module.exports = {
optimize: {
bundle: true,
minify: true,
target: 'es2018',
},
};
但是由於 esbuild 目前還沒非常成熟,官方目前其實比較推薦用 webpack 來做打包,使用方式非常簡單,先安裝好 @snowpack/plugin-webpack,然後在 config 中加入:
// snowpack.config.jsmodule.exports = {
plugins: ['@snowpack/plugin-webpack'],
};
只需一行即設定完成!開發者也可以對 webpack 設定做調整,方法請自行參考套件文件。
至此就是所有我經歷的過程,其實目前 Snowpack 已經十分完善,很多碰到的問題都可以在官方文件得到解答,祝各位都能順利的轉換,享受 ESM 帶來的高速開發體驗!