使用webpack4一步步搭建react專案(三)

gotcha發表於2019-04-06

第二章的配置基本已能達到正常的開發需求了。但是還有很多地方可以進行改善。

第三章 改善專案

使用最新的ES語法

React開發中難免要用到ES最新語法。例如常用的Decorators還在Stage 2階段,Dynamic import還在Stage 3階段。這些新的語法並沒被@babel/preset-env涵蓋。因此我們需要額外配置對應的babel外掛。

安裝babel外掛:

  • 支援裝飾器 @babel/plugin-proposal-decorators
  • 支援類屬性 @babel/plugin-proposal-class-properties
  • 支援動態import @babel/plugin-syntax-dynamic-import

配置.babelrc檔案:

{
  "presets": ["@babel/preset-env", "@babel/preset-react"],
  "plugins": [
    // 注意decorators外掛要寫在class-properties前面
    // decorators外掛需要配置legacy為true來相容以前的裝飾器寫法
    ["@babel/plugin-proposal-decorators", { "legacy": true }],
    ["@babel/plugin-proposal-class-properties", { "loose": true }],
    "@babel/plugin-syntax-dynamic-import"
  ]
}
複製程式碼

新增css預處理與postcss

我們可以使用sass來增強css的程式設計和抽象能力,使用postcss的autoprefixer外掛給css自動新增瀏覽器廠商字首。

安裝:

  • sass-loader
  • postcss-loader autoprefixer

webpack.dev.js的配置:

// ...
module: {
  rules: [
    {
      test: /\.scss$/,
      // loader是從後往前載入的,postcss-loader得在sass-loader前面
      use: ["style-loader", "css-loader", "postcss-loader", "sass-loader"]
    },
    // ...
  ]
},
// ...
複製程式碼

webpack.prod.js的配置:

// ...
module: {
  rules: [
    {
      test: /\.scss$/,
      use: [
        MiniCssExtractPlugin.loader,
        "css-loader",
        "postcss-loader",
        "sass-loader"
      ]
    },
    // ...
  ]
},
// ...
複製程式碼

在專案根目錄下建立postcss.config.js檔案:

module.exports = {
  plugins: [require("autoprefixer")]
};
複製程式碼

配置瀏覽器相容範圍

.babelrc內配置的@babel/preset-env能自動為專案打包必要的polyfill,postcss.config.js內配置的autoprefixer外掛能自動為css新增必要的瀏覽器廠商字首。它們是怎麼確定哪些polyfill還有哪些瀏覽器廠商字首是必要新增的呢,畢竟不同公司甚至不同專案所要相容的瀏覽器版本不一樣。有的專案沒有任何相容需求,那麼專案應該少依賴一些polyfill,有些專案要相容到IE瀏覽器,那就要新增更多的polyfill和瀏覽器廠商字首。所以我們需要配置.browserslistrc來告訴這些打包工具我們要相容的瀏覽器範圍。

在專案根目錄下建立.browserslistrc檔案:

> 1%
last 2 versions
not ie <= 8
複製程式碼

這個配置的大概意思是:市場份額大於1%的瀏覽器,最新的兩個版本,排除IE8以下的瀏覽器。

配置.editorconfig

有些人喜歡用水平製表符縮排,而有些人喜歡用2個空格。因為使用的作業系統不同,有些人換行符是LF,有些人是CRLF。雖然這些瑣碎的東西可以在專案開發初期約定好,並設定到每個開發人員編輯器格式化配置內。但是這樣很麻煩。

我們在專案根目錄下建立.editorconfig

root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
複製程式碼

這個配置告訴編輯器,當前專案的縮排用的是2個空格,換行用的是LF,並在每個檔案底部插入一行空行。編輯器看到專案內有.editorconfig檔案,就會按它的要求來格式化專案檔案。

使用editorconfig的好處是,他能更細粒度的控制每個專案甚至不同檔案型別的格式化風格,這樣可以讓不同的專案擁有不同的格式化風格。

配置完後,編輯器需要在外掛市場下載editorconfig外掛。webstorm內部預設安裝了該外掛,所以可以不用下載。

配置ESLint和prettier

ESLint可以校驗我們的程式碼風格和一些語法錯誤,在團隊開發時,可以保證程式碼風格的一致性並及早發現一些錯誤。

ESLint很多時候會因為缺少空格或逗號而報錯,這些瑣碎的錯誤會很惱人,因此我們可以使用prettier來幫助我們來格式化程式碼。

安裝:

  • eslint eslint-loader
  • babel-eslint
  • eslint-config-airbnb eslint-config-prettier

