Webpack + React + TypeScript 構建一個標準化應用

項目及工程化配置以及主要功能配置、規范化管理和使用細節應該都沒啥問題了。

后面若發現構建及配置問題、以及可優化的細節部分、包括功能的進一步迭代也會使項目不斷更新完善的~

目前主要是做了規范及工程化的配置,后期打算開發并開源一個react-admin標準后臺管理系統,用于實踐并鞏固一些前端技術框架與組件開發等。

hello

效果圖

最簡單的demo運行效果

最終效果

背景

為什么要自己搭建一個webpack-react-ts的標準化項目?

原因之一

在很早之前的公司時,項目實際開發過程中產生過這種需求:

  1. 每次開發新項目時希望有個完整功能、配置好用、標準化規范的模板可以快速使用

  2. 完整功能:如果是使用create-react-app創建項目,屬于最簡易版的一個實現了,各種loader、plugin、babelwebpack配置缺失,作為現代前端開發不可或缺的構建工具,其對項目的大部分功能支持是必須的。

  3. 配置好用:webpack對各種插件的配置與集成,基本路由模塊、頁面模塊、組件模塊、store狀態管理模塊等基本常用功能的簡要示例及demo,要有一定的覆蓋率。

  4. 標準規范:這個可能是工程化構建最重要的部分之一了,eslintprettierstylelint、commitlint等lint規范和格式化以及test測試,還有目錄結構規范、命名規范等。對于規范化的意義其重要性不言而喻,可讀性、可維護性、開發效率、bug率等可見一斑

原因之二

當然網上肯定有很多優秀的輪子供我們使用,他們有的功能更全、有的細節更好,有的示例更完整。這都是我們學習的榜樣,對于其源碼閱讀和學習也是極為有益的,不過,始終避免不了一點,看的再多都不如自己實踐來的有效果,所以,這也是我考慮的原因之一,為了自己實踐和操作來提升技術熟練度。

原因三

這也是源于在實際開發過程中的需求,即,不同技術平臺及場景適應于不同的技術框架和路線。

舉個栗子,

  1. 管理后臺系統:這個多適用于PC端,使用單頁面應用開發,主流技術框架 React、VueAngular

  2. 網站類:這類項目一般追求美觀和SEO搜索的重要性,而不會像管理后臺系統一樣有很復雜的邏輯,更多的是一些動效及UI交互,因為SPA的首屏加載及SEO問題,社區有成熟的服務端渲染SSR方案:nextnuxt,分別對應reactvue技術棧,對于習慣了單頁面開發的同學還是很友好的。

  3. 移動端:輕量化、輕量化、輕量化,重要的事情說三遍。手機端流量第一,項目越小越輕量性能越好加載也就越快,對于用戶體驗也就越好。比較手機端一般對應的都是C端用戶,不像管理后臺主要是給B端及公司內部使用。用戶體驗要求是完全不一樣的。如,移動端版react——preact,又如sveltesolidjs等無虛擬DOM框架,減少大量運行時代碼。

所以,我認為每個技術都有其對應的優勢和適合的場景,單一框架并不是完全適合梭哈到底的。

這也是我開發的node-cli自動化初始化項目的一個框架模板之一。

接下來對各個不同技術方案及最佳實踐也會考慮構建具有實戰意義的模板以供使用

主要方向大概分為:webpack+react/vue+typescriptwebpack方向、vite+react/vue+typescriptvite方向、nuxt/next/egg/koa等服務端渲染SSR方向、svelte/solidjs等無虛擬DOM的輕量級框架方向、rollup/parcel等構建工具方向、esbuild/swc等新型編譯器與構建工具的結合使用等、以及小程序/跨平臺等。

有點飄啊,想法還挺多的??~

開搞

