上一次将webpack1升级到3,也仅是 半年前,前端工具发展变化太快了,如今webpack4已经灰常稳定,传说性能提升非常高,值得升级。

一直用着的webpack3越来越慢,一分多钟的编译时间简直不能忍,升级之后在几个系统和几台电脑上评测,平均提高了7-9倍,生产模式的最突出

升级之后完整的 webpack4项目配置DEMO 已经放到Github中,欢迎围观 star ~

关于如何升级到V4已经有很多优秀的文章,结合官方文档你也可以升级起来

本文仅说说本次升级主要做的改动优化点,或者坑

webpack4升级完全指南    webpack4 changelog   React 16 加载优化性能

1. 移除了commonchunk插件,改用了optimization属性进行更加灵活的配置 ,不过稍微不注意,就会有问题,如

Uncaught Error: only one instance of babel-polyfill is allowed

如果一个页面存在多个entry入口文件,即页面引用了多个模块时,默认会产生多个独立的common区

所以记得将common设为公有,如

optimization: {
runtimeChunk: {
name: 'common'
},

2. 默认的生产模式noEmitOnError为true,导致代码检查工具报错之后无法将检查结果写入文件中

按需将其设置为false即可

optimization: {
noEmitOnErrors: false,

3. 默认的提取公共模块机制可能会产生意外的结果,尽量取消默认后再自定义

在多页面应用中,假设某个页面的css文件重写了样式,就有可能使这个重写流入到公共样式中,在另一个页面被引用而导致布局出错。这时样式是不需要提取出来的,除非特殊情况

比如可以将default设置为false,或者表现得更强烈一点

optimization: {
splitChunks: {
chunks(chunk) {
// 不需要提取公共代码的模块
return !(configs.commonChunkExcludes || []).includes(chunk.name);
},
name: 'common',
minChunks: 2,
cacheGroups: {
default: false,
styles: {
name: 'common',
test: /\.scss|css$/,
chunks: 'initial',
// 不生成公共样式文件
minChunks: 999999,
enforce: true
}
}
}

4. 将css文件提取的 ExtractTextWebpackPlugin 插件 替换成 mini-css-extract-plugin

升级指南里说着这个新插件不兼容web-dev-server,不过目前还没遇到,碰到的几个坑开始以为是它提取出的问题,后来发现并不是..

5. 正确地使用 optimization.concatenateModules ,需要关闭babel的module模块转换

6. 看起来似乎 loader 的 exclude 和 include 配置失效了,不知道是为何

7. 加入编译结果消息弹出提示,更友好,引入 webpack-build-notifier

长长的编译结果,看起来很乏味,开发人员并不能知道什么时候编译好了

new WebpackBuildNotifierPlugin({
title: processEntity,
suppressSuccess: false,
suppressCompileStart: false,
suppressWarning: false,
activateTerminalOnError: true
}),

   

在win10上看比较醒目直观,但在win7上仅是状态栏的气泡弹出

不过在编译结果的内容提示还不够完善,可以改进

8. webpack-dev-server的端口自动获取空闲端口,多webpack项目共存时很方便

因基本所有获取空闲端口的npm包都是异步的,原理都是以端口开启服务器,如果开启成功则表示这个端口空闲。

但项目的webpack配置是直接 module.export一个配置项的,不是使用NodeJS API的方式,尝试切换为这种方式时发现竟然与HMR不同兼容,就此作罢

尝试寻找同步直接获取空闲端口的办法,想出了一个简单的,直接执行 netstat -an 命令列出当前进程端口再正则匹配即可,奈思~

 let execSync = require('child_process').execSync,
// 已使用的端口
usedPorts = [],
// (初始)可使用的端口
freePort = 10000,
// 可用端口范围
portStart = 10000;
portEnd = 30000,
// 查询最大步
maxStep = 100000; /**
* 获取随机端口
* @return {[type]} [description]
*/
function getRandomPort() {
return Math.floor(Math.random() * (portEnd - portStart) + portStart);
} function getFreePort() {
console.log('Finding free port...'); let stepIndex = 0,
res = '',
portSplitStr = ':'; try {
res = execSync('netstat -an', {
encoding: 'utf-8'
});
usedPorts = res.match(/\s(0.0.0.0|127.0.0.1):(\d+)\s/g); if (!usedPorts) {
usedPorts = res.match(/\s(\*|127.0.0.1)\.(\d+)\s/g);
portSplitStr = '.';
} usedPorts = usedPorts.map(item => {
let port = item.split(portSplitStr);
port = port.slice(-1)[0];
return parseInt(port.slice(0, -1), 10);
}); usedPorts = [...new Set(usedPorts)]; let portAvaliable = false;
while (!portAvaliable) {
freePort = getRandomPort(); if (!usedPorts.includes(freePort)) {
portAvaliable = true;
console.log('Use port ' + freePort + ' for devServer\n');
} if (++stepIndex > maxStep) {
console.log('Cannot find free port for devServer\n');
break;
}
}
} catch(e) {
console.log('Cannot find free port for devServer\n');
console.log(e);
} return freePort;
} module.exports = getFreePort;

9. 编译的dos进程窗添加标题,多个webpack项目执行时,在任务栏小窗区分更方便

也比较简单,直接设置即可

process.title = `${configs.versionControl || 'branch'}--${configs.name || 'anonymous'}--[${process.env.NODE_ENV}]`,

不过在使用git bash时,这样设置是无效的

使用 node-bash-title 即可

require('node-bash-title')(`${configs.versionControl || 'branch'}--${configs.name || 'anonymous'}--[${process.env.NODE_ENV}]`);

10. 引入 dllplugin动态链接库方案,将第三方库单独打包,再链入我们的webpack项目中

可以参考介篇文章

新建一个webpack.dll.config.js配置文件

let path = require('path');
let webpack = require('webpack'); module.exports = {
entry: {
// 需要预配置动态链接的库
vendor: [
'babel-polyfill',
// 'echarts'
'react',
// 'redux',
// 'react-redux',
'react-dom',
// 'react-router'
]
}, // 启用sourceMap
// devtool: 'cheap-module-source-map', output: {
path: path.resolve(__dirname, './'),
filename: '[name].js',
library: '[name]_library_wcr'
}, plugins: [
new webpack.DllPlugin({
path: path.join(__dirname, './', '[name].manifest.json'),
name: '[name]_library_wcr'
})
]
}

执行一次,将第三方包打包出来,如果该配置文件有改动的,也需要再次打包

使用 DllReferencePlugin 插件链接这个manifest清单引用

new webpack.DllReferencePlugin({
manifest: require(path.join(__dirname, './dll/', 'vendor.manifest.json')),
}),

使用 add-asset-html-webpack-plugin这个插件将vendor库插入到页面中

需要注意的是,默认它会将vendor插入到所有htmlWebpackPlugin设置的页面中,所有我们需要通过files属性定义好

如果有父页面的,则只插入生成的父页面中即可

// 动态链接库引用配置
if (configs.vendorDllOpen) {
let addAssetHtmlPluginOption = {
filepath: require.resolve('./dll/vendor.js'),
includeSourcemap: false,
hash: true
}; if (configs.vendorDllInsertFiles !== 'all') {
Object.assign(addAssetHtmlPluginOption, {
files: configs.vendorDllInsertFiles
});
} commonConfig.plugins.push(
new webpack.DllReferencePlugin({
manifest: require(path.join(__dirname, './dll/', 'vendor.manifest.json')),
}),
new AddAssetHtmlPlugin(addAssetHtmlPluginOption)
);
}

不过它的hash控制不能设定位数,不够优雅

注意这里是由 htmlWebpackPlugin调用的ejs-loader 解析源页面文件的配置生成的

<% for(var key in htmlWebpackPlugin.files.js) { %>
<script src="<%= htmlWebpackPlugin.files.js[key] %>"></script>
<% } %>

11. 使用 webpack-bundle-analyzer 分析打包结果

// 打包模块分析
if (process.argv.includes('--analysis')) {
commonConfig.plugins.push(new BundleAnalyzerPlugin({
analyzerMode: 'server',
analyzerHost: '127.0.0.1',
analyzerPort: require('./getFreePortSync')(),
reportFilename: 'report.html',
defaultSizes: 'parsed',
openAnalyzer: true,
generateStatsFile: false,
statsFilename: 'stats.json',
statsOptions: null,
logLevel: 'info'
}));
}

 12. 引入代码检查工具套件,关于这部分,可移步 这里

 13. 将配置文件再抽取,抽出核心部分与和业务相关的多变动的部分

形成如下结构,一般来说只需要变动 webpack.config.js 这个配置即可

趁webpack5还没出,先升级成webpack4吧的更多相关文章

  1. 升级过log4j,却还没搞懂log4j漏洞的本质?

    摘要:log4j远程代码漏洞问题被大范围曝光后已经有一段时间了,今天完整讲清JNDI和RMI以及该漏洞的深层原因. 本文分享自华为云社区<升级过log4j,却还没搞懂log4j漏洞的本质?为你完 ...

  2. 成功熬了四年还没死?一个IT屌丝创业者的深刻反思

    三个IT屌丝创业的故事 从前有三个屌丝,聚在一起做网络.提供免费的网络服务,砸锅卖铁,通宵达旦,除了卖肾,啥都做了.3年后终于做到了五百万用户.对于年轻人来说,能把五百万人玩弄于鼓掌之间,已经是很牛逼 ...

  3. 在各方面还没准备好的时候,大家一定要慎用border-box样式!!!!

    这几天,我被一个js问题困扰到癫狂了! 事情是这样的,我之前写了个功能非常复杂的纯jquery代码的前端gridview控件,实现了大量的功能和效果,在一些项目里也用得很好. 最近有个项目,样式做了调 ...

  4. 自动发布工具版本从python2升级成python3后遇到的种种问题(涉及paramiko,Crypto,zipfile等等)

    从在公司实习到正式入职,一直还在被同事使用的是我写的一个自动发布工具.该工具的主要功能是:开发人员给出需要更新的代码包(zip格式),测试人员将该代码包部署到测服,这些代码包和JIRA数据库里的项目信 ...

  5. 骚年,看我如何把 PhantomJS 图片的 XSS 升级成 SSRF/LFR

    这篇文章实在是太好了,我看了好几篇,所以极力推荐给大家 原文地址   http://buer.haus/2017/06/29/escalating-xss-in-phantomjs-image-ren ...

  6. Java中的等待唤醒机制—至少50%的工程师还没掌握!

    这是一篇走心的填坑笔记,自学Java的几年总是在不断学习新的技术,一路走来发现自己踩坑无数,而填上的坑却屈指可数.突然发现,有时候真的不是几年工作经验的问题,有些东西即使工作十年,没有用心去学习过也不 ...

  7. 将arcEngine9.3和dev9.2.4开发的项目升级成arcObject10.2和dev15.1.3过程中遇到的问题和解决

    好久没碰.net了,arcgis更是感觉都忘干净了,今天将arcEngine9.3和dev9.2.4开发的一个项目升级成arcObject10.2和dev15.1.3过程中遇到了一系问题,留个笔记,留 ...

  8. 不会吧,你连Java 多线程线程安全都还没搞明白,难怪你面试总不过

    什么是线程安全? 当一个线程在同一时刻共享同一个全局变量或静态变量时,可能会受到其他线程的干扰,导致数据有问题,这种现象就叫线程安全问题. 为什么有线程安全问题? 当多个线程同时共享,同一个全局变量或 ...

  9. Windows Server 2008 R2 辅域控制器如何升级成主域控制器

    一.实验模拟故障问题: zhuyu公司架设了一台主域控制器和一台辅域控制器,某一天,zhuyu公司的主域控制器系统崩溃,主域控制器系统也进不去. 虽然辅域控制器可以暂时代替主域控制器的普通工作,但是特 ...

随机推荐

  1. Codeforces Round #485 (Div. 2) A. Infinity Gauntlet

    Codeforces Round #485 (Div. 2) A. Infinity Gauntlet 题目连接: http://codeforces.com/contest/987/problem/ ...

  2. 基于ESP32的uart通讯

    本文源码地址为:http://download.csdn.net/download/noticeable/9961054 ESP32上有三个UART通讯接口,设备号,从0~2,即UART0,UART1 ...

  3. json、txt、xlsx

    json:   json异于pickle,无乱码,各语言都支持,但Python各对象只直接接收int,str,(),[],{}.读入txt时只接受str,int变为str(int),()[]{}被js ...

  4. shell脚本基础教程

    一.什么是shell: shell解释:引用别人的话说:“Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁.Shell 既是一种命令语言,又是一种程序设计语言.” 简而言之, ...

  5. RunTime之类与对象

    我们知道,Objective-C是一门动态语言,它将很多静态语言在编译时期做的事放到了运行时来处理.用C++编写的程序通过编译器直接把函数地址硬编码进入可执行文件:而Objective-C无法通过编译 ...

  6. Codeforces Round #553 (Div. 2) C. Problem for Nazar 数学

    题意:从奇数列 1 3 5 7 9 ....  偶数列2 4 6 8 10...分别轮流取 1 2 4 ....2^n 个数构成新数列 求新数列的区间和 (就一次询问) 思路:首先单次区间和就是一个简 ...

  7. Ubuntu18.04安装网易云音乐

    一. 安装 去网易云官网下载对应于ubuntu系统的安装包 安装依赖 dpkg -s libcanberra-gtk-module #检查依赖是否安装 sudo apt install libcanb ...

  8. 关于 SQL 注入的问题

    拼串 (Statement)方式 1.编译次数多,效率比较低:会出现SQL注入问题(数据安全问题):先传参数再编译. 2.Sql文对应的字符串不一样,需要再次编译.Sql文对应的字符串一样,不会再编译 ...

  9. MySQL学习笔记2(多表操作)

    外键:使两张表之间存在关联 特点: 1.从表外键的值是对主表主键的引用 2.从表外键类型,必须与主表主键类型一致 示例: 创建两个表并准备数据: USE mybase; CREATE TABLE ca ...

  10. 人脸检测第一文---A Dream of Spring

    人脸识别研究的人很多,可是,真正具有划时代意义的还要当属Paul Viola的一篇文章<RobustReal-time Object Detection>.这篇文章让 人脸识别在实际应用中 ...