【问题标题】:How to minimize the size of webpack's bundle?如何最小化 webpack 包的大小?
【发布时间】:2016-03-18 07:43:56
【问题描述】:

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

我从webpack 创建的bundle.js 是2.2 mb。在使用-p 标志运行优化后,它将捆绑包减少到 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"
    }]
  }
};

编辑

package.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"
  }
}

【问题讨论】:

  • 只有reactreact-dom 的依赖项吗?我已经看到一些依赖项拉入节点的某些部分(例如断言),并且可能会变得很大。我不太了解 webpack,但从这里看起来不错。也许尝试只用一个小组件编译一个脚本,没有其他依赖项,然后查看包大小
  • webpack 会将所有依赖项捆绑到您的单个 bundle.js 文件中,包括 CSS。除了react 和您自己的文件之外,您还需要其他文件吗?您能否在您的package.json 文件中发布dependencies 部分?你的 CSS 文件有多大?
  • 我的 css 文件可以忽略不计,我正在使用 react-bootstrapmaterial-ui。我不知道 webpack 还会在我的 package.json 中打包依赖项。我在我的jsx 文件中使用import 语句来使用这些组件。 @dreyescat
  • Webpack 没有在你的 package.json 中打包依赖。只是想知道除了react 之外还有哪些其他依赖项。但是,如果您使用的是 react-bootstrapmaterial-ui(您需要它们),那么可以。您还将它们打包到您的捆绑文件中。这就是为什么你会得到这么大的文件。

标签: reactjs webpack


【解决方案1】:

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

source-map-explorer yourBundle.js

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

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

【讨论】:

    【解决方案2】:

    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-ication 转义 unicode 字符的一个晦涩问题,因此,如果您使用这些转换,请注意可能出现的边缘情况。

    您可以在webpack docs 中阅读有关webpack 支持的特定选项的更多信息,其中包含一些后续链接以进一步阅读。


    (旁注:我认为您的 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 省略一些用于节点环境构建的东西

    最后,如果您使用源映射(您可能应该这样做),您需要添加适当的行。哨兵写了a nice blog post about this

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

    【讨论】:

    • Webpack 是一些黑魔法。当捆绑 react 和 react-dom 时,三个插件中的最后一个将包大小从 218kb 减少到 143kb。我不认为它会影响包大小。
    • @Capaj 这里没有 Webpack 的黑魔法。 React 使用 NODE_ENV 作为功能切换来删除像 PropTypes 这样的检查。请参阅this answer 了解更多信息。
    • 作为提醒,DedupePlugin 已从 Webpack 中移除,它现在应该大致默认这样做了。
    • 答案中对 UglifyJSPlugin 选项的引用已过时,正确的是现在webpack.js.org/plugins/uglifyjs-webpack-plugin
    【解决方案3】:

    2018 年 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
        })
      ],
    

    【讨论】:

    • 我尝试了上述从 3.5mb 到 1.9mb 的答案。但是这个答案给了我 996kb 的结果..太棒了。
    • 很高兴它帮助了你
    • 这一行应该是 bundle.js,而不是 'css'?新的 ExtractTextPlugin("bundle.css"
    • 应该是new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
    • @KhalidAzam 你有更新版本的答案吗?因为它会产生很多错误。我希望你已经更新了你的配置版本。谢谢。
    【解决方案4】:

    根据您的 cmets,您使用的是 material-uireact-bootstrap。这些依赖项与您的 reactreact-dom 包一起由 webpack 捆绑。任何时候你 requireimport 一个包,它都会被捆绑到你的包文件中。

    这是我的猜测。您可能正在使用 library 方式导入 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 及其各自的依赖项。但不是整个图书馆。所以我会尝试摆脱你所有的 library 导入并改用 component 方式。

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

    进一步解释:

    当您使用 library 方式时,您正在导入 all these react-bootstrapall these material-ui 组件,无论您实际使用的是哪些组件。

    【讨论】:

    • 感谢您的详细解释。我认为从库中导入特定元素,就像你刚才描述的那样,只会捆绑组件而不是整个库。我现在将以这种方式实现它。再次感谢!
    • 假设我有很多组件要导入,是否有写所有这些导入的简写? @dreyescat
    • @Candroid 创建一个mystuff 文件,该文件仅导入您在应用程序中需要的组件并重新导出它们。然后你的应用程序的其余部分可以只导入mystuff
    • 谁能解释或链接到一篇文章为什么 import { foo } from 'bar';与从 'bar/foo' 导入 foo 比较;是不同的?我认为 webpack 会优化未使用的代码
    • @SteveWillard 据我所知,这与模块如何构建其导出有关。 { foo } from 'bar' 只是require('bar').foo 的语法糖,其中bar module.exports = {foo: etc}foo from 'bar/foo' 等价于require('bar/foo'),其中bar/foo module.exports = etc--即,不嵌套在对象中。
    【解决方案5】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-09
      相关资源
      最近更新 更多