1. 程式人生 > 程式設計 >從零搭建Webpack5-react腳手架的實現步驟(附原始碼)

從零搭建Webpack5-react腳手架的實現步驟(附原始碼)

目錄
  • webpack5
  • 正式開始
  • 搭建指南
    • 開始搭建
    • 完成了依賴的準備工作,開始搭建專案
    • 編寫webpack.dev.開發配置
    • 開始編寫webpack.prod.js生產配置
    • 編寫scripts命令
    • 配置程式碼質量管控流程
    • 單元測試

webpack5

近期終於有時間和精力專注於公司技術基礎建設了,於是一開始,將公司的Saas系統改造成了微前端模式,解決了歷史遺留的一部分問題

接著,想著webpack5已經發布這麼久了,該在生產環境用起來了,也順勢想推動微前端、webpack5、vite在業內的普及率,沒看過我之前文章的朋友可以在文末找找,乾貨真的很多

正式開始

webpack5升級後,有哪些改變?

  • 通過持久化快取提高效能
  • 採用更好的持久化快取演算法和預設行為
  • 通過優化 Tree Shaking 和程式碼生成來減小Bundle體積(幹掉了nodejs的polyfill)
  • 提高 Web 平臺的相容性
  • 清除之前為了實現 Webpack4 沒有不相容性變更導致的不合理 state
  • 嘗試現在引入重大更改來為將來的功能做準備,以使我們能夠儘可能長時間地使用 Webpack 5
  • 新增Module Federation(聯邦模組)

搭建指南

推薦大家使用我在我們公司(深圳明源雲空間)做的腳手架,給大家一鍵生成專案模板,這樣大家在看本文的時候會得到更好的提升

生成模板步驟:

npm  i ykj-cli -g 
ykj init webpack5 (這裡選擇通用專案模板)
cd webpack5
yarn 
yarn dev

開始搭建

首先新建資料夾,使用yarn初始化專案

mkdir webpack5-demo
cd webpack5-demo
yarn init webpack5-demo
...一路回車

下載webpack webpack-cli最新版本:

yarn add webpack@next webpack-cli@next -D

然後安裝React react-dom17版本的庫

yarn add [email protected] [email protected] --save 

接著安裝react官方熱更新推薦的庫

yarn add react-refresh -D

安裝less style標籤 postcss等樣式處理的庫(mini-css-extract-plugin要安裝@next版本的)

yarn add less less-loader css-loader style-loader mini-css-extract-plugin@next -D

安裝相關babel依賴

yarn add [email protected] @babel/core@next  babel-loader@next @babel/preset-env@next -D

babel具體要哪些配置,建議大家參考我的模板裡面

完成了依賴的準備工作,開始搭建專案

專案根目錄建立config資料夾,用於放置webpack配置檔案
config資料夾下新建四個檔案

paths.js//存放路徑
webpack.base.js //基礎配置
webpack.dev.js//開發配置
webpack.prod.js//生產配置

在paths檔案內,用變數記錄幾個關鍵目錄:

const path = require('path');

module.exports = {
    // 原始碼目錄
    src: path.resolve(__dirname,'../src'),// 構建後的資源產物資料夾
    build: path.resolve(__dirname,'../dist'),// 靜態資源
    public: path.resolve(__dirname,'../public'),};

編寫基礎webpack.base.js配置檔案,引入依賴

//webpack.base.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const paths = require('./paths');