目標

  • 技術棧:Webpack5.x + React17.x + Antd4.x + TypeScript4.x + Less
  • 工程規范/格式化:Eslint + Stylelint + Prettier + Commitlint
  • ES6、JSXBabel支持
  • 支持HMR熱更新
  • 支持低版本瀏覽器兼容
  • 支持Antd按需加載、自定義主題、css module
  • 支持js、css壓縮、chunk拆分、Gzip

依賴

dependencies

"dependencies": {
  "antd": "^4.16.10", // 懂得都懂
  "axios": "^0.21.1", // 懂得都懂
  "clsx": "^1.1.1", // 條件處理 React className 類名
  "core-js": "3", // 現代JS語法polyfills庫,用于兼容瀏覽器及ES6、ES7語法
  "dayjs": "^1.10.6", // 日期處理庫,比moment小很多,只有幾kb
  "history": "^5.0.1", // H5 history庫
  "lodash": "^4.17.21", // 非常全面的方法庫
  "react": "^17.0.2", // 懂得都懂
  "react-dom": "^17.0.2", // 懂得都懂
  "react-helmet-async": "^1.0.9", // 在react中優雅的添加 HTML header 各種屬性
  "react-router-dom": "^5.2.0" // react 路由庫,經典 react 三件套
}

devDependencies

