Webpack3.X升级到4.X多页面实战和构建优化

4,174 阅读5分钟

Webpack4.x出来也有一段时间了,网上已经有很多关于Webpack4.x原理和新特性的介绍,比如零配置等,这边就不重复了。

最近将之前基于Webpack3.x写的一个多页面项目升级到4.x,记录和总结Webpack3.x升级到4.x遇到的问题以及解决方案。

项目预览gif:

在线查看: webpack.czero.cn

区分3.x和4.x不同之外,也对Webpack进行了构建优化,并分别配置了Webpack3.x和Webpack4.x的基础配置文件托管在Github,可以用在项目中,减少配置的时间。

Webpack3.x:github.com/czero1995/w…

Webpack4.x:github.com/czero1995/w…

项目中Webpack实现功能:

  • 多页面入口配置
  • 使用Ejs模板实现组件化功能(共用头部和底部)
  • 提取公共CSS文件
  • 使用HappyPack做多线程打包
  • 引入最新Babel编译,可编译ES7,ES8(装饰圈@等)
  • devServer,保存自动刷新
  • 引入Less处理器
  • 配置TypeScript
  • 每次Build都先删除掉原先Build出来的文件

区分开发环境和生产环境

开发环境: npm run dev
生产环境: npm run build

区分开发环境可以提高Webpack打包效率,比如

  • 开发环境中:

    配置调试模式devtool:cheap-source-map

    配置devServer:保存自动刷新

  • 生产环境:

    配置调试模式devtool:inline-source-map

    加载提取CSS组件

    加载PostCss插件(浏览器前缀,提高兼容性)

    添加每次Build时先删除之前Build的文件

    压缩代码

    清空代码注释和空格

    加载PostCss插件

Webpack3.x和Webpack4.x的几个明显的区别和问题

1. 运行webpack要加参数

从4.0开始:运行webpack一定要加参数

-- mode development 或者 --mode production,

分别对应开发环境和生产环境,否则会报警告:

3.x (package.json)

"scripts": {
    "build": "webpack --optimize-minimize",
    "dev": "webpack-dev-server --config webpack.dev.config.js"
  },

4.x (package.json)

"scripts": {
    "build": "webpack --optimize-minimize --mode production",
    "dev": "webpack-dev-server --config webpack.dev.config.js --mode development"
  },

2. 移除loaders,必须使用rules

在Webpack3.x中还保留之前版本的loaders,与rules并存都可以使用,在新版中完全移除了loaders,必须使用rules。否则会报错,将module下面的loaders改为rules即可

3. 需要安装webpack-cli

4.x需要安装webpack-cli,不然运行不起来

npm install webpack-cli --save

4. TypeScript ts-loader版本太低

在webpack3.x中typescript使用正常,升级到webpack4.x之后就用不了typescript了,因为版本太低 修改typescript版本,我的事5.2.2,在package.json中修改ts-loader版本号,或者删掉,重新执行 npm install ts-loader即可

5. Ejs无法使用

Webpack结合Ejs可以做到组件化开发,共用HTML代码,比如多个页面的头部和底部,用组件引入的方式,方面后面的开发和维护。

3.x中正常使用,4.x会报ejsRenderLoder of undefined,需要修改htmlplugin的配置。 3.x为:

template: 'ejs-render-loader!pages/index.ejs',

4.x为

template: 'ejs-loader!pages/index.ejs',

5. text-webpack-plugin版本太低,构建失败

在package.json中修改extract-text-webpack-plugin版本号

"extract-text-webpack-plugin": "^v4.0.0-alpha.0",

Webpack构建优化

区分开发环境和生产环境

  • 开发环境不需要去压缩代码
  • 指定调试模式devtool模式

压缩代码用ParalleUglifyPlugin代替自带的UglifyJsPlugin插件

自带的js压缩插件是单线程执行的,而webpack-parallel-uglify-plugin可以并行的执行 开发环境不做无意义的操作

很多配置,在开发阶段是不需要去做的,我们可以区分出开发和线上的两套配置,这样在需要上线的时候再全量编译即可,比如代码压缩,目录内容清理,计算文件hash,提取css文件等

babel-loader开启缓存

babel-loader在执行的时候,可能会产生一些运行期间重复的公共文件,造成代码体积大多余,同时也会减慢编译效率

可以加上cacheDirectory参数或使用transform-runtime插件试试

// webpack.config.js
use: [{
    loader: 'babel-loader',
    options: {
        cacheDirectory: true
    }]


// .bablerc
{
    "presets": [
        "env",
        "react"
    ],
    "plugins": ["transform-runtime"]
    
}

使用happypack来加速构建

	happypack会采用多进程去打包构建

优化构建时的搜索路径alias

使用noParse

webpack打包的时候,有时不需要解析某些模块的加载(这些模块并没有依赖,或者并根本没有模块化),我们可以直接加上这个参数,直接跳过这种解析

module:{
noParse: /node_modules\/(jquery.js)
}

启用DllPlugin和DllReferencePlugin预编译库文件

这是最复杂也是提升效果最明显的一步,原理是将第三方库文件单独打包一次,以后的编译都不需要在编译打包第三方库

拷贝静态资源文件,引入DllPlugin和DllReferencePlugin来提前构建一些第三方库,来优化Webpack阿宝。

而在生产环境时,就需要将提前构建好的包同步到dist中

对于commonChunkPlugin,webpack每次打包实际还是需要去处理这些第三方库,只是打包完之后,能把第三方库和我们自己的代码分开。 而DllPlugin则是能把第三方代码完全分离开,即每次只打包项目自身的代码。 在build/文件夹下新建webpack.dll.config.js文件,复制一下代码:

	const path = require("path")
	const webpack = require("webpack")
	
	module.exports = {
	    // 你想要打包的模块的数组
	    entry: {
	        vendor: ['vue/dist/vue.esm.js', 'axios', 'vue-router', 'vuex']
	    },
	    output: {
	        path: path.join(__dirname, '../static/js'), // 打包后文件输出的位置
	        filename: '[name].dll.js',
	        library: '[name]_library'
	    },
	    plugins: [
	        new webpack.DllPlugin({
	            path: path.join(__dirname, '.', '[name]-manifest.json'),
	            name: '[name]_library',
	            context: __dirname
	        }),
	        // 压缩打包的文件
	        new webpack.optimize.UglifyJsPlugin({
	            compress: {
	                warnings: false
	            }
	        })
	    ]
	}

build/webpack.dev.config.jsbuild/webpack.prod.config.js中添加plugins

	new webpack.DllReferencePlugin({
	      context: __dirname,
	      manifest: require('./vendor-manifest.json')
	}),

根目录下的index.html下引入预编译的库

 	<script src="./static/js/vendor.dll.js"></script>

package.json/scripts下中添加dll命令

"dll": "webpack --config ./build/webpack.dll.config.js"

运行:

npm run dll

然后再

npm run dev或npm run build

提取公共代码 使用CommonsChunkplugin提取公共的模块,可以减少文件体积,也有助于浏览器层的文件缓存

npm run dll
npm run dev 或npm run build