在安裝eslint-config-airbnb時,控制檯會有warning,我們需要根據它的warning將所有的peer dependency都安裝好。

webpack.common.js配置:

// ...
module: {
  rules: [
    {
      enforce: "pre",
      test: /\.jsx?$/,
      include: path.resolve(__dirname, "src"),
      use: "eslint-loader"
    },
    // ...
  ]
}
// ...
複製程式碼

根目錄下新增.eslintrc.js

module.exports = {
  root: true,
  parser: "babel-eslint",
  env: {
    browser: true,
    es6: true,
    node: true
  },
  parserOptions: {
    ecmaVersion: 6,
    sourceType: "module"
  },
  extends: ["airbnb", "prettier"],
  rules: {
    "no-console": process.env.NODE_ENV === "production" ? "error" : "off",
    "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off"
  }
};

複製程式碼

package.json內新增lint precommit兩條指令碼

// ...
"scripts": {
  "start": "cross-env NODE_ENV=development webpack-dev-server --config webpack.dev.js",
  "build": "cross-env NODE_ENV=production webpack --config webpack.prod.js",
  "lint": "cross-env NODE_ENV=production eslint --ext .jsx --ext .js --fix ./src",
  "precommit": "npm run lint"
},
// ...
複製程式碼

執行npm run lint時,ESLint會檢查./src目錄下的所有.js .jsx結尾的檔案,並盡力修復一些問題。ESLint不能修復的問題會列印到控制檯上,此時就要手動去修復問題了。

每次git提交程式碼前會先執行precommit指令碼,該指令碼就是讓ESLint檢查程式碼,如果檢查不通過就無法提交程式碼。這樣可以保證程式碼倉庫內的程式碼質量。想要precommit指令碼生效,需要安裝husky(哈士奇),而且我們在指令碼內使用“cross-env”來修改環境變數,所以得安裝cross-env

安裝:

  • husky
  • cross-env

推薦在編輯器內安裝ESLint 外掛,這樣能在書寫程式碼實就能看的ESLint的報錯資訊。安裝ESLint外掛後,它可能會在我們不願意它去檢查的檔案內報錯,所以我們新增.eslintignore來告訴外掛要跳過的檢查檔案與目錄。

.eslintignore配置

node_modules
/dist

webpack.common.js
webpack.prod.js
webpack.dev.js
postcss.config.js
複製程式碼

同時推薦安裝prettier外掛,並配置編輯器在儲存時自動格式化。

熱更新 (Hot Module Replacement)

使用webpack-dev-server開發React時,每次檔案修改便會自動重新整理頁面。雖然這和傳統的手動重新整理頁面相比方便了很多,但是在某些情況下還不夠方便。就比如開發一個表單模態視窗時,重新整理頁面會導致模態視窗被關閉,並且表單內填寫的資訊丟失。

webpack的熱更新就能解決這個痛點,它能在介面不重新整理的狀態下更新介面。

webpack4預設支援熱更新,我們只需要開啟這個功能就可以。

webpack.dev.js內開啟熱更新:

// ...
devServer: {
  hot: true, // 開啟熱更新
  historyApiFallback: true
},
// ...
複製程式碼

我們使用react-hot-loader來支援React的熱更新。

安裝:

  • react-hot-loader

.babelrc新增react-hot-loader提供的外掛:

{
  "presets": ["@babel/preset-env", "@babel/preset-react"],
  "plugins": [
    ["@babel/plugin-proposal-decorators", { "legacy": true }],
    ["@babel/plugin-proposal-class-properties", { "loose": true }],
    "@babel/plugin-syntax-dynamic-import",
    "react-hot-loader/babel"
  ]
}
複製程式碼

注意這個外掛的寫法是react-hot-loader/babel

最後,修改App.jsx內的程式碼。使用react-hot-loader提供的高階元件來裝飾我們的App元件。

import React from "react";
// 匯入hot函式
import { hot } from "react-hot-loader/root"; 

// ...

function App() {
  return (
    // ...
  );
}

// 使用hot函式裝飾App元件
export default hot(App);
複製程式碼

搖樹優化 (Tree Shaking)

webpack4在production模式下會開啟Tree Shaking,但是需要注意以下幾點

  • 使用ES2015模組語法(例:importexport),被編譯成CommonJS規範的模組不能被優化。
  • 需要在package.json檔案內新增"sideEffects"欄位。該欄位的值可以是模組名稱陣列,用來告訴webpack哪些模組是有負作用的。該欄位的值也可以是false,表示所有模組都沒有副作用。被標識有副作用的模組不會被Tree Shaking。
  • webpack配置內的mode設為"production"

程式碼

專案程式碼 Github 倉庫

其他章節

相關文章