"devDependencies": {
  // babel
  "@babel/cli": "^7.14.8", // 可以讓babel以cli的方式執行  如:babel src --out-dir dist --watch
  "@babel/core": "^7.15.0", // babel 核心包
  "@babel/plugin-proposal-class-properties": "^7.14.5", // @babel/preset-env 插件已包含
  "@babel/plugin-syntax-dynamic-import": "^7.8.3", // 動態導入、懶加載
  "@babel/plugin-transform-modules-commonjs": "^7.15.0", // 轉化成CommonJS 規范的代碼
  "@babel/plugin-transform-react-constant-elements": "^7.14.5", // React 常量元素轉換器 : 它會尋找不隨 props 改變的所有靜態元素,并將它們從渲染方法(或者無狀態函數式組件)中抽離出來,以避免多余地調用 createElement
  "@babel/plugin-transform-react-inline-elements": "^7.14.5", // React 行內元素轉換器 : 它會將所有 JSX 聲明(或 者 createElement 調用)替換成優化過的版本,以便代碼可以更快執行
  "@babel/plugin-transform-runtime": "^7.15.0", // 抽離提取 Babel的注入代碼,防止重復加載,減小體積
  "@babel/preset-env": "^7.15.0", // 提供的預設,允許我們使用最新的JavaScript
  "@babel/preset-react": "^7.14.5", // react 支持
  "@babel/preset-typescript": "^7.15.0", // typescript 支持
  "babel-plugin-dynamic-import-node": "^2.3.3", // 為node提供加載轉換 import => require
  "babel-plugin-import": "^1.13.3", // 按需引入、加載
  "babel-plugin-lodash": "^3.3.4", // 按需加載
  "babel-plugin-transform-react-remove-prop-types": "^0.4.24", // 從生產生成中刪除不必要的類型

  // commitlint 是 git commit 執行規則相關插件
  "@commitlint/cli": "^13.1.0", 
  "@commitlint/config-conventional": "^13.1.0",

  // react hot 配合webpack實現熱更新插件
  "react-refresh": "^0.10.0",
  "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3",

  // @types 開頭的是對應包的 TypeScript 類型聲明
  "@types/enzyme": "^3.10.9",
  "@types/enzyme-adapter-react-16": "^1.0.6",
  "@types/enzyme-to-json": "^1.5.4",
  "@types/react-dom": "^17.0.9",
  "@types/react-helmet": "^6.1.2",
  "@types/react-router-dom": "^5.1.8",
  "@types/webpack-env": "^1.16.2",

  // enzyme 測試庫
  "enzyme": "^3.11.0",
  "enzyme-adapter-react-16": "^1.15.6",
  "enzyme-to-json": "^3.6.2",

  // eslint
  "eslint": "^7.32.0",
  "eslint-config-airbnb-typescript": "^12.3.1", // airbnb 規范
  "eslint-config-prettier": "^8.3.0", // 關閉所有不必要或可能與[Prettier]沖突的規則。
  "eslint-import-resolver-typescript": "^2.4.0", // 添加 ts 語法支持  eslint-plugin-import
  "eslint-import-resolver-webpack": "^0.13.1", // 支持 eslint-plugin-import 讀寫模塊解析
  "eslint-plugin-import": "^2.23.4", // ES6+  import/export 語法支持
  "eslint-plugin-jsx-a11y": "^6.4.1", // JSX元素的可訪問性規則的靜態AST檢查器 
  "eslint-plugin-prettier": "^3.4.0", // 以 eslint的規則運行 prettier 格式化
  "eslint-plugin-react": "^7.24.0", // react 相關規則
  "eslint-plugin-react-hooks": "^4.2.0", // react-hooks 相關規則
  "eslint-plugin-redux-saga": "^1.2.1", // redux-saga 相關規則
  "@typescript-eslint/eslint-plugin": "^4.29.0", // 使 eslint 支持 typescript,.eslintrc.js 的 plugins 參數
  "@typescript-eslint/parser": "^4.29.0", // 使 eslint 支持 typescript ,.eslintrc.js 的 parser 參數

  // webpack
  "webpack": "^5.49.0",
  "webpack-bundle-analyzer": "^4.4.2", // 包依賴分析 可視化
  "webpack-cli": "^4.7.2", // cli
  "webpack-dev-middleware": "^5.0.0", // 中間件,可配合 express以服務的方式開發使用
  "webpack-dev-server": "^3.11.2", // dev-server
  "webpack-hot-middleware": "^2.25.0", // 熱加載
  "webpack-pwa-manifest": "^4.3.0", // 生成 pwa 相關配置

  // webpack loader:解析對應文件
  "babel-loader": "^8.2.2",
  "style-loader": "^3.2.1", // 添加 css 到 HTML
  "css-loader": "^6.2.0", // css加載器 處理 @import/url()
  "postcss-loader": "^6.1.1", // 處理 css
  "less-loader": "^10.0.1", // less => css
  "file-loader": "^6.2.0", // 通過 import/require() 加載的圖片等解析為 url
  "html-loader": "^2.1.2", // 壓縮HTML
  "svg-url-loader": "^7.1.1",
  "url-loader": "^4.1.1",

  // webpack plugin
  "html-webpack-plugin": "^5.3.2", // 簡化HTML文件的創建 ,配合webpack包含hash的bundle使用
  "mini-css-extract-plugin": "^2.2.0", // css 壓縮
  "terser-webpack-plugin": "^5.1.4", // 使用 terser 壓縮 js (terser 是一個管理和壓縮 ES6+ 的工具)
  "clean-webpack-plugin": "^4.0.0-alpha.0", // 用于刪除/清理生成的 build 文件 
  "compression-webpack-plugin": "^8.0.1", // Gzip壓縮

  // prettier 格式化
  "prettier": "^2.3.2",
  "pretty-quick": "^3.1.1", // 在更改的文件上運行 prettier

  // stylelint css樣式規范
  "stylelint": "^13.13.1",
  "stylelint-config-recess-order": "^2.4.0", // 按照session和Bootstrap的方式對CSS屬性進行排序。
  "stylelint-config-standard": "^22.0.0", // 基本規范

  // 工具
  "husky": "^7.0.1", // 自動配置 Git hooks 鉤子
  "lint-staged": "^11.1.2", // 對暫存的git文件運行linter
  "rimraf": "^3.0.2", // 刪除cli,兼容不同平臺 
  "yargs": "^17.1.0", // 讀取命令參數

  // 其他
  "typescript": "^4.3.5",
  "less": "^4.1.1", // less 的解析庫
  "postcss": "^8.3.6", // 專門處理樣式的工具
  "postcss-nested": "^5.0.6", // 解析處理嵌套規則
  "autoprefixer": "^10.3.1", // 自動生成各瀏覽器前綴 postcss 的一個插件
  "serve": "^12.0.0", // 本地啟動一個服務,可以查看靜態文件
}

