首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Webpack 4,React项目,包大小

Webpack 4,React项目,包大小
EN

Stack Overflow用户
提问于 2018-07-27 15:22:01
回答 1查看 252关注 0票数 0

在React项目中使用了Webpack 4,所以使用的NPM包很少,但是包的大小很大--比如6MB。

我已经阅读了Webpack 4的文档,以了解如何缩小和构建生产就绪包,但文件大小似乎并没有减少那么多。

我也尝试过拆分捆绑包,但没有真正成功。例如,试图将所有与React相关的包放在一个包中,但这破坏了web应用程序-浏览器抛出错误,说它找不到包。不过,我可能做错了什么!

因此,我正在寻找一些帮助来改进我的构建设置,并将文件拆分成更小的文件,通常只是让事情变得更好。

我的Webpack 4配置文件:

代码语言:javascript
复制
const path = require('path');
const precss = require('precss');
const webpack = require('webpack');
const packageJson = require('./package.json');
const autoprefixer = require('autoprefixer');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');

const filenames = {
    css: '[name].bundle.css',
    js: '[name].bundle.js',
};

console.log('#########################################');

/* Cache busted names for production */
if (process.env.NODE_ENV === 'production') {
    console.log('#   XXXXXX v', packageJson.version, ' PRODUCTION   #');

    const timestamp = +new Date();

    filenames.css = `[name].bundle.${timestamp}.css`;
    filenames.js = `[name].bundle.${timestamp}.js`;
} else {
    console.log('#   XXXXXX v', packageJson.version, ' DEVELOPMENT   #');
}

console.log('#########################################');
console.log('');

module.exports = (env, options) => ({
    entry: './src/assets/js/Scheduler.jsx',
    output: {
        publicPath: '/',
        filename: `assets/js/${filenames.js}`,
        path: path.resolve(__dirname, 'public'),
    },
    watchOptions: {
        ignored: /node_modules/,
    },
    node: {
        fs: 'empty',
    },
    devtool: (options.mode === 'production') ? 'source-map' : 'cheap-module-source-map',
    devServer: {
        hot: true,
        watchContentBase: true,
        historyApiFallback: true,
        contentBase: path.join(__dirname, 'src'),
    },
    module: {
        rules: [{
            test: /\.(js|jsx)$/,
            exclude: /node_modules|bower_components/,
            use: [
                'babel-loader',
                'eslint-loader',
            ],
        }, {
            test: /\.(css)$/,
            exclude: /node_modules|bower_components/,
            use: [
                MiniCssExtractPlugin.loader,
                {
                    /* Interprets `@import` and `url()` like `import/require()` and will resolve them */
                    loader: 'css-loader',
                    options: {
                        sourceMap: true,
                    },
                },
            ],
        }, {
            test: /\.(scss)$/,
            exclude: /node_modules|bower_components/,
            use: [
                {
                    loader: 'css-hot-loader',
                    options: {
                        sourceMap: true,
                    },
                },
                /**
                 * Commented out as we want to extract the styles into a seperate file which the mini CSS extract plugin will do.
                 * If you want to keep the styles within the scripts, comment this back in and comment out mini CSS extract plugin line below.
                 */
                /*
                {
                    loader: 'style-loader',
                    options: {
                        sourceMap: true,
                    },
                },
                */
                MiniCssExtractPlugin.loader,
                {
                    /* Interprets `@import` and `url()` like `import/require()` and will resolve them */
                    loader: 'css-loader',
                    options: {
                        sourceMap: true,
                    },
                }, {
                    /* Loader for webpack to process CSS with PostCSS */
                    loader: 'postcss-loader',
                    options: {
                        autoprefixer: {
                            browsers: ['last 3 versions'],
                        },
                        plugins: loader => [
                            precss(),
                            autoprefixer(),
                        ],
                        sourceMap: true,
                    },
                }, {
                    /* Loads a SASS/SCSS file and compiles it to CSS */
                    loader: 'sass-loader',
                    options: {
                        sourceMap: true,
                    },
                },
            ],
        }, {
            test: /\.woff2?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
            exclude: /node_modules|bower_components/,
            use: 'url-loader?limit=10000',
        }, {
            test: /\.(ttf|eot|svg)(\?[\s\S]+)?$/,
            exclude: /node_modules|bower_components/,
            use: 'file-loader',
        }, {
            test: /\.(png|jp(e*)g|svg|gif)$/,
            exclude: /node_modules|bower_components/,
            use: [{
                loader: 'url-loader',
                options: {
                    limit: 8000, /* Convert images < 8kb to base64 strings */
                    name: 'assets/img/[name]-[hash].[ext]',
                },
            }],
        }, {
            test: /\.html$/,
            exclude: /node_modules|bower_components/,
            use: {
                loader: 'html-loader',
                options: {
                    minimize: true,
                },
            },
        }, {
            test: /bootstrap\/dist\/js\/umd\//,
            use: 'imports-loader?jQuery=jquery',
        }],
    },
    resolve: {
        extensions: ['*', '.jsx', '.js', '.scss', '.css', '.html'],
    },
    performance: {
        hints: false,
    },
    optimization: {
        runtimeChunk: 'single',
        splitChunks: {
            cacheGroups: {
                commons: {
                    name: 'vendors',
                    chunks: 'initial',
                    test: /node_modules/,
                },
            },
        },
        minimizer: [
            new UglifyJsPlugin({
                cache: true,
                parallel: true,
                sourceMap: true,
            }),
            new OptimizeCSSAssetsPlugin(),
        ],
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: `assets/css/${filenames.css}`,
        }),
        new HtmlWebPackPlugin({
            template: 'src/index.html',
            filename: 'index.html',
            hash: (options.mode === 'production'),
        }),
        new HtmlWebPackPlugin({
            template: 'src/404.html',
            filename: '404.html',
            hash: (options.mode === 'production'),
        }),
        new webpack.ProvidePlugin({
            $: 'jquery',
            jQuery: 'jquery',
            'window.jQuery': 'jquery',
        }),
        new webpack.HashedModuleIdsPlugin(),
        new CopyWebpackPlugin([
            {
                force: true,
                cache: true,
                to: 'assets/icons',
                from: 'src/assets/icons',
            }, {
                force: true,
                cache: true,
                to: 'assets/img',
                from: 'src/assets/img',
            }, {
                force: true,
                cache: true,
                to: 'assets/fonts',
                from: 'src/assets/fonts',
            }, {
                force: true,
                cache: true,
                to: 'assets/fonts',
                from: 'node_modules/font-awesome/fonts',
            },
        ]),
    ],
});

