webpack4升级webpack5

2,743 阅读4分钟

借着公司项目,将webpack4升级到webpack5,下面是一些主要配置方式

webpack5新特性介绍

  1. 启动命令
  2. 持久化缓存
  3. 资源模块
  4. moduleIds & chunkIds的优化
  5. 更智能的tree shaking
  6. nodeJs的polyfill脚本被移除
  7. 模块联邦
npm i react-dev-utils webpackbar friendly-errors-webpack-plugin -D

npm i webpack webpack-cli webpack-dev-server webpack-merge -D

升级步骤

1、自定义开发环境

对于开发环境,我们更加灵活的自定义配置的方式

const webpack = require("webpack");
const WebpackDevServer = require('webpack-dev-server');

const compiler = webpack(config)
const devServer = new WebpackDevServer(compiler, devConfig)
devServer.listen(Config.port, host, err => {
  if (err) {
    return console.log(err);
  }
  console.log(chalk.cyan('Starting the development server...\n'));
});

2、端口号(可能被占用)

随着项目越来越多,端口号可能会出现重复,所以启动项目时发现端口号已经被占用,需要找到合适的可用端口进行启动项目

const portfinder = require('portfinder');

portfinder.getPortPromise()
    .catch((err) => {
        console.log('webpack启动错误', err)
    })
    .then((port) => {
  		// 没有被占用的端口号
  		console.log(port)
		})

3、ip链接

需求:由于移动端或者pc端,经常会拿ip链接进行手机的调试,或者将ip链接发送给对方进行联调,这时如果开发工具者控制台有这样的ip链接就很方便

const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');

new MyFriendlyErrorsWebpackPlugin({
  compilationSuccessInfo: {
    messages: [
      'App running at:',
      `- Local:   ${chalk.cyan(newWorkUrl(host, port, Config.prefix))}`,
      `- Network: ${chalk.cyan(newWorkUrl(getNetworkIp(), port, Config.prefix))}`,
    ],
    notes: [
      'Note that the development build is not optimized.',
      `To create a production build, run ${chalk.cyan('npm run build')}`,
    ]
  },
}),
const os = require('os')

function getNetworkIp() {
    let needHost = ''; // 打开的host
    try {
        // 获得网络接口列表
        let network = os.networkInterfaces();
        for (let dev in network) {
            let iface = network[dev];
            for (let i = 0; i < iface.length; i++) {
                let alias = iface[i];
                if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
                    needHost = alias.address;
                }
            }
        }
    } catch (e) {
        needHost = 'localhost';
    }
    return needHost;
}

function prettyPrintHost(host) {
    const isUnspecifiedHost = host === '0.0.0.0' || host === '::';
    if (isUnspecifiedHost) {
        return 'localhost';
    }
    return host
}

function newWorkUrl(host, port, prefix) {
    return `http://${prettyPrintHost(host)}:${port}/${prefix ? prefix : ''}`
}

问题:

antv和webpack5之间有一些警告问题,一旦有了警告,那么friendly-errors-webpack-plugin就不会将我们的ip链接暴露出来,所以本地二次封装friendly-errors-webpack-plugin插件,达到目的

4、添加缓存

cache: {
  type: 'filesystem',  //'memory' | 'filesystem'
  cacheDirectory: path.resolve(__dirname, '../node_modules/.cache/webpack'),
},

4.1、去除dll动态链接库

create-react-app以及vue-cli在webpack4.x的时候就已经移除dll,原因:就是webpack4.x的性能足够好,使用dll后收益非常小,而且dll还需要进行额外的繁琐配置

结论:我们也去除dll,配置中将所有关于dll的全部删除掉

5、关于图片和图标

去除file-loader和url-loader

{ // 图标的转化
  test: /\.(woff|woff2|eot|ttf|otf|svg)$/i,
    type: 'asset/resource'
},
{ // 图片的转化
    test: /\.(jpe?g|png|gif|bmp)$/i,
    type: 'asset', 
        parser: {
          dataUrlCondition: {
            maxSize: 8192,// 8kb
          }
        }
},

6、css的路径问题

因为css和images是单独打包成一个独立的文件夹,那么css中寻找图片路径是从css目录开始找的,所以需要配置下

isDevelopment ? {
  loader: "style-loader",
  options: { esModule: true },
} : {
  loader: MiniCssExtractPlugin.loader,
  options: { esModule: true, publicPath: '../' }, // 在原来配置的基础上添加publicPath属性
},

7、启动

 "scripts": {
        "dev": "node ./scripts/webpack.dev",
        "build:hr": "webpack --config ./scripts/webpack.prod",
        "start": "cross-env NODE_ENV=development npm run dev",
        "build": "cross-env NODE_ENV=production npm run build:hr"
    },

开发:npm run start

打包:npm run local/test/pre/build

8、css压缩插件

optimize-css-assets-webpack-plugin 在webpack5中不建议使用了

说明:如果使用webpack5版本,需要使用css-minimizer-webpack-plugin插件进行替换

细节问题

1、webpack5和cnpm有兼容性

因为webpack5里面的解析包是按照npm标准的@babel这样的格式,如果违反规则直接失败,而cnpm是_@babel多了一个下划线

结论:避免使用cnpm,使用npm和yarn的方式

2、webpack.NamedChunksPlugin被废弃

optimization: {
    moduleIds: 'deterministic', // 模块名称的生成规则 -> 根据模块名称生成简短的hash值
    chunkIds: 'deterministic', // 代码块名称的生成规则
}

3、watermark-dom

# webpack4引用
import watermark from 'watermark-dom'
watermark.loading({})
# webapack5
改成
import 'watermark-dom'
watermark.loading({})

原因:webpack4和webpack5对非【commonjs和esmodule】打包方式不一致,webpack5是直接将其注入到window属性中

4、mac启动项目默认打开一个tab

举例:如果本地已经启动了 http://localhost:8080/web/ 的项目,并且在浏览器中打开了(不关闭),如果我们将8080端口的项目关掉,在重新启动项目,则会在浏览器中找到刚才运行的项目页面开始编译,不会重新在浏览器中重新打开一个新的页面

const openBrowser = require('react-dev-utils/openBrowser');

devServer.listen(Config.port, host, err => {
  if (err) {
    return console.log(err);
  }
  console.log(chalk.cyan('Starting the development server...\n'));
+  openBrowser(`http://localhost:${port}/${Config.prefix}`)

});

5、清空控制台信息

原因:开发中,启动项目时,我们并不需要控制台这么多信息,本着简洁的原则需要:编译时间、以及项目链接

开发

new WebpackDevServer(compiler, {
   overlay: false,
   quiet: true,
})

生产

   stats: {
            all: false,
            errors: true,
            moduleTrace: true,
            logging: 'error',
            assets: true,
        },

6 移除clean-webpack-plugin

  • 5.20版本以后output新增特性clean,用于清除dist文件
{
  output: {
    clean: true, // Clean the output directory before emit.
  }
}

移除插件

  • add-asset-html-webpack-plugin 不再需要
  • open-browser-webpack-plugin 新插件替换
  • url-loader、file-loader 对于图片/图标webpack5有新的写法
  • hard-source-webpack-plugin 不再需要,有新的缓存方式

添加插件

  • react-dev-utils 辅助工具

  • friendly-errors-webpack-plugin 启动提示

  • webpackbar 启动进度条/编译时间

升级前后编译对比

webpack版本首次编译(s)二次启动(s)修改文件编译(s)打包时间(s)打包体积备注
4.41.025s左右25s左右1s左右40左右2730kb
5.43.025s左右3s左右1s左右40左右2669kb