編寫entry和output欄位:

 entry: paths.src + 'index.tsx',output: {
        path: path.resolve(__dirname,filename: '[name].[contenthash].js',publicPath: '',},

這裡要注意的是,webpack5對contenthash演算法進行了優化,這裡可以在chunkhash和contenthash中http://www.cppcns.com選擇一個,建議contenthash

編寫基礎loader配置:

    module: {
        rules: [
            {
                use: 'babel-loader',test: /\.(ts|tsx)$/,exclude: /node_modules/,{
                use: ['style-loader','css-loader','less-loader'],test: /\.(css|less)$/,{
                type: 'asset',test: /\.(png|svg|jpg|jpeg|gif)$/i,],

這裡要注意的是:webpack5對於資源,類似:圖片、字型檔案等,可以用內建的asset去處理,不用url-loader和file-loader了

接著,由於專案需要配置別名和省略字尾名,我們先配置resolve欄位(我是TypeScript+React技術棧):

 resolve: {
        extensions: ['.ts','.tsx','.js','.json','.jsx'],alias: {
            '@': paths.src,'@c': paths.src + '/components','@m': paths.src + '/model','@s': paths.src + '/services','@t': paths.src + '/thttp://www.cppcns.comypes',

外掛的話,由於是基礎配置,只要一個clean、html的外掛即可

  plugins: [
        new CleanWebpackPlugin(),new HtmlWebpackPlugin({
            template: './public/index.html',}),

在專案根目錄新建檔案babel.config.js

const { argv } = require('yargs');
const isDev = argv.mode === 'development';
const plugins = [
    [
        'const-enum',{
            transform: 'constObject','lodash','@babel/plugin-transform-runtime',//支援import 懶載入
    '@babel/plugin-syntax-dynamic-import','@babel/plugin-transform-async-to-generator','transform-class-properties',[
        'import',{
            libraryName: 'antd',libraryDirectory: 'es',style: true,// or 'css'
        },'antd',{
            libraryName: 'ykj-ui',libraryDirectory: 'lib/components','ykj-ui',];
module.exports = (api) => {
    api.cache(true);
   www.cppcns.com return {
        presets: [
            [
                '@babel/preset-env',{
                    corejs: 3.9,useBuiltIns: 'usage',[
                '@babel/preset-react',{
                    runtime: 'automatic','@babel/preset-typescript',plugins: isDev ? [...plugins,'react-refresh/babel'] : [...plugins],};
};

這樣,我們的基礎webpack配置就好了,捋一捋先:

  • 用babel處理tsx ts 和es高階語法
  • 用loader處理less語法
  • 用外掛處理了html和負責清理工作
  • 用resolve欄位配置了別名和省略檔案字尾
  • 用內建的asset處理了靜態檔案,例如圖片等

編寫webpack.dev.js開發配置

引入依賴

const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const { HotModuleReplacementPlugin } = require('webpack');
const { merge } = require('webpack-merge');
const common = require('./webpack.base');

先引入了熱更新、合併配置、基礎配置、官方react熱更新依賴
接著編寫配置

const devConfig = {
    mode: 'development',devServer: {
        port: 3000,contentBase: '../dist',open: true,hot: true,target: 'web',plugins: [new HotModuleReplacementPlugin(),new ReactRefreshWebpackPlugin()],devtool: 'eval-cheap-module-source-map',};

module.exports = merge(common,devConfig);

注意:這裡要設定 target: 'web'才會有熱更新效果

devtool在開發模式最佳實踐是:eval-cheap-module-source-map

這樣,我們的開發模式配置就搭建好了,只要在public資料夾下編寫一個index.html,就可以跟之前一樣,開始寫react專案了

開始編寫webpack.prod.js生產配置

引入依賴:

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { merge } = require('webpack-merge');
const common = require('./webpack.base');

生產環境要抽離css標籤,所以這裡針對less和css要做特殊處理,一個是postcss處理樣式相容性問題,一個是MiniCssExtractPlugin.loader:

const prodConfig = {
    mode: 'production',devtool: 'hidden-source-map',module: {
        rules: [
            {
                test: /\.(css|less)$/,use: [MiniCssExtractPlugin.loader,'postcss-loader',optimization: {
        splitChunks: {
            chunks: 'all',name: false,plugins: [new MiniCssExtractPlugin()],};
module.exports = merge(common,prodConfig);

這樣生產的配置也編寫好了

生產環境devtool最佳實踐是: hidden-source-map

編寫scripts命令

"build": "webpack --config config/webpack.prod.js  --mode production","dev": "webpack serve --config config/webpack.dev.js  --mode development",

注意:熱更新以前是webpack-dev-server,現在是webpack serve!!!

配置程式碼質量管控流程

新增依賴

yarn add lint-staged @commitlint/cli @commitlint/config-conventional -D

編寫程式碼、提交檢測流程

 "husky": {
        "hooks": {
            "pre-commit": "lint-staged","commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
        }
    },"lint-staged": {
        "src/**/*.{js,jsx,ts,tsx,json,css,less,md}": [
            "prettier --write","eslint --fix","git add"
        ]
    },"browserslist": [
        "ie >= 10","ff >= 30","chrome >= 34","safari >= 8","opera >= 23"
    ]
}

新增eslint配置:

//.eslintrc.js
module.exports = {
    root: true,parserOptions: {
        ecmaVersion: 7,sourceType: 'module',parser: '@typescript-eslint/parser',plugins: ['typescript','react'],env: {
        browser: true,node: true,es6: true,rules: {
        semi: ['error','always'],// 該規則強制使用一致的分號
        'no-unused-vars': 'off',// 禁止未使用過的變數
        'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',//生產環境禁用 debugger
        'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',//生產環境禁用 console
        'default-case': ['warn',{ commentPattern: '^no default$' }],//要求 Switch 語句中有 Default
        'dot-location': ['warn','property'],// 強制在點號之前或之後換行
        eqeqeq: ['error','allow-null'],//要求使用 === 和 !==
        'new-parens': 'warn',//要求呼叫無參建構函式時帶括號
        'no-caller': 'error',// 禁用 caller 或 callee
        'no-const-assign': 'error',//不允許改變用 const 宣告的變數
        'no-dupe-args': 'error',//禁止在 function 定義中出現重複的引數
        'no-dupe-class-members': 'error',//不允許類成員中有重複的名稱
        'no-dupe-keys': 'warn',//禁止在物件字面量中出現重複的鍵
        'no-extend-native': 'warn',//禁止擴充套件原生物件
        'no-extra-bind': 'warn',//禁止不必要的函式繫結
        'no-fallthrough': 'error',//禁止 case 語句落空
        'no-func-assign': 'warn',//禁止對 function 宣告重新賦值
        'no-implied-eval': 'error',//禁用隱式的 eval()
        'no-label-var': 'error',//禁用與變數同名的標籤
        'no-loop-func': 'error',//禁止迴圈中存在函式
        'no-mixed-operators': [
            'warn',{
                groups: [
                    ['&','|','^','~','<<','>>','>>>'],['==','!=','===','!==','>','>=','<','<='],['&&','||'],['in','instanceof'],allowSamePrecedence: false,//禁止混合使用不同的操作符
        'no-multi-str': 'warn',//禁止多行字串 (需要多行時用\n)
        'no-native-reassign': 'warn',//禁止重新分配本地物件
        'no-obj-calls': 'warn',//禁止將全域性物件當作函式進行呼叫
        'no-redeclare': 'error',//禁止重新宣告變數
        'no-script-url': 'warn',//禁用 Script URL
        'no-shadow-restricted-names': 'warn',//關鍵字不能被遮蔽
        'no-sparse-arrays': 'warn',//禁用稀疏陣列
        'no-this-before-super': 'warn',//在建構函式中禁止在呼叫 super()之前使用 this 或 super
        'nohttp://www.cppcns.com-undef': 'error',//禁用未宣告的變數
        'no-unexpected-multiline': 'warn',//禁止使用令人困惑的多行表示式
        'no-use-before-define': [
            'warn',{
                functions: false,classes: false,variables: false,//禁止定義前使用
        'no-with': 'error',//禁用 with 語句
        radix: 'error',//禁用函式內沒有 yield 的 generator 函式
        'rest-spread-spacing': ['warn','never'],//強制限制擴充套件運算子及其表示式之間的空格
        'react/jsx-no-undef': 'error',//在 JSX 中禁止未宣告的變數
        'react/no-direct-mutation-state': 'error',//禁止 this.state 的直接變化
        'react/jsx-uses-react': 'warn',//防止 React 被錯誤地標記為未使用
        'no-alert': 0,//禁止使用alert confirm prompt
        'no-duplicate-case': 2,//switch中的case標籤不能重複
        'no-eq-null': 2,//禁止對null使用==或!=運算子
        'no-inner-declarations': [2,'functions'],//禁止在塊語句中使用宣告(變數或函式)
        'no-iterator': 2,//禁止使用__iterator__ 屬性
        'no-negated-in-lhs': 2,//in 操作符的左邊不能有!
        'no-octal-escape': 2,//禁止使用八進位制轉義序列
        'no-plusplus': 0,//禁止使用++,--
        'no-self-compare': 2,//不能比較自身
        'no-undef-init': 2,//變數初始化時不能直接給它賦值為undefined
        'no-unused-expressions': 2,//禁止無用的表示式
        'no-useless-call': 2,//禁止不必要的call和apply
        'init-declarations': 0,//宣告時必須賦初值
        'prefer-const': 0,//首選const
        'use-isnan': 2,//禁止比較時使用NaN,只能用isNaN()
        'vars-on-top': 2,//var必須放在作用域頂部
    },};

單元測試

新增命令:

"test": "jest",//進行測試
"test-c": "jest --coverage" //生成測試報告

安裝jest等依賴:

yarn add jest-environment-enzyme ts-jest@next enzyme enzyme-adapter-react-17 enzyme-to-json  @types/enzyme @types/enzyme-adapter-react-17 @types/enzyme-to-json -D 

新建資料夾 test

編寫第一個單元測試,引入依賴:

import App from '../src/App';
import { mount,shallow } from 'enzyme';
import React from 'react';
import toJson from 'enzyme-to-json'; //做快照

然後就可以愉快的開始寫單元測試了哦

這樣,一個webpack5的腳手架就搭建好了,webpack內建的一些東西,可以讓我們省去很多配置,看起來會更簡單

到此這篇關於從零搭建Webpack5-react腳手架的實現步驟(附原始碼)的文章就介紹到這了,更多相關Webpack5-react搭建腳手架內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!