目錄規劃

├── dist                                // 默認的 build 輸出目錄
├── .husky                              // pre-commit hook
├── config                              // 全局配置文件及webpack配置文件
├── public                              // 靜態文件
├── test                                // 測試目錄
└── src                                 // 源碼目錄
    ├── assets                          // 公共的文件(如image、css、font等)
    ├── components                      // 項目組件
    ├── constants                       // 常量/接口地址等
    ├── layout                          // 全局布局
    ├── routes                          // 路由
    ├── store                           // 狀態管理器
    ├── utils                           // 工具庫
    ├── pages                           // 頁面模塊
        ├── Home                        // Home模塊,建議組件統一大寫開頭
        ├── ...
    ├── App.tsx                         // react頂層文件
    ├── main.ts                         // 項目入口文件
    ├── typing.d.ts                     // ts類型文件
├── .editorconfig                       // IDE格式規范
├── .eslintignore                       // eslint忽略
├── .eslintrc                           // eslint配置文件
├── .gitignore                          // git忽略
├── .npmrc                              // npm配置文件
├── .prettierignore                     // prettierc忽略
├── .prettierrc                         // prettierc配置文件
├── .stylelintignore                    // stylelint忽略
├── .stylelintrc                        // stylelint配置文件
├── babel.config.js                     // babel配置文件
├── commitlint.config.js                // commit配置文件
├── LICENSE.md                          // LICENSE
├── package.json                        // package
├── postcss.config.js                   // postcss
├── README.md                           // README
├── setupEnzyme.ts                      // Enzyme測試配置文件
├── tsconfig.json                       // typescript配置文件

使用 npx create-react-app xxx --typescript 可以快速創建 TS 項目,我們可以基于創建完的項目再進行一些自定義配置。

ES6+、JSX 、TypeScript 支持

這里我們使用 babel 處理,當然對于 TypeScript 也可以使用 ts-loader 解析,這里就不做演示了,網上也有很多對比測試

JavaScript 語法特性支持

  • 首先安裝 babel 相關依賴: yarn add @babel/preset-env -D
  • 然后在 .babelrc.js 中添加預設
module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        // 這里可以配置相關瀏覽器兼容規則,暫時我們先不管
        // corejs: 3, 
        // debug: true,
        // useBuiltIns: 'usage', // 開啟瀏覽器兼容 polyfills,會根據browserslist配置,引入需要的庫,需要安裝對應版本的 core-js@3
      }
    ]
  ]
}

React的JSX語法支持

  • 安裝依賴:yarn add @babel/preset-react -D
  • 然后在 .babelrc.js 中添加預設
module.exports = {
  presets: ['@babel/preset-env', '@babel/preset-react']
}

TypeScript 支持

  • 安裝依賴:yarn add typescript @babel/preset-typescript -D
  • 然后在 .babelrc.js 中添加預設
module.exports = {
  presets: ['@babel/preset-env', '@babel/preset-react', '@babel/preset-typescript']
}
  • 接下來在 webpack 中配置 loader
module.exports = {
  module: {
    rules: [
      // .ts .tsx
      {
        test: /\.(ts|tsx)$/,
        use: 'babel-loader',
        exclude: /node_modules/,
      },
    ]
  }
}

Antd按需加載、主題定制

antd作為react的好基友,在國內后臺系統開發中幾乎快成為標配了,我們以antd為例配置按需加載和主題定制化

babel配置按需加載

  • 安裝antd:yarn add antd
  • 安裝依賴:yarn add babel-plugin-import -D
  • 然后在 .babelrc.js 中配置plugins
