如何最小化 webpack 包的大小?

IT技术 reactjs webpack
2021-04-06 05:47:08

我正在使用reactwebpack作为我的module捆绑器编写一个网络应用程序jsx到目前为止,我的代码真的很轻,整个文件夹的大小为 25 kb。

bundle.js创建的大小webpack是 2.2 mb。-pflag运行优化后,把bundle缩小到700kb,还是非常大的。

我查看了该react.min.js文件,其大小为 130kb。

webpack 有可能产生这么大的文件还是我做错了什么?

webpack.config.js

var path = require('path');
var webpack = require('webpack');

module.exports = {
  entry: './public/components/main.jsx',
  output: {
    path: __dirname + "/public",
    filename: 'bundle.js'
  },
  module: {
    loaders: [{
      test: /.jsx?$/,
      loader: 'babel-loader',
      exclude: /node_modules/,
      query: {
        presets: ['es2015', 'react']
      }
    }, {
      test: /\.css$/,
      loader: "style!css"
    }]
  }
};

编辑

包.json:

{
  "name": "XChange",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "main": "./bin/www",
  "devDependencies": {
    "body-parser": "~1.13.2",
    "cookie-parser": "~1.3.5",
    "debug": "~2.2.0",
    "express": "~4.13.1",
    "jade": "~1.11.0",
    "morgan": "~1.6.1",
    "serve-favicon": "~2.3.0",
    "react-dom": "~0.14.3",
    "react": "~0.14.3",
    "webpack": "~1.12.9",
    "babel-loader": "~6.2.0",
    "babel-core": "~6.2.1",
    "babel-preset-react": "~6.1.18",
    "babel-preset-es2015": "~6.1.18",
    "react-bootstrap": "~0.28.1",
    "material-ui": "~0.14.0-rc1",
    "history": "~1.13.1",
    "react-router": "~1.0.2",
    "style-loader": "~0.13.0",
    "css-loader": "~0.18.0"
  },
  "dependencies": {
    "express-validator": "~2.18.0",
    "mongoose": "~4.2.9",
    "kerberos": "~0.0.17",
    "bcrypt": "~0.8.5"
  }
}
5个回答

根据您的评论,您正在使用material-uireact-bootstrap这些依赖项由 webpack 与您的reactreact-dom捆绑在一起任何时候你requireimport一个包都被捆绑为你的包文件的一部分。

这是我的猜测。您可能正在使用方式导入react-bootstrapmaterial-ui组件

import { Button } from 'react-bootstrap';
import { FlatButton } from 'material-ui';

这很好也很方便,但它不仅捆绑ButtonFlatButton(及其依赖项)而且整个库。

缓解它的一种方法是仅尝试importrequire需要什么,例如组件方式。使用相同的示例:

import Button from 'react-bootstrap/lib/Button';
import FlatButton from 'material-ui/lib/flat-button';

这只会捆绑ButtonFlatButton以及它们各自的依赖关系。但不是整个图书馆。所以我会尝试摆脱所有的导入并使用组件方式。

如果您没有使用大量组件,那么它应该会大大减少捆绑文件的大小。

作为进一步的解释:

当您使用方式时,您将导入所有这些 react-bootstrap所有这些 material-ui组件,无论您实际使用的是哪些组件。

假设我有很多组件要导入,是否有速记来编写所有这些导入?@dreyescat
2021-05-22 05:47:08
谢谢详细的解释。我认为从库中导入特定元素,就像您刚刚描述的那样,只会捆绑组件而不是整个库。我现在将通过这种方式实现它。再次感谢!
2021-05-23 05:47:08
@Candroid 创建一个mystuff文件,文件仅导入您在应用程序中需要的组件并重新导出它们。然后你的应用程序的其余部分就可以导入mystuff.
2021-05-29 05:47:08
@SteveWillard 据我所知,这与module的导出结构有关。{ foo } from 'bar'只是 的语法糖require('bar').foo,其中bar module.exports = {foo: etc}. foo from 'bar/foo'等价于require('bar/foo'), 其中bar/foo module.exports = etc--ie, 不嵌套在对象中。
2021-06-11 05:47:08
任何人都可以解释或链接到一篇关于为什么从 'bar' 导入 { foo } 的文章吗?对比从“bar/foo”导入 foo;是不同的?我认为 webpack 会优化未使用的代码
2021-06-20 05:47:08

01/2017 编辑- 从那以后,我对不同的 Webpack 插件有了更多了解,并想对其进行更新。事实证明,UglifyJS有很多配置选项,这些选项似乎不是很主流,但可以对您的包大小产生巨大影响。这是我当前的配置,带有一些注释(网站上的文档很棒):

 new webpack.optimize.UglifyJsPlugin({
      comments: false, // remove comments
      compress: {
        unused: true,
        dead_code: true, // big one--strip code that will never execute
        warnings: false, // good for prod apps so users can't peek behind curtain
        drop_debugger: true,
        conditionals: true,
        evaluate: true,
        drop_console: true, // strips console statements
        sequences: true,
        booleans: true,
      }
    })

