记一次 webpack 打包体积优化

手头作的项目开发得差很少了,而打包配置是一开始粗略配置的,不大的项目打包出来得6MB+,因此如今必须进行优化。javascript

打包结果分析

执行命令 webpack --profile --json > stats.json ,能够将打包过程的详细信息以 json 格式记录到文件中。依据该文件,webpack-bundle-analyzerWebpack Chart 等分析工具会以可视化的形式展现打包过程和结果。css

webpack-bundle-analyzer

若是不想用这些额外工具,经过命令 webpack --display-modules --sort-modules-by size ,webpack 会在日志中按大小排序显示全部模块。java

我在项目中,将第三方库基本都集中打包到一个 chunk (vendors),业务逻辑单独一个 chunk (app)。打包整体积的大头来自 vendors,其中antd占据大头(3MB+)、moment占据约500KB、提取的 css 约300KB、react-dom也是500KB+,出乎意料的是 lodash 也是500KB+。react

逐个击破

设置环境变量 NODE_ENVproduction

很多库会按开发环境(development)和生产环境(production)提供不一样的文件,主要是为了开发模式下的调试,也会所以有文件体积上的差异。用于生产环境的打包,设置其为production后,这些库会提供最小体积的文件。webpack

plugins: [
    // ...
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify('production')
      }
    }),
    // ...
]

css-loader

css-loader 在 webpack 默认不开启压缩,须要设置 css-loader?minimizegit

module: {
    // ...
    {
      test: /\.css$/,
      use: ExtractTextPlugin.extract({
        fallback: 'style-loader',
        use: 'css-loader?minimize'
      })
    }
    // ...
}

大头——antd (ant design)

由于并无使用 antd 的全部组件,因此按需加载是必需的。根据其文档(按需加载 - Ant Design),须要安装 bable 插件 babel-plugin-import ,并在 babel 配置中添加:es6

{
    // ...
    "plugins": [
        ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }],
        // ...
    ]
}

在我配置过程当中,libraryDirectory 配置的不一样也会有较大影响,但按目前文档来看貌似没有影响,待我确认后再作记录。github

=== 2018-02-23 更新 ===web

看来bable-plugin-import这几天有更新,如今配置项 libraryDirectory 的默认值时 lib,即便用经过 require (commonjs) 引用模块的文件。而先前我在配置的时候并无默认值,若是没有显示配置 libraryDirectory,打包结果会出现重复的内容。json

采用了 es6 module 的项目建议配置 libraryDirectoryes,即便用经过 import (es6 module) 引用模块的文件。这种状况打包后的体积要更小一些。

=== end ===

这里还有很重要一点,babel-plugin-import 要求 antd 不能被提取为公共模块 vendors,不然就没法实现按需加载。尚不清楚是 babel 插件的缘由,仍是这个插件单独的缘由。

moment

moment 库的体积开销主要是 i18n 文件,配置 webpack 将用不到 i18n 文件不打包便可。

plugins: [
    new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /zh-cn/),
]

看上去很轻量的 lodash

lodash看上去就是一些工具函数,应该是很轻量的,然而一次所有加载下来要达到500KB,所以也须要按需加载。它的按需加载还比较麻烦。

lodash为每一个方法单独提供了库,但这种方式在实际使用中并不灵活,因此这种最「干净」的方法不建议使用。

像 antd 同样,lodash 也有 babel 插件用于按需加载——babel-plugin-lodash

{
    // ...
    "plugins": [
        "lodash",
        // ...
    ]
}

一样,lodash 就不能提取到公共模块了。

最后

打包结果的体积开销主要就是以上几项。通过优化后,体积降低至1.5MB之内,仍是很客观的。不过 antd 依然占据大头,后续会考虑把 antd 替换掉,毕竟用到的组件很少。

相关文章
相关标签/搜索