WeHelp
簡單 5 步驟,透過 Webpack 建立 React 開發環境
2023-01-12 02:12:38
## 起頭 在開發一個新專案時,第一道難關就是建立開發環境, 開始 React 專案的方式有很多種, 像是一些常聽到的 toolchain 工具 : [CRA (create-react-app)](https://create-react-app.dev/)、[Vite](https://vitejs.dev/), 或是使用一些 Framework 如 : [Next.JS](https://nextjs.org/)、[Gatsby](https://www.gatsbyjs.com/), 詳細可以參考 [官網](https://beta.reactjs.org/learn/start-a-new-react-project) 上的介紹。 而這篇文章所使用到的 [Webpack](https://webpack.js.org/) 也是其中之一, 同時這也是我推薦每一位剛接觸前端的朋友可以嘗試的選項, 原因是上述那些如 CRA 或 Next.JS 這些方便的開發工具, 大多都是基於 Webpack 之上的一個產物, 早點接觸 Webpack, 有助於你理解它們在背後幫你處理了哪些麻煩事, 另外若之後你想在專案的打包上做更彈性的調整, 相信 Webpack 會是你的不二之選。 ## 工具介紹 工欲善其事,必先利其器, 在開始之前,我們先來一覽等等會用到的工具 | 工具 | 簡述 | | -------- | ------------------------------------------------------------------------------ | | npm | Node.js 的套件管理工具 | | Webpack | 打包工具,能夠將多個資源檔合併成一個檔案 | | Babel | JavaScript Compiler,能夠轉換一些如 JSX 的 JavaScript 寫法成瀏覽器讀得懂的語法 | | Eslint | JavaScript Linter,幫你進行靜態的的語法分析,抓出常見的錯誤 | | Prettier | 程式碼格式化工具,可確保你專案中的 Coding Style 一致 | 本篇文章只會將重點著重在以上提到的工具, 其餘的配置相信讀者在讀完之後,有能力自行完成 ## 建立開發環境 ### 1. 安裝 EsLint 及 Prettier [Install EsLint](https://eslint.org/docs/latest/user-guide/getting-started) ```shell npm init @eslint/config ``` [Install Prettier](https://prettier.io/docs/en/install.html) ```shell npm install --save-dev --save-exact prettier npm install --save-dev eslint-config-prettier echo {}> .prettierrc.json ``` 最後整合 EsLint 和 Prettier 這兩者需再稍作一些調整, 可以參考[官方文章](https://prettier.io/docs/en/related-projects.html#eslint-integrations) 的說明, 我這邊是使用 [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) 來處理。 整體的目的而言, 就是讓 Coding Style 專心交給 Prettier 處理, 而 其餘程式上的寫法檢查 就交給 EsLint 來協助, 下方是產出的結果 : **.eslintrc.json** ```JSON { "env": { "browser": true, "es2021": true }, "extends": ["eslint:recommended", "plugin:react/recommended", "prettier"], "plugins": ["react"], "settings": { "react": { "version": "detect" } } } ``` **.prettierrc.js** ```JavaScript module.exports = { trailingComma: "es5", tabWidth: 4, semi: true, singleQuote: false, }; ``` ### 2. 安裝 Webpack 及處理 Config 檔設定 [Install Webpack](https://webpack.js.org/guides/getting-started/#basic-setup) ```shell npm install webpack webpack-cli --save-dev ``` 安裝完成後, 接下來我們要建立 Webpack 的 Config 檔, 讓我們能彈性設置專案的打包方式, - `entry` : 是指我們要執行打包的進入點。 - `output` : 則是告訴 webpack 打包後的檔案要輸出到哪。 **webpack.config.js** ```JavaScript const path = require("path"); module.exports = { entry: "./src/index.js", output: { filename: "bundle.js", path: path.resolve(__dirname, "dist"), }, }; ``` 建立 Config 完成後, 我們分別去建立 `entry` 的 JavaScript 程式碼, 以及在我們 `output` 的 folder `dist` 下, 建立一個 html 來引入我們打包過後的 js 檔。 **/src/index.js** ```JavaScript const root = document.getElementById("root"); const helloWebpack = document.createElement("h1"); helloWebpack.textContent = "Hello Webpack"; root.appendChild(helloWebpack); ``` **/dist/index.html** ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Hello React</title> </head> <body> <div id="root"></div> <script src="./bundle.js"></script> </body> </html> ``` 之後就在我們的 package.json 中加入 bundle 的指令 **package.json** ```json { ... "scripts": { "build": "webpack --mode='production'", }, ... } ``` 最後執行它,那麼設定一個最基本的 Webpack 就大功告成了~ 之後如果要做靜態網站的部署, 就直接將 `dist` 這個 folder 拿去做 Hoisting 就可以了 ``` npm run build ``` ### 3. 優化我們的開發體驗,Webpack Dev Server 你們可能已經注意到了, 每一次我們異動完 `entry` 的 js 後, 都要再執行一次 `npm run build` 才能使我們的 html 拿到最新版本的 JavaScript, 這一來一回也漸漸消磨我們的耐心, 整個開發體驗多了不少煩躁感~ 為了解決這個問題, 推薦大家使用 [Webpack Dev Server]() 這個工具, 每一次我們更動完並按下儲存後, 它就會自動將我們的程式碼打包一次輸出到 `output` 指定的位置, 細節大家可以再去看看它的[文件](https://github.com/webpack/webpack-dev-server), 這邊就進行最基本的 Dev Server 配置 [Install Webpack](https://webpack.js.org/configuration/dev-server/) ```shell npm install webpack webpack-cli --save-dev ``` 首先在我們的 `webpack.config.js` 加入 Dev Server 的設定 **webpack.config.js** ```JavaScript const path = require("path"); module.exports = { ..., devServer: { compress: true, port: 9000, static: { directory: path.join(__dirname, "dist"), }, }, }; ``` 並在 package.json 中加入啟動 Dev Server 的指令 **package.json** ```json { ... "scripts": { "build": "webpack --mode='production'", "dev": "webpack serve --mode='development'" }, ... } ``` 這樣你在本機開發上, 只要執行 `npm run dev` 就可以享受舒適的開發體驗, 而 `npm run build` 這個指令,就留到要部署的時候再去執行即可 ### 4. 讓瀏覽器讀懂我們的 JavaScript,Babel 舉個例子, 我們在開發時很常使用 module 的方式來管理程式碼, 很常 `import` 來 `export` 去, 但是瀏覽器本身其實是讀不懂 `import` 及 `export` 這兩個語法, 那要怎麼辦呢? 就好比一個日本人在你面前用日語自我介紹,而你一個字也聽不懂, 這時後你可能就會拿出 Google Translate 來進行翻譯, 轉換成你聽得懂的中文。 而 Babel 正是扮演 Google Translate 這樣的角色, 特別是現在 JavaScript 的語法一直推陳出新, 而瀏覽器本身跟不上這個速度, 那麼就可以使用 Babel 來將一些比較新穎的語法, 轉換成瀏覽器讀得懂的舊語法, 這就是為何要使用 Babel 的原因。 [Install Babel](https://babeljs.io/setup#installation) ```shell npm install --save-dev babel-loader @babel/core @babel/preset-env ``` 安裝完之後,將 Babel 加入至我們的 webpack.config.js 中, 並且建立 `.babelrc` 來設定我們的 babel **webpack.config.js** ```JavaScript const path = require("path"); module.exports = { ..., module: { rules: [ { test: /\.m?js$/, exclude: /node_modules/, use: "babel-loader", }, ], }, }; ``` **.babelrc** ```json { "presets": ["@babel/preset-env"] } ``` #### Babel 和 EsLint 整合 這樣的話 Webpack 打包設定就差不多完成了, 但是還有一點,就是我們開發環境的 EsLint 設定。 在預設狀況下,EsLint 是以最新的 ECMAScript 標準來去審查我們的 Code, 而這也會如瀏覽器一樣,不支援一些新語法, 因次我們需要安裝 [@babel/eslint-parser](https://www.npmjs.com/package/@babel/eslint-parser), 來讓 EsLint 透過 Babel 讀懂我們的程式碼 [Install @babel/eslint-parser](https://www.npmjs.com/package/@babel/eslint-parser) ```shell npm install --save-dev @babel/eslint-parser ``` 接下來就是在我們的 `.eslintrc.json` 加入設定就可以了 ```json { ..., "parser": "@babel/eslint-parser", ... } ``` ### 5. 安裝 React 最後也是最重要的, 在我們的專案加入 React 來開發,第一步當然就是先安裝啦~ **Install React** ```shell npm install react react-dom ``` 接這寫一個簡單的 React 程式碼在我們的 `entry` **/src/index.jsx** ```JavaScript import React from "react"; import ReactDOM from "react-dom/client"; import App from "./app"; ReactDOM.createRoot(document.getElementById("root")).render( <React.StrictMode> <App /> </React.StrictMode> ); ``` **/src/app.jsx** ```JavaScript import { useState } from "react"; const App = () => { const [liked, setLiked] = useState(false); if (liked) { return "Hello React"; } return <button onClick={() => setLiked(true)}>Click Me</button>; }; export default App; ``` 另外我們也來調整一下 Webpack 的設定, 以符合 React 的開發, **webpack.config.js** ```JavaScript const path = require("path"); module.exports = { entry: "./src/index.jsx", ..., // 加入預設副檔名的解析順序 resolve: { extensions: [".jsx", ".js"], }, ..., module: { rules: [ { // 多一個 jsx 的解析 test: /\.m?jsx?$/, exclude: /node_modules/, use: "babel-loader", }, ], }, }; ``` 如果直接執行 `npm run build`, 那它會直接跳一個錯誤跟你說 `Support for the experimental syntax 'jsx' isn't currently enabled`, 這是因為我們在 JavaScript 裡面使用 JSX 這種寫法, Webpack 讀不懂因此直接中斷打包。 而要處理這種讀不懂的問題, 就是找我們的 Babel 來協助了,而 [@babel/preset-react](https://babeljs.io/docs/en/babel-preset-react#docsNav) 就是我們會用到的工具 **Install @babel/preset-react** ```shell npm install --save-dev @babel/preset-react ``` 安裝完成後,再把它加入 `.babelrc` 的設定中就可以了 ```json { "presets": [ "@babel/preset-env", [ "@babel/preset-react", { "runtime": "automatic" } ] ] } ``` 最後就是關於 EsLint 的一些設置, 讓 EsLint 知道我們有使用 JSX 這種語法 **.eslintrc.json** ```JSON { ..., "parserOptions": { "ecmaFeatures": { "jsx": true } }, ... "rules": { // React 17 之後,就不用每隻都要 import React 了 "react/jsx-uses-react": "off", "react/react-in-jsx-scope": "off" } } ``` ## 結語 以上就完成了 React + Webpack + Babel 的基本配置了, 之後如果需要加其他的配置,例如讓 [Webpack 讀懂 CSS](https://webpack.js.org/guides/asset-management/#loading-css) 或是 [Webpack 讀懂圖片檔](https://webpack.js.org/guides/asset-management/#loading-images), 相信對讀完此篇的各位也不是太難的問題, 整篇文章的程式碼放在我的 [Github](https://github.com/ChengYiLin/Setup-React-with-Webpack) 上, 喜歡也不忘給個星星, Happy Coding 🥳 ## 參考資料 - [EsLint](https://eslint.org/docs/latest/user-guide/getting-started) - [Prettier](https://prettier.io/docs/en/install.html) - [Webpack Guides](https://webpack.js.org/guides/) - [Babel Guides](https://babeljs.io/setup#installation)