我的package.json文件:

代码语言:javascript
复制
"devDependencies": {
    "@types/file-saver": "^1.3.0",
    "@types/react": "^16.4.7",
    "autoprefixer": "^8.6.5",
    "axios-mock-adapter": "^1.15.0",
    "babel-core": "^6.26.3",
    "babel-eslint": "^8.2.6",
    "babel-jest": "^22.4.4",
    "babel-loader": "^7.1.5",
    "babel-plugin-transform-class-properties": "^6.24.1",
    "babel-preset-airbnb": "^2.5.3",
    "babel-preset-env": "^1.7.0",
    "babel-preset-react": "^6.24.1",
    "babel-preset-stage-2": "^6.24.1",
    "clean-webpack-plugin": "^0.1.19",
    "copy-webpack-plugin": "^4.5.2",
    "cross-env": "^5.2.0",
    "css-hot-loader": "^1.4.1",
    "css-loader": "^0.28.11",
    "eslint": "^4.19.1",
    "eslint-config-airbnb": "^16.1.0",
    "eslint-loader": "^2.1.0",
    "eslint-plugin-import": "^2.13.0",
    "eslint-plugin-jsx-a11y": "^6.1.1",
    "eslint-plugin-react": "^7.10.0",
    "exports-loader": "^0.7.0",
    "file-loader": "^1.1.11",
    "html-loader": "^0.5.5",
    "html-webpack-plugin": "^3.2.0",
    "imports-loader": "^0.8.0",
    "jest": "^22.4.4",
    "jest-cli": "^22.4.4",
    "mini-css-extract-plugin": "^0.4.1",
    "moxios": "^0.4.0",
    "node-sass": "^4.9.2",
    "optimize-css-assets-webpack-plugin": "^4.0.3",
    "popper.js": "^1.14.3",
    "postcss-loader": "^2.1.6",
    "precss": "^3.1.2",
    "react-test-renderer": "^16.4.1",
    "redux-mock-store": "^1.5.3",
    "sass-loader": "^6.0.7",
    "sinon": "^5.1.1",
    "style-loader": "^0.20.3",
    "uglifyjs-webpack-plugin": "^1.2.7",
    "url-loader": "^1.0.1",
    "webpack": "^4.16.2",
    "webpack-cli": "^2.1.5",
    "webpack-dev-server": "^3.1.5"
},
"dependencies": {
    "axios": "^0.18.0",
    "babel-polyfill": "^6.26.0",
    "bootstrap": "^4.1.3",
    "classlist-polyfill": "^1.2.0",
    "core-js": "^2.5.7",
    "element-closest": "^2.0.2",
    "enzyme": "^3.3.0",
    "enzyme-adapter-react-16": "^1.1.1",
    "fastclick": "^1.0.6",
    "file-saver": "^1.3.8",
    "font-awesome": "^4.7.0",
    "font-awesome-filetypes": "^1.2.0",
    "fs": "0.0.1-security",
    "jquery": "^3.3.1",
    "jwt-decode": "^2.2.0",
    "loaders.css": "^0.1.2",
    "lodash": "^4.17.10",
    "mailcheck": "^1.1.1",
    "mobile-drag-drop": "^2.3.0-rc.1",
    "mock-local-storage": "^1.0.5",
    "moment": "^2.22.2",
    "moment-range": "^4.0.1",
    "prop-types": "^15.6.2",
    "query-string": "^6.1.0",
    "raf": "^3.4.0",
    "react": "^16.4.1",
    "react-avatar": "^3.1.2",
    "react-block-ui": "^1.1.1",
    "react-confirm": "^0.1.17",
    "react-datepicker": "^1.5.0",
    "react-dom": "^16.4.1",
    "react-form-with-constraints": "^0.9.2",
    "react-hot-loader": "^4.3.4",
    "react-image": "^1.3.1",
    "react-loaders": "^3.0.1",
    "react-number-format": "^3.5.0",
    "react-redux": "^5.0.7",
    "react-router-dom": "^4.3.1",
    "react-toastify": "^4.1.0",
    "reactstrap": "^5.0.0",
    "redux": "^3.7.2",
    "redux-logger": "^3.0.6",
    "redux-thunk": "^2.3.0",
    "sortablejs": "^1.7.0",
    "vanilla-autofill-event": "^1.0.3",
    "zxcvbn": "^4.4.2"
}
EN

