我正在参加「掘金·启航计划」
前言
由于我司的工程久远且代码量庞大, 平时开发编译和生产编译都很慢,差不多需要20-30分钟,之前看到说webpack5的编译方式优化,可以加快编译速度,就想试着开始升级一下。我们原来用的是webpack3.5.1的版本,不用管什么的直接升级到最新的,本次我升级的是webpack5.74.0。
具体思路
一、基于webpack5.x搭建react工程
1、先把node版本升级到14.x ,因为经测试好像有些依赖低于14的装不上,这里就不说怎么安装了,大家自行百度可以的^_^。
2、找个干净的目录,依次执行一下命令
-
(1)初始化目录,生成一个package.json文件
npm init -y
-
(2)安装webpack相关的包
npm install -D webpack webpack-cli
-
(3)安装html-webpack-plugin插件
npm install -D html-webpack-plugin
-
(4)安装react和babel插件
npm install react react-dom
npm install @babel/core
npm install -D @babel/preset-env @babel/preset-react babel-loader
-
(5)安装css-loader、sass、sass-loader、style-loader插件
npm install -D css-loader sass sass-loader style-loader
-
(6)在根目录新建一个文件
webpack.config.js
,内容如下:
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require("copy-webpack-plugin");
const config = require('./config.js');
let pages = config.pages;
const VERSION = Date.now();
let hbsHtmlWebpackPlugins = [
new HtmlWebpackPlugin({
template: __dirname + '/template.html',
filename: './page/' + pages[i].name + '.html',
title: pages[i].title,
inject: 'body',
chunks: [pages[i].name]
})
];
module.exports = {
// 打包模式: 'production' or development'
mode: 'development',
entry: {
index: './index.js',
},
// output为项目打包后的输出位置
output: {
path: __dirname + '/dist',
filename: 'busi/[name]-' + VERSION + '.js',
publicPath: '../'
},
plugins: hbsHtmlWebpackPlugins.concat([
new MiniCssExtractPlugin({ filename: 'css/[name]-' + VERSION + '.css', ignoreOrder: true }),
new CopyWebpackPlugin(
{
patterns: [
{
from: __dirname + '/lib',
to: __dirname + '/dist/lib'
}
]
}
)
]),
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react']
}
}
},
{
test: /\.(css|scss)$/i,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"]
},
{
test: /\.(png|jpe?g|gif)$/i,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 8 * 1024
}
},
generator: {
filename: "images/[name].[ext]"
}
},
{
test: /\.(svg|eot|ttf|woff|woff2)$/,
type: "asset",
generator: {
filename: "fonts/[name].[ext]"
}
},
{
test: /\.js$/,
exclude: /node_modules/,
use: 'eslint-loader',
enforce: 'pre'
}
]
}
};
-
(7)在根目录新建一个文件
index.js
,内容如下:
import React from 'react';
import ReactDOM from 'react-dom';
const App = () => {
return (
<div>
<span>我是文字</span>
</div>
)
}
ReactDOM.render(<App />, document.getElementById('root'));
-
(8)在根目录新建一个文件
template.html
,内容如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<div id="root" ></div>
</body>
</html>
-
(9)在package.json里面增加一下代码,然后运行
npm run build
,就可以完成简单的编译了。
"scripts":{
"build": "webpack --config ./scripts/webpack.config.js"
},
二、把原来的工程代码迁移进来,注意修改webpack.config.js里面的output和entry成自己工程的。
- 把原工程package.json里面的依赖包放到新的里面,然后看哪个是重复的,取最新的。
- 然后把旧的依赖包版本去掉,重新install一下,安装最新的。
- 然后根据对应的报错,查找对应的问题,一种错误是版本不对应,安装对应版本即可;另一种是接口过时,跟进文档使用最新的方法即可。
三、我遇到的问题及解决方式
1、# Invalid options object. Copy Plugin has been initialized using an options object that does not match
:
这是copy-webpack-plugin插件报的,原因是新版本的入参已经修改了,原来是
new CopyWebpackPlugin([{
from: __dirname + '/lib',
to: __dirname + '/dist/lib'
})
现在需要改成这样:
new CopyWebpackPlugin(
{
patterns: [
{
from: __dirname + '/lib',
to: __dirname + '/dist/lib'
}
]
}
)
2、# Uncaught Error: ES Modules may not assign module.exports or exports.
:同时使用了module.exports 和export default ,需要使用插件。安装babel-plugin-add-module-exports
和babel-plugin-dynamic-import-webpack
插件,然后再loader里面使用
// ...
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'],
plugins: ["add-module-exports", "dynamic-import-webpack"]
}
}
},
// ...
3、IE兼容问题,在IE打不开,报: SCRIPT1002: 语法错误
解决方法:安装babel-polyfill
插件,然后在主入口引入即可,如果不行,可以删除node_module然后再重新安装一下。
import "babel-polyfill";
4、最新的eslint-loader 和最新的eslint并不匹配,编译时会报错:Cannot read property 'getFormatter' of undefined
,看了代码,最新的eslint并没有把cliEngine
方法暴露出去,所以拿不到getFormatter
解决方法:安装低于8.x版本的eslint,例如:7.32.0
5、打包出来后出现两份图片和字体的问题,因为webpack5自带了静态资源的处理,所以不用额外使用url-loader或者file-loader。
应该按照以下配置即可:
// ...
{
test: /\.(png|jpe?g|gif)$/i,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 8 * 1024
}
},
generator: {
filename: "images/[name].[ext]"
}
},
{
test: /\.(svg|eot|ttf|woff|woff2)$/,
type: "asset",
generator: {
filename: "fonts/[name].[ext]"
}
},
// ...
设置type: "asset"
即为按照静态资源处理,其他参数可参考对应文档。
6、另外还有一个插件不兼容webpack5的,一般都有提示或者报错,按照报错搜一下就有替代的方案。例如extract-text-webpack-plugin
可以换成mini-css-extract-plugin
、 uglifyjs-webpack-plugin
可以换成terser-webpack-plugin
,不过据我测试terser-webpack-plugin
用了好像也没有进行压缩。可以直接改config 的mode为“development
”就会进行压缩打包。
结语
升级之后,编译时间只需7分钟,减少了2/3的时间。由于开始迁移的时候,没有过多的记录报错及解决方法,有一些报错还是没有收集到,因为每个工程的代码、环境都不太一样,因此仅供参考。