gloria0 2019-06-21
对于大型web app来说,如果把所有的文件都打包到一个文件中是非常低效的,特别是当一些代码块只在某些特定的条件下被调用。webpack可以让你的代码库分割成不同的块(chucks),仅仅在需要的时候再加载。其他的一些打包工具叫它们图层(layers), 卷(rollups) 或者 片段(fragments),这些特性被叫做代码分离(code splitting)。
这是一个可选的属性。你可以在你的代码库中定义分割点。webpack能帮你管理好依赖,输出文件和运行时。
澄清一个共同的误解:代码分离(code splitting)不仅仅是抽出公共代码把它们放进一个共享的块(chuck)中。更重要的特性是代码分离(code splitting)可以将代码分割成按需加载的块。这可以使项目初始化的时候只需要加载很少的代码,当应用请求的时候再按需加载代码。
有三种常用的代码分离方法:
这是迄今为止最简单,最直观的拆分代码的方式。但是它是比较偏向手动并且有一些陷阱需要我们去注意的。看一看我们是怎么样从主buddle中分割其他模块的。
webpack-demo |- package.json |- webpack.config.js |- /dist |- /src |- index.js + |- another-module.js |- /node_modules
import _ from 'lodash'; console.log( _.join(['Another', 'module', 'loaded!'], ' ') );
const path = require('path'); const HTMLWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: { index: './src/index.js', another: './src/another-module.js' }, plugins: [ new HTMLWebpackPlugin({ title: 'Code Splitting' }) ], output: { filename: '[name].bundle.js', path: path.resolve(__dirname, 'dist') } };
这将会产生下面的build结果:
Hash: 309402710a14167f42a8 Version: webpack 2.6.1 Time: 570ms Asset Size Chunks Chunk Names index.bundle.js 544 kB 0 [emitted] [big] index another.bundle.js 544 kB 1 [emitted] [big] another [0] ./~/lodash/lodash.js 540 kB {0} {1} [built] [1] (webpack)/buildin/global.js 509 bytes {0} {1} [built] [2] (webpack)/buildin/module.js 517 bytes {0} {1} [built] [3] ./src/another-module.js 87 bytes {1} [built] [4] ./src/index.js 216 bytes {0} [built]
还记得我们提到的那些陷阱嘛?
这两点中的第一点绝对是我们例子的中的问题。像lodash
也在./src/index.js中被导入,所以它会在两个bundle中重复。让我们来使用CommonsChunkPlugin来移除这个重复的部分。
CommonsChunkPlugin插件允许我们抽出共同的依赖放在一个存在的入口chunk或者一个存在的new chunk里。让我们使用这个插件去除上一个例子中重复的lodash依赖。
const path = require('path'); + const webpack = require('webpack'); const HTMLWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: { index: './src/index.js', another: './src/another-module.js' }, plugins: [ new HTMLWebpackPlugin({ title: 'Code Splitting' + }) + }), + new webpack.optimize.CommonsChunkPlugin({ + name: 'common' // Specify the common bundle's name. + }) ], output: { filename: '[name].bundle.js', path: path.resolve(__dirname, 'dist') } };
在这里使用commonsChunkPlugin,我们将会看到重读的依赖会从我们的index.bundle.js文件中移除。插件将会注意到我们已经将loadash分割成一个单独的块。并且从我们的主bundle中删除了这部分。让我们运行npm run bulid
来看看它是否起作用了。
Hash: 70a59f8d46ff12575481 Version: webpack 2.6.1 Time: 510ms Asset Size Chunks Chunk Names index.bundle.js 665 bytes 0 [emitted] index another.bundle.js 537 bytes 1 [emitted] another common.bundle.js 547 kB 2 [emitted] [big] common [0] ./~/lodash/lodash.js 540 kB {2} [built] [1] (webpack)/buildin/global.js 509 bytes {2} [built] [2] (webpack)/buildin/module.js 517 bytes {2} [built] [3] ./src/another-module.js 87 bytes {1} [built] [4] ./src/index.js 216 bytes {0} [built]
这里有一些社区提供的分割代码的插件和加载器:
当涉及到动态分割的时候,有两种相似的技术被支持。第一个并且也是更完满的方法是使用遵循ECMAScript规范的import语法来进行动态导入。更老的一种是,webpack特殊的方法require.ensure。让我们来试一试使用第一种方法。
import调用使用promise,如果你想在不支持promise的老旧浏览器上使用,请引入一个promise polyfill。
在我们开始之前,让我们移除这个多余的entry和commonsChunkPlugin 从我们的配置文件中。因为它们在接下来的教学中已经不再需要了。
webpack.config.js
const path = require('path'); - const webpack = require('webpack'); const HTMLWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: { + index: './src/index.js' - index: './src/index.js', - another: './src/another-module.js' }, plugins: [ new HTMLWebpackPlugin({ title: 'Code Splitting' - }), + }) - new webpack.optimize.CommonsChunkPlugin({ - name: 'common' // Specify the common bundle's name. - }) ], output: { filename: '[name].bundle.js', + chunkFilename: '[name].bundle.js', path: path.resolve(__dirname, 'dist') } };