webpack5

近期终于有工夫和精力专一于公司技术根底建设了,于是一开始,将公司的Saas零碎革新成了微前端模式,解决了历史遗留的一部分问题

接着,想着webpack5曾经公布这么久了,该在生产环境用起来了,也趁势想推动微前端webpack5vite在业内的普及率,没看过我之前文章的敌人能够在文末找找,干货真的很多

正式开始

webpack5降级后,有哪些扭转?

  • 通过长久化缓存进步性能
  • 采纳更好的长久化缓存算法和默认行为
  • 通过优化 Tree Shaking 和代码生成来减小Bundle体积(干掉了nodejs的polyfill)
  • 进步 Web 平台的兼容性
  • 革除之前为了实现 Webpack4 没有不兼容性变更导致的不合理 state
  • 尝试当初引入重大更改来为未来的性能做筹备,以使咱们可能尽可能长时间地应用 Webpack 5
  • 新增Module Federation(联邦模块)

    搭建指南

    举荐大家应用我在咱们公司(深圳明源云空间)做的脚手架,给大家一键生成我的项目模板,这样大家在看本文的时候会失去更好的晋升

生成模板步骤:

npm  i ykj-cli -g ykj init webpack5 (这里抉择通用我的项目模板)cd webpack5yarn yarn dev

开始搭建

  • 首先新建文件夹,应用yarn初始化我的项目

    mkdir webpack5-democd webpack5-demoyarn init webpack5-demo...一路回车
  • 下载webpack webpack-cli最新版本:

    yarn add webpack@next webpack-cli@next -D
  • 而后装置React react-dom17版本的库

    yarn add react@17.0.0 react-dom@17.0.0 --save 
  • 接着装置react官网热更新举荐的库
yarn add react-refresh -D
  • 装置less css 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 core-js@3.9.0 @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.jsconst { CleanWebpackPlugin } = require('clean-webpack-plugin');const HtmlWebpackPlugin = require('html-webpack-plugin');const path = require('path');const paths = require('./paths');
  • 编写entryoutput字段:

     entry: paths.src + 'index.tsx', output: {      path: path.resolve(__dirname, '../dist'),      filename: '[name].[contenthash].js',      publicPath: '',  },
    这里要留神的是,webpack5contenthash算法进行了优化,这里能够在chunkhashcontenthash中抉择一个,倡议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-loaderfile-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 + '/types',      },  },
  • 插件的话,因为是根底配置,只有一个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',  ],  [      'import',      {          libraryName: 'ykj-ui',          libraryDirectory: 'lib/components',          style: true, // or 'css'      },      'ykj-ui',  ],];module.exports = (api) => {  api.cache(true);  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 tses高阶语法
  • 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, 'css-loader', 'postcss-loader', 'less-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.jsmodule.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      'no-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内置的一些货色,能够让咱们省去很多配置,看起来会更简略

看完两件事

如果你感觉这篇内容对你挺有启发,我想邀请你帮我几件小事

1.点个「在看、赞、关注」,让更多人也能看到这篇内容(点了「在看」,bug -1 )
2.关注微信公众号「前端巅峰」,让我继续为你推送精选好文
我是Peter谭,一位小厂前端开发工程师,喜爱搞架构,对性能优化,跨平台开发有肯定钻研,还喜爱做自媒体,区块链。欢送关注我