使用Webpack优化你的第三方库

在webpack项目中使用了第三方库?使用这些方法可以缩小bundle!

async

async是一组用于处理异步函数的实用程序. npm package

通常,您应该使用async-es。它随ES模块一起提供,并且更适合webpack打包。

尽管如此,即使更喜欢使用async,对于优化列表,请参阅async-es部分。

async-es

async-es是一组用于处理异步函数的实用程序。它与async相同,但它更适合webpack打包。npm package

使用babel-plugin-lodash删除未使用的方法

如果你使用async-es作为单个导入,你将整个库打包到应用程序中 —— 即使你只使用它的几个方法:


// 您只使用`async.map`,但整个库被打包
import async from 'async-es';

async.map(['file1', 'file2', 'file3'], fs.stat, function(err, results) {
  console.log(results);
});

使用babel-plugin-lodash只选择你需要的async-es方法:


// 应用Babel之前
import async from 'async-es';

async.map(['file1', 'file2', 'file3'], fs.stat, function(err, results) {
  console.log(results);
});


// 应用Babel之后
import _map from 'async-es/map';

_map(['file1', 'file2', 'file3'], fs.stat, function(err, results) {
  console.log(results);
});

启用此插件,如下所示:


// .babelrc
{
  "plugins": [["lodash", { "id": ["async-es"] }]],
}

babel-polyfill

babel-polyfill是一个Babel的包,它加载了core-js和一个自定义的再生器运行时。 Babel docs · npm package

有关优化列表,请参阅core-js部分。

core-js

core-js是一套用于ES5和ES2015+的polyfill。npm package

使用babel-preset-env删除不必要的polyfill

如果使用Babel和babel-preset-env编译代码,请添加useBuiltIns: true选项。此选项将Babel配置为仅包含目标浏览器所必需的polyfill。例如,如果您将应用程序定位为支持Internet Explorer 11:


// .babelrc
{
  "presets": [
    [
      "env",
      {
        "targets": {
          "browsers": ["last 2 versions", "ie >= 11"]
        }
      }
    ]
  ]
}

启用useBuiltIns: true将删除Internet Explorer 11已支持的所有功能(例如Object.createObject.keys等)的polyfill。

将非转换代码发送到现代浏览器

所有支持<script type ="module">的浏览器也支持现代JS功能,如async/await,箭头函数和类。使用此功能构建bundle包的两个版本,并使现代浏览器仅加载现代代码。有关指南,请参阅Philip Walton的文章

date-fns

date-fns是一个日期实用程序库。 npm package

启用babel-plugin-date-fns

babel-plugin-date-fns使用特定日期函数函数的导入替换date-fns的完整导入:


import { format } from 'date-fns';
format(new Date(2014, 1, 11), 'MM/DD/YYYY');


import _format from 'date-fns/format';
_format(new Date(2014, 1, 11), 'MM/DD/YYYY');

lodash

Lodash是一个实用程序库。 npm package

启用babel-plugin-lodash

babel-plugin-lodash通过导入特定的Lodash功能取代了完整的Lodash导入:


import _map from 'lodash/map';
_map([1, 2, 3], i => i + 1);


import _map from 'lodash/map';
_map([1, 2, 3], i => i + 1);

注意:该插件不适用于方法链 – 比如这样的代码不会被优化。


_([1, 2, 3]).map(i => i + 1).value();

lodash-es别名为lodash

一些依赖项可能使用lodash-es而不是lodash。如果是这样的话,Lodash将打包两次。

为避免这种情况,请将lodash-es包别名为lodash


// webpack.config.js
module.exports = {
  resolve: {
    alias: {
      'lodash-es': 'lodash',
    },
  },
};

启用lodash-webpack-plugin

lodash-webpack-plugin剥离了你不需要的Lodash功能部分。例如,如果您使用_.get()但不需要深层路径支持,则此插件可以删除它。将其添加到您的webpack配置中以使打包更小。

请谨慎使用该插件。 默认设置会删除许多功能,您的应用可能会使用其中一些功能。

lodash-es

lodash-es是Lodash的ES模块。 npm package

有关优化列表,请参阅lodash部分。

moment

Moment.js是一个处理日期的库。 npm package

使用moment-locales-webpack-plugin删除未使用的语言

默认情况下,Moment.js附带160多KB压缩后的本地化文件。如果您的应用程序仅提供几种语言,则不需要所有这些文件。使用moment-locales-webpack-plugin删除未使用的语言。

请谨慎使用该插件。 默认设置删除所有区域设置;如果您使用其中一些,这可能会破坏您的应用。

react

React是一个用于构建用户界面的库。 npm package