我曾经遇到过一个uglify关于转义 unicode 字符的 -ication的晦涩问题,所以如果你使用这些转换可能会出现边缘情况,请注意。

您可以webpackwebpack 文档中阅读有关特定选项支持的更多信息,并提供一些后续链接以供进一步阅读。


(旁注:我认为你的 package.json 是混淆的......至少有一些开发依赖是我见过的每个 package.json 的依赖(例如,react-starter-kit

如果您正在为制作做准备,则还应该采取更多步骤来减小文件大小。这是我的 webpack.config.js 的片段:

 plugins: [


        new webpack.optimize.UglifyJsPlugin(),
        new webpack.optimize.DedupePlugin(),
        new webpack.DefinePlugin({
            'process.env': {
                'NODE_ENV': JSON.stringify('production')
            }
        })
    ],

1) 缩小/丑化你的代码

2) 替换重复代码以最小化文件大小

3) 告诉 webpack 省略它用于节点环境构建的一些东西

最后,如果您使用源映射(您可能应该使用),您将需要添加适当的行。Sentry 写了一篇关于此的不错的博客文章

在我的构建中,我使用 devtool:'source-map'用于生产

答案中对 UglifyJSPlugin 选项的引用已过时,现在在webpack.js.org/plugins/uglifyjs-webpack-plugin 中是正确的
2021-05-28 05:47:08
@Capaj 这里没有 Webpack 黑魔法。React 使用NODE_ENV作为功​​能切换来删除像 PropTypes 这样的检查。有关更多信息,请参阅此答案
2021-06-05 05:47:08
由于 DedupePlugin 已从 Webpack 中删除,因此默认情况下它应该大致执行此操作。
2021-06-15 05:47:08
Webpack 是一些黑魔法。当捆绑 react 和 react-dom 时,三个插件中的最后一个将包大小从 218kb 减少到 143kb。我不希望它会影响包的大小。
2021-06-17 05:47:08

18 年 5 月更新: 更新 UglifyJsPlugin 设置以更好地缩小

我在生产代码中使用以下配置进行缩小。

 plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        // This has effect on the react lib size
        'NODE_ENV': JSON.stringify('production'),
      }
    }),
    new ExtractTextPlugin("bundle.css", {allChunks: false}),
    new webpack.optimize.AggressiveMergingPlugin(),
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.UglifyJsPlugin({
      mangle: true,
      compress: {
        warnings: false, // Suppress uglification warnings
        pure_getters: true,
        unsafe: true,
        unsafe_comps: true,
        screw_ie8: true,
        conditionals: true,
        unused: true,
        comparisons: true,
        sequences: true,
        dead_code: true,
        evaluate: true,
        if_return: true,
        join_vars: true
      },
      output: {
        comments: false,
      },
      exclude: [/\.min\.js$/gi] // skip pre-minified libs
    }),
    new webpack.IgnorePlugin(/^\.\/locale$/, [/moment$/]), 
    new CompressionPlugin({
      asset: "[path].gz[query]",
      algorithm: "gzip",
      test: /\.js$|\.css$|\.html$/,
      threshold: 10240,
      minRatio: 0
    })
  ],
@KhalidAzam 你有更新版本的答案吗?因为它会产生很多错误。我希望你已经更新了你的配置版本。谢谢。
2021-05-23 05:47:08
应该是 new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
2021-05-27 05:47:08
我尝试了从 3.5mb 到 1.9mb 的上述答案。但是这个答案给了我 996kb 的结果……太棒了。
2021-06-02 05:47:08
很高兴它帮助了你
2021-06-16 05:47:08
这行应该是 bundle.js,而不是 'css'?新的 ExtractTextPlugin("bundle.css"
2021-06-18 05:47:08

你有没有看过你的脚本是如何通过网络发送的......我有一些非常简单的react组件,每个组件大约 300kb,这是在 webpack 优化之后。在它们被压缩后,它们降到了 38kb。仍然相当可观 - 但这就是我们今天使用明天功能所得到的。如果您使用 node/express 来提供静态资源,包括您的 javascript - 查看压缩 ( https://github.com/expressjs/compression )。我还建议查看用于生产的节点最佳实践指南https://expressjs.com/en/advanced/best-practice-performance.html 如果您不通过节点提供文件,则使用 apache(或其他网络服务器)将有用于压缩基于文本的文件的选项。

我发现提及 source-map-explorer 实用程序很有用,它有助于了解您的 bundle.js 文件中的确切内容。它可以帮助您识别 bundle js 中是否有任何不必要的东西。您可以从 npm 安装 source-map-explorer 并使用它

source-map-explorer yourBundle.js

除此之外,正如@kimmiju 所提到的,检查您的服务器是否正在使用某种压缩。

Chrome 中的网络选项卡

您还可以尝试异步加载路由(在 webpack 中延迟加载),这样您的整个 bundlejs 文件就不会一次性发送,而是在用户导航到这些路由时分块发送。