03月06, 2018

webpack代码分割

来源:https://webpack.js.org/guides/code-splitting/

代码分割

这篇指南是对【开始指南】和【输出管理】里面的代码例子的扩展,请确定你已熟悉对应的代码。

代码分割是Webpack的一个非常吸引人的特性,这个功能允许我们并行或者按需加载需要的代码。它被用来打包成更小的代码包,并管理它们的加载优先级。如果使用得当的话,可以大幅缩短加载时间。

常见的代码分割方式有三种

  • 入口文件: 通过对entry的配置手工分割
  • 减少冗余: 使用CommonsChunkPlugin将公共模块抽离出来
  • 动态加载: 在模块内部通过行内函数分割代码。

Entry Point

这是最简单的代码分割方式,但不好维护。下面是个例子:

project

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

anthoer-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/idnex.js',
        another: './src/another-module.js'
    },
    plugins: [
        new HTMLWebpackPlugin({
            title: 'Code Spliting'
        })
    ],
    output: {
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    }
}

这种方式可能会有一些问题:

  • 在entry里面的有重复引用的模块
  • 无法根据核心应用逻辑对代码进行动态分割

这两个问题在上面的例子中也有,lodash被引用了两遍。 下面我们使用 CommonsChunkPlugin来解决这个问题。

Prevent Duplication

CommonsChunkPlugin 允许我们将公共依赖的部分打包进某个已存在的entry chunk或者一个新的chunk, 让我们看下上面的例子如何优化。

webpack.config.js

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 Spliting'
        })
    ],
    optimization: {
        splitChunks: {
            cacheGroups: {
                default: false,
                commons: {
                    test: /node_modules/,
                    name: 'vendor',
                    chunks: 'initial',
                    minSize: 1
                }
            }

        }
    },
    output: {
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    }
};

commonsChunkPlugin在webpack4已废弃,提示使用splitChunk,所以在配置中改为splitChunks。配置如上。

Error: webpack.optimize.CommonsChunkPlugin has been removed, please use config.optimization.splitChunks instead.

通过公共模块的抽取,我们应该能够看到重复的依赖lodash已经从Index.bundle.js中移除。

下面是一些有用的代码抽取插件:

  • ExtractTextPlugin
  • bundle-loader
  • promise-loader

Dynamic Imports

Webpack提供两种动态代码分割的方式,一种是通过import()的语法, 另外一种是require.ensure

import()的调用是基于promise的,如果要在旧的浏览器上使用,请确认使用polifill,如es6-promise或者promise-polyfill。

在开始之前,我们先移除多余的entry和代码分割的插件。

注意,chunkFileName指的是不是entry定义的入口文件生成的文件名称。

最终的代码:

index.js

async function getComponent () {
    var element = await import(/* webpackChunkName: "lodash" */ 'lodash');

    element.innerHTML = _.join(['hello', 'world'], ' ');

    return element;
}

getComponent.then(component => {
    document.body.appendChild(component);
});

webpack.config.js

const path = require('path');
const webpack = require('webpack');
const HTMLWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: {
        index: './src/index.js'
    },
    plugins: [
        new HTMLWebpackPlugin({
            title: 'Code Spliting'
        })
    ],
    output: {
        filename: '[name].bundle.js',
        chunkFilename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    }
};

注意:

  1. 我们使用[name].bundle.js来命令引用的第三方库。
  2. Import()返回的是一个promise,所以可以使用async await语法。(前提是有babel可以进行处理)

Bundle Analysis

一旦开始分割代码,就可以通过分析工具来查看代码生成的大小。可以从官方分析工具开始[https://github.com/webpack/analyse], 也有很多其他的分析工具如下:

本文链接:http://fengbaiyang.cn/post/webpack-code-split.html

-- EOF --

Comments

暂不支持评论,如有问题,请发邮件至baiyang.feng@outlook.com。 望不吝赐教~