1

对于大型web app来说,如果把所有的文件都打包到一个文件中是非常低效的,特别是当一些代码块只在某些特定的条件下被调用。webpack可以让你的代码库分割成不同的块(chucks),仅仅在需要的时候再加载。其他的一些打包工具叫它们图层(layers), 卷(rollups) 或者 片段(fragments),这些特性被叫做代码分离(code splitting)。
这是一个可选的属性。你可以在你的代码库中定义分割点。webpack能帮你管理好依赖,输出文件和运行时。
澄清一个共同的误解:代码分离(code splitting)不仅仅是抽出公共代码把它们放进一个共享的块(chuck)中。更重要的特性是代码分离(code splitting)可以将代码分割成按需加载的块。这可以使项目初始化的时候只需要加载很少的代码,当应用请求的时候再按需加载代码。
有三种常用的代码分离方法:

  • 入口起点: 使用entry选项手动分离代码
  • 防止重复: 使用 CommonsChuckPlugin 来去重和分离代码
  • 动态导入: 在模块内部通过内联函数来调用代码

入口

这是迄今为止最简单,最直观的拆分代码的方式。但是它是比较偏向手动并且有一些陷阱需要我们去注意的。看一看我们是怎么样从主buddle中分割其他模块的。

project

webpack-demo
|- package.json
|- webpack.config.js
|- /dist
|- /src
  |- index.js
+ |- another-module.js
|- /node_modules

another-module.js

import _ from 'lodash';

console.log(
  _.join(['Another', 'module', 'loaded!'], ' ')
);

webpack.config.js

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]

这里有一些社区提供的分割代码的插件和加载器:

  • ExtractTextPlugin: 用来从主程序中分割出css
  • bundle-loader: 用来分离代码并且懒加载结果bundles
  • Promise-loader: 和bundle-loader作用相同,但是它是使用promise
    CommonsChunkPlugin使用explicit vendor chunks从核心应用代码中来分离vendor模块

动态导入

当涉及到动态分割的时候,有两种相似的技术被支持。第一个并且也是更完满的方法是使用遵循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')
    }
  };

淼淼真人
1.1k 声望202 粉丝

一个前端菜鸟!