module.exports = {
  presets: [],
  plugins: [
    [
      'import',
      {
        libraryName: 'antd',
        libraryDirectory: 'es',
        style: true, // or 'css'
      },
      'antd',
    ]
  ]
}

webpack/loader配置antd主題

css-loader、style-loader 也是必須的

module.exports = {
  module: {
    rules: [
      // 處理 .css
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      },
      // 處理 .less
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          // less-loader
          {
            loader: 'less-loader',
            options: {
              lessOptions: {
                // 替換antd的變量,去掉 @ 符號即可
                // https://ant.design/docs/react/customize-theme-cn
                modifyVars: {
                  'primary-color': '#1DA57A',
                },
                javascriptEnabled: true, // 支持js
              },
            },
          },
        ],
      },
    ]
  }
}

工程化規范配置

Eslint代碼檢查

  • 安裝ts解析器:yarn add @typescript-eslint/parser -D

  • 安裝相關拓展:yarn add eslint-config-airbnb-typescript eslint-plugin-prettier -D

  • 安裝相關插件:yarn add eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-jsx-a11y @typescript-eslint/eslint-plugin -D

  • 添加 .eslintrc.js

module.exports = {
  parser: '@typescript-eslint/parser',
  // 使用 airbnb 拓展插件規范相關庫
  // prettier 已內置了許多相關插件
  extends: ['airbnb-typescript', 'prettier'],
  // 拓展和支持相關能力的插件庫
  plugins: ['prettier', 'react', 'react-hooks', 'jsx-a11y', '@typescript-eslint'],
}
  • ES6+規范 import/export 導入導出配置:yarn add eslint eslint-plugin-import eslint-import-resolver-typescript eslint-import-resolver-webpack -D
module.exports = {
  parser: '@typescript-eslint/parser',
  // 使用 airbnb 拓展插件規范相關庫
  // prettier 已內置了許多相關插件
  extends: ['airbnb-typescript', 'prettier'],
  // 拓展和支持相關能力的插件庫
  plugins: ['prettier', 'react', 'react-hooks', 'jsx-a11y', '@typescript-eslint'],
  settings: {
    'import/parsers': {
      '@typescript-eslint/parser': ['.ts', '.tsx'],
    },
    'import/resolver': {
      webpack: {
        config: './config/webpack.base.js',
      },
      typescript: {
        alwaysTryTypes: true, // always try to resolve types under `<root>@types` directory even it doesn't contain any source code, like `@types/unist`
        directory: './tsconfig.json',
      },
    },
    'import/ignore': ['types'], // Weirdly eslint cannot resolve exports in types folder (try removing this later)
  }
}

Prettier 代碼格式化

  • Eslint配置中我們已經添加prettier插件,支持以eslint的規范進行格式化,并提供保存時存在沖突時的解決方案
  • 添加 .prettierrc,這里再定義下格式化基本風格

yarn add prettier -D

{
  "printWidth": 100, 
  "tabWidth": 2,
  "useTabs": false,
  "semi": true,
  "singleQuote": true,
  "trailingComma": "all",
  "arrowParens": "avoid",
  "endOfLine": "auto"
}

Stylelint 樣式規范

  • 安裝依賴:yarn add stylelint stylelint-config-recess-order stylelint-config-standard -D
  • 添加.stylelintrc.js
module.exports = {
  extends: ['stylelint-config-standard', 'stylelint-config-recess-order'],
};

針對以上代碼規范檢查,我們也應該添加對應 ignore 文件以忽略非必要的檢查文件,以優化性能

如:.eslintignore

node_modules
dist

Commitlint 代碼提交規范

git hook 鉤子的實現,這里我們使用 husky + lint-staged 方案

  • 安裝依賴:yarn add husky lint-staged -D

git commit 規范,這里我們使用 @commitlint/config-conventional

  • 安裝依賴:yarn add "@commitlint/cli @commitlint/config-conventional -D