删除生产中的propTypes声明

React不会在生产中执行propTypes检查,但propTypes声明仍然占用了bundle的一部分。 使用babel-plugin-transform-react-remove-prop-types从构建过程中删除它们。

迁移到另一个类似React的库

React的替代品具有类似的API,具有更小的尺寸或更高的性能,但缺少一些功能(例如,Fragments, Portals或合成事件)。

  • Preact | 最小的React替代方案(preact@8.3.1 + preact-compat@3.18.3 7.6 kB gzipped; react@16.4.0 + react-dom@16.4.0 31.4 kB gzipped)| 没有合成事件| IE8支持polyfill
  • Nerv | 比React小,比Preact大(nervjs@1.3.3 9.8 kB gzipped,不需要compat; react@16.4.0 + react-dom@16.4.0 31.4 kB gzipped)| Nerv的目标是100%使用相同的API(没有Fiber和Suspense),详见NervJS/nerv#10 | IE8支持
  • Inferno | 比React小,大于Preact和Nerv(inferno@5.4.2 + inferno-compat@5.4.2 11.3 kB gzipped; react@16.4.0 + react-dom@16.4.0 31.4 kB gzipped)| 比React更高的运行时性能,是所有React替代品中性能最高的,提供了手动优化的可能性 部分合成事件| IE8原生不受支持

谨慎迁移到替代品。 一些替代品没有合成事件或缺少一些React 16功能(Preact issue, Inferno issue, Nerv issue)。 但是,许多项目仍然可以在没有任何代码库更改的情况下进行迁移。 请参阅迁移指南:Preact, Inferno, Nerv

reactstrap

Reactstrap是基于Bootstrap 4的React库。 npm package

使用babel-plugin-transform-imports删除未使用的模块

从Reactstrap导入模块时:


import { Alert } from 'reactstrap';

其他Reactstrap模块也会打包到应用程序中并使其更大。

使用babel-plugin-transform-imports去除未使用的模块:


// .babelrc
{
  "plugins": [
    ["transform-imports", {
      "reactstrap": {
        "transform": "reactstrap/lib/${member}",
        "preventFullImport": true
      }
    }]
  ]
}

要了解它是如何工作的,请查看babel-plugin-transform-imports部分。

react-bootstrap

react-bootstrap是基于React的Bootstrap 3库。 npm package

使用babel-plugin-transform-imports删除未使用的模块

react-bootstrap导入模块时:


import { Alert } from 'reactstrap';

其他react-bootstrap模块也会打包到应用程序中并使其更大。

使用babel-plugin-transform-imports去除未使用的模块:


// .babelrc
{
  "plugins": [
    ["transform-imports", {
      "react-bootstrap": {
        "transform": "react-bootstrap/es/${member}",
        "preventFullImport": true
      }
    }]
  ]
}

要了解它是如何工作的,请查看babel-plugin-transform-imports部分

react-router

React Router是React的流行路由器解决方案。 npm package

使用babel-plugin-transform-imports删除未使用的模块

从React Router导入模块时:


import { withRouter } from 'react-router';

其他React Router模块也会打包到应用程序中并使其更大。

使用babel-plugin-transform-imports去除未使用的模块:


// .babelrc
{
  "plugins": [
    ["transform-imports", {
      "react-router": {
        "transform": "react-router/${member}",
        "preventFullImport": true
      }
    }]
  ]
}

(这是使用React Router v4测试的。)

要了解它是如何工作的,请查看babel-plugin-transform-imports部分。

styled-components

styled-components是一个CSS-in-JS库。 npm package

使用babel-plugin-styled-components压缩代码

babel-plugin-styled-components插件可以压缩用styled-components编写的CSS代码。请参阅相关文档

whatwg-fetch

whatwg-fetch是一个完整的window.fetch() polyfill。 npm package

替换为unfetch

unfetchwindow.fetch()的500字节polyfill。与whatwg-fetch不同,它不支持完整的window.fetch() API,而是专注于polyfill最常用的部分。

谨慎迁移到unfetch 虽然它支持最流行的API部分,但如果它依赖于不太常见的东西,您的应用可能会无法正常运行。

适用于多个库的解决方案

当然,也有其他库的优化技巧。你可以将它们与常识一起使用,以获得更小或更高性能的bundle包。

babel-plugin-transform-imports

这个方便的babel插件会将您的导入转换为仅导入特定组件,这可确保不会包含整个库。


// Before
import { Grid, Row, Col } from 'react-bootstrap';
// After
import Grid from 'react-bootstrap/lib/Grid';
import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';

原文地址

GoogleChromeLabs/webpack-libs-optimizations