回答 1

Stack Overflow用户

发布于 2020-03-23 23:22:17

开发包的大小并不是什么大问题,因为您在本地机器上工作。重要的是产品捆绑包应该最小化。因为当您的应用程序上线时,它将使用生产包。因此,更小的捆绑包意味着,由您的托管平台提供的服务器将更快地发送生产资产。

在生产模式下,您安装的包将自动剥离您的库在开发过程中包含的许多内容。

代码语言:javascript
复制
**Minification**

最小化的功能包括删除空格、删除注释、删除不需要的分号、缩短十六进制代码长度……

该文件仍然是完全有效的代码。您不会想要阅读它或使用它,但它并没有违反任何规则。浏览器可以读取和使用它,就像它可以使用原始文件一样。

最小化只是改变文本,而文件压缩完全重写文件中的二进制代码。

代码语言:javascript
复制
  const TerserPlugin = require("terser-webpack-plugin");
  optimization:{
  minimize:true //this should be set
  minimizer:[new TerserPluign()]}

在Production中压缩资源的

compression-webpack-plugin默认使用gzip算法。Gzip是标准的,所有的浏览器都能理解。在webpack.prod-client.js中

代码语言:javascript
复制
    `const CompressionPlugin = require("compression-webpack-plugin");

     plugins: [
          new CompressionPlugin(),
        ]`

这将压缩除"jpeg“图像之外的资源文件。因为jpeg已经是压缩文件类型。

我们创建了gzip文件,但是我们还不能加载它们。因为在网络选项卡中,文件的内容类型应该是gzip。我们需要更好的服务器配置。

代码语言:javascript
复制
   npm i express-static-gzip

   const expressStaticGzip = require("express-static-gzip");
   server.use(expressStaticGzip("dist")); //make sure you use this middleware first

我们以gzip格式下载文件,但浏览器使用的是未压缩版本。

Brotli是另一种最初由Google开发的压缩算法,它提供的压缩比gzip更好。

代码语言:javascript
复制
  const BrotliPlugin = require("brotli-webpack-plugin");
  new BrotliPlugin(),
  server.use(expressStaticGzip("dist", { enableBrotli: true, orderPreference: ["br", "gzip"] }));

现在我们有了一组新的文件:原始文件,gz版本和br版本,它们甚至更小。

在构建运行期间,Webpack压缩将一次性压缩您的文件。然后将这些压缩版本保存到磁盘。express-static-gzip可以为那些预编译的版本提供服务,因此您不会在请求点受到gzip的性能影响。如果Node.js直接响应你的HTTP请求,而你没有使用上游代理/负载均衡器,这是很有用的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51552798

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档