這里也可以使用pretty-quick代替prettier格式化:yarn add pretty-quick -D,使得prettier格式化更簡單易用

  • 根目錄下創建 .husky 文件夾與commitlint.config.js文件,并在.husky 文件夾下添加 precommit、commit-msg、以及.gitignore

commitlint.config.js 用于配置 commitlint 相關規范

// git commit 規范
// <類型>[可選的作用域]: <描述>

// # 主要type
// feat:     增加新功能
// fix:      修復bug

// # 特殊type
// docs:     只改動了文檔相關的內容
// style:    不影響代碼含義的改動,例如去掉空格、改變縮進、增刪分號
// build:    構造工具的或者外部依賴的改動,例如webpack,npm
// refactor: 代碼重構時使用
// revert:   執行git revert打印的message

// # 暫不使用type
// test:     添加測試或者修改現有測試
// perf:     提高性能的改動
// ci:       與CI(持續集成服務)有關的改動
// chore:    不修改src或者test的其余修改,例如構建過程或輔助工具的變動

module.exports = {
  extends: ['@commitlint/config-conventional'],
  // rules: [] // 可以自定義規則
};

precommit git提供的鉤子函數,在該階段執行eslint等驗證規范,再根據執行結果判斷是否提交

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

# npx --no-install pretty-quick --staged
npx --no-install lint-staged

commit-msg 驗證 git commit -m "xx" 提交的 message 信息格式和規范

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx --no-install commitlint --edit $1

.gitignore 作用是為了忽略 husky安裝產生的非項目代碼文件

_

package.json配置

"scripts": {
  // 這里換成 postinstall 也可以,npm提供的一個生命周期鉤子
  // 主要是為了我們在安裝完 husky依賴后可以執行husky腳本,使git hook鉤子生效
  "prepare": "husky install", 
  "commitlint": "commitlint --from=master",

  // lint 相關規則和規范執行命令
  "lint:eslint:fix": "eslint --ext .ts,.tsx --no-error-on-unmatched-pattern --quiet --fix",
  "lint:style": "stylelint --fix \"src/**/*.less\" --syntax less",
  "lint": "npm run lint:eslint:fix && npm run lint:style",

  // prettier 格式化的一個拓展庫
  "pretty-quick": "pretty-quick",
},
"lint-staged": {
  "*.{ts,tsx}": [
    "npm run lint:eslint:fix",
    "git add --force"
  ],
  "*.{md,json}": [
    "pretty-quick --staged",
    "git add --force"
  ]
}

vscode 配置

  • 安裝 eslint、prettier 拓展插件
  • 添加 .vscode/settings.json 配置文件,或者全局設置 vscode settings.json
// 保存時格式化
"editor.formatOnSave": true, 
// 相當于是 vscode 保存時調用的鉤子事件
"editor.codeActionsOnSave": {
  // 保存時使用 ESLint 修復可修復錯誤
  "source.fixAll.eslint": true
}
// 針對對應文件設置默認格式化插件
"[javascript]": {
  "editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascriptreact]": {
  "editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
  "editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
  "editor.defaultFormatter": "esbenp.prettier-vscode"
},

HMR 熱更新配置

這里我們使用 react-refresh+webpack 方案

  • 安裝依賴:yarn add react-refresh @pmmmwh/react-refresh-webpack-plugin -D
  • 添加webpack配置
const { HotModuleReplacementPlugin } = require('webpack');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');

module.exports = {
  devServer: {
    port: 3010, // 端口
    publicPath: '/', // 基礎路徑
    open: true, // 打開頁面
    hot: true, // 開啟熱更新
    historyApiFallback: true, // 把404響應定位到 index.html
    // proxy:{} // 開發環境,接口代理
  },
  plugins: [new HotModuleReplacementPlugin(), new ReactRefreshWebpackPlugin()]
}

生產環境打包壓縮、chunk拆分

  • 安裝css壓縮插件:yarn add mini-css-extract-plugin css-minimizer-webpack-plugin -D
  • 安裝js壓縮插件:yarn add terser-webpack-plugin -D
  • 安裝gzip壓縮插件:yarn add compression-webpack-plugin -D
  • 如果想查看對包模塊的可視化分析可使用插件:webpack-bundle-analyzer

css壓縮的webpack配置:

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
// 支持動態注入 link 標簽到 html中
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  module: {
    rules: [
      // .css
      {
        test: /\.css$/,
        use: [
          // 該插件是為了把 CSS提取到單獨的文件中
          MiniCssExtractPlugin.loader, 
          'css-loader'
        ],
      },
      // less
      {
        test: /\.less$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'less-loader'
        ],
      },
    ]
  },
  plugins: [
    // 簡化 HTML 文件的創建
    new HtmlWebpackPlugin({
      template: 'public/index.html',
    }),

    // MiniCss
    new MiniCssExtractPlugin({
      filename: "[name].css",
      chunkFilename: "[id].css",
    }),
  ],

  optimization: {
    minimizer: [
      // 壓縮
      new CssMinimizerPlugin(),
    ]
  }
}

js壓縮的webpack配置:

webpack5.x內置有terser-webpack-plugin,不過如果想要自定義配置還是需要安裝的

// 使用 terser 壓縮 JavaScript
const TerserPlugin = require("terser-webpack-plugin");

module.exports = {
  optimization: {
    minimize: true, // 開啟壓縮
    minimizer: [
      // 1. 簡單使用默認配置
      new TerserPlugin() // 使用插件
      // 2. 自定義配置一些參數
      new TerserPlugin({
        terserOptions: {
          output: {
            comments: false, // 在輸出中省略注釋
          },
          // ie8: true 開啟 ie8 支持
        },
      }),
    ],
  },
}

chunk拆分

這里的可玩性還是比較高的,各種性能優化啥的,有興趣的朋友可以研究研究,我們這里只做簡單使用配置??~

module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all', // 處理哪種chunk,可選值為:all、async、initial(all包括異步和非異步)
      maxInitialRequests: 10, // 入口點的最大并行請求數。
      minSize: 0, // 生成 chunk 的最小體積(以 bytes 為單位)
      // 緩存組,該組內配置可繼承、覆蓋splitChunks中的配置
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/, // [\\/] 是為了分別匹配 win、Unix系統路徑
          // 拆分 vendor,自定義name(vendor默認是合并為一個 chunk)
          name(module) {
            // 把 npm 庫拆分獨立打包
            const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
            return `npm.${packageName.replace('@', '')}`;
          },
        },
      },
    }
  },
}

Gzip壓縮

const CompressionPlugin = require('compression-webpack-plugin');

module.exports = {
  plugins: [
    new CompressionPlugin({
      algorithm: 'gzip', // 壓縮算法
      test: /\.js$|\.css$|\.html$/,
      threshold: 10240, // 只壓縮大于 10240 bytes 的chunk
      minRatio: 0.8, // 只壓縮大于該值的 minRatio = Compressed Size / Original Size
    })
  ]
}

【圖 1】chunk拆分、gzip壓縮后的效果

壓縮產物

【圖 2】Analyzer可視化分析

Analyzer分析

總結

本文著重描述了項目的工程化配置,涉及相關代碼規范、開發環境搭建、生產環境優化等,旨在打造出一個可快速使用的現代化webpack+react+typescript模板,以供在以后的實際業務場景需求中零成本使用。

目前這只算是最簡陋的一個demo,對webpack相關的各種調優與項目優化還有很多方向可研究。

接下來就是搞實際場景的業務組件的開發、第三方開源組件的集成使用、通用組件的使用和開發封裝了~

項目地址:https://github.com/JS-banana/webpack-react-ts

告辭

參考

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容