[React-章节4]webpack的代码分割与公共代码提取
接着上篇《如何为react导入css和img?》 来说,对于一个多页面应用来说,webpack会把每个entry独立编译成chunk,也就是生成一对js和css文件。如果2个chunk代码都引用了同样的库(例如jquery),那么jquery代码会被分别打包进入2个chunk中,导致js文件尺寸增加,是一个不必要的冗余。
另外,我也猜想对于单页面应用来说,本身是不需要切换html页面的,所以貌似不存在加载多个不同chunk的需求。但是,如果单页应用比较大,那么1个bundle.js文件也会非常大,下载花费的时间就比较长,如果能把它切成几份并行下载也许也是个优化。
自动提取公共js,css
webpack库自身携带了几个常用的插件,这次要用到其中的CommonsChunkPlugin。它的作用是自动提取几个chunk中引用的相同模块到独立的文件中,这样可以实现多个chunk并行加载,从而提速。
CommonsChunkPlugin插件的原理介绍参考博客:怎么打包公共代码才能避免重复?
插件本身配置并不复杂,只需要修改webpack.config.js。在头部require引入webpack模块,在plugins部分new一个插件对象进行配置即可。
1 2 3 4 5 6 7 8 9 |
var webpack = require("webpack"); // 多页面应用,插件自动提取公共代码css/js new webpack.optimize.CommonsChunkPlugin({ name: 'commons', filename: 'bundle-[name]-[hash:8].js', minChunks: 2, chunks: ['a', 'b'] }), |
这里,我配置了这个公共chunk的名字叫做commons,而filename表示提取的js文件的命名方式([name]其实就是commons);minChunks我配置为2的意思是只要相同模块在2个chunk中同时出现就提取出来,因为我只有a和b两个模块,为了看到效果所以配置了数字2;chunks配置表示提取a和b这两个chunk的公共模块。
配置之后,可以webpack编译一下,会发现磁盘上多了bundle-commons-d919c270.js和bundle-commons-d919c270.css两个文件,而原先的bundle-a-xxxx.js和bundle-b-xxxx.js变得非常小了,说明公共代码已经全部被提取到commons这个chunk里了。
值得注意的是,原先的bundle-a-xxx.css和bundle-b-xxx.css全都不见了,却多了一个bundle-commons-xxx.css,说明CommonsChunkPlugin插件也可以提取公共css文件(别忘了webpack一切皆模块,包括css和img)。同时,因为在我的项目里,a和b两个chunk都是同一套代码,所以经过提取之后a和b就没有非公共的css文件了,所有的css都进入了commons。
自动引入公共模块
CommonsChunkPlugin插件只是分析和提取多个chunk之间公共js和css,就像ExtractTextPlugin只是帮我们把1个chunk里的所有css提取到一个独立文件中一样,它们的产出物并不会自动引入到index.html中。
这里,我们继续借助之前学习的HtmlWebpackPlugin插件,它可以帮我们自动引入CommonsChunkPlugin提取的公共js,css到生成的index.html中。
配置方法并没有什么新的花样,因为CommonsChunkPlugin提取的js和css都被归属于commons这个chunk,因此只需要让HtmlWebpackPlugin的chunks配置中额外包含commons这个chunk,最终生成的html中就会包含引入的相关代码了,完整配置如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
var ExtractTextPlugin = require("extract-text-webpack-plugin"); var HtmlWebpackPlugin = require("html-webpack-plugin"); var webpack = require("webpack"); module.exports = { // 字典的形式,配置了2个entry入口,就会对应2个所谓的chunk // 一个叫做a,一个叫做b,编译的话会生成2套css和js entry: { a: "./app.es6", b: "./app.es6" }, output: { // bundle.js也进行了编码 filename: "bundle-[name]-[hash:8].js", hash: true, // 开启hash编码功能 }, module: { preLoaders: [ { test: /\.js$/, exclude: /node_modules/, loader: 'jshint-loader' } ], loaders: [ { test: [ /\.js$/, /\.es6$/], exclude: /node_modules/, loader: 'babel-loader', query: { cacheDirectory: true, presets: ['react', 'es2015'] } }, { test: /\.css$/, //loader: "style-loader!css-loader?modules" loader: ExtractTextPlugin.extract( "style-loader", "css-loader?modules" ) }, { // 小于8KB的图片使用base64内联 test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' } ] }, plugins: [ // 提取的css文件名进行了编码 new ExtractTextPlugin("bundle-[name]-[hash:8].css"), // 引入了html-webpack-plugin自动生成html // 生成chunk=a的html new HtmlWebpackPlugin({ title: 'a', filename : 'a_index.html', chunks: ['a', 'commons'] // 在entry里我定义过了a这个chunk }), // 生成chunk=b的html new HtmlWebpackPlugin({ title: 'b', filename : 'b_index.html', chunks: ['b', 'commons'] // 在entry里我定义过了b这个chunk }), // 多页面应用,插件自动提取公共代码css/js new webpack.optimize.CommonsChunkPlugin({ name: 'commons', filename: 'bundle-[name]-[hash:8].js', minChunks: 2, chunks: ['a', 'b'] }), ], resolve: { extensions: ['', '.js', '.es6'] } } |
访问localhost:8080/b_index.html,也就是访问b这个chunk(entry),可以看到所有的css都被提取到了commons里,而js文件有属于chunk b的,也有提取到chunk commons中的:
1 2 3 4 5 6 7 8 9 |
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>b</title> <link href="bundle-commons-1bf893a9.css" rel="stylesheet"></head> <body> <script type="text/javascript" src="bundle-commons-1bf893a9.js"></script><script type="text/javascript" src="bundle-b-1bf893a9.js"></script></body> </html> |
通过该篇的学习,应该感觉对webpack的常见用法有一个整体的把握了。接下来,我会学习react-router,从而能够轻松的编写单页应用!
如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~
