Eastman
@Eastman
Frontend's Zen

Какой у вас размер bundle.min.js в React.js приложении или Померяемся React.js билдами?

Есть небольшое SPA на React.js. Ничего сверх, все как у людей - router, flux, material-ui, больше десятка компонентов. Собирается это все, конечно же, с помощью Webpack. На выходе получается минифицированный файл bundle.js размером 603kb. O_o
Так должно быть? Как оптимизировать/уменьшить файл сборки? Куда обращать внимание?
Конфигурации проекта ниже.

package.json
...
  "dependencies": {
    "events": "^1.1.1",
    "flux": "^2.1.1",
    "keymirror": "^0.1.1",
    "less": "^2.7.1",
    "material-ui": "^0.15.2",
    "react": "^15.2.1",
    "react-dom": "^15.2.1",
    "react-router": "^2.6.0",
    "react-tap-event-plugin": "^1.0.0"
  },
  "devDependencies": {
    "autoprefixer-loader": "*",
    "babel-core": "^6.9.1",
    "babel-loader": "^6.2.4",
    "babel-preset-es2015": "^6.9.0",
    "babel-preset-react": "^6.5.0",
    "babel-preset-stage-0": "^6.5.0",
    "css-loader": "^0.22.0",
    "extract-text-webpack-plugin": "^1.0.1",
    "file-loader": "^0.8.5",
    "image-webpack-loader": "^1.8.0",
    "json-loader": "^0.5.4",
    "less-loader": "^2.2.2",
    "react-hot-loader": "3.0.0-beta.2",
    "style-loader": "^0.13.0",
    "url-loader": "^0.5.6",
    "webpack": "^1.13.1",
    "webpack-dev-server": "1.14.0"
  }
...


webpack.config,js
var webpack = require('webpack');

const NODE_ENV = process.env.NODE_ENV || 'development';
const NODE_HOST = process.env.NODE_HOST || '0.0.0.0';
const NODE_PORT = process.env.NODE_PORT || 8090;

const ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
    entry: getEntrySources(['./src/main.js']),
    output: {
        path: __dirname + '/public/build',
        publicPath: "/build/",
        filename: "bundle.js"
    },
    module: {
        loaders: [
            {
                test: /\.css$/,
                loader: (process.env.NODE_ENV === "production")
                            ? ExtractTextPlugin.extract('style', 'css!autoprefixer')
                            : "style-loader!css-loader!autoprefixer-loader",
                exclude: [/node_modules/, /public/]
            },
            {
                test: /\.less$/,
                loader: (process.env.NODE_ENV === "production")
                            ? ExtractTextPlugin.extract('style', 'css!less!autoprefixer')
                            : "style-loader!css-loader!autoprefixer-loader!less",
                exclude: [/node_modules/, /public/]
            },
            {
                test: /\.(jpe?g|png|gif|svg|ico)$/i,
                loaders: [
                    'file?name=[sha512:hash:base64:7].[ext]',
                    'image-webpack?progressive=true&optimizationLevel=7&interlaced=true'
                ],
                exclude: [/node_modules/, /public/, /src\/fonts/]
            },
            {
                test   : /\.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/,
                loader : 'file?name=[name].[ext]',
                exclude: [/node_modules/, /public/, /src\/img/]
            },
            {
                test: /\.json$/,
                loader: "json-loader"
            },
            {
                test: /\.jsx?$/,
                exclude: /node_modules/,
                loader: 'babel',
                query: {
                    presets: ["es2015", "stage-0", "react"],
                    plugins: (process.env.NODE_ENV === "production")
                             ? []
                             : ["react-hot-loader/babel"]

                }
            }
        ]
    },

    devServer: {
        colors: true,
        historyApiFallback: true,
        inline: false,
        contentBase: __dirname + '/public',
        port: NODE_PORT,
        hot: true
    },

    plugins: [
        new ExtractTextPlugin('bundle.css', {
            allChunks: true,
            disable: process.env.NODE_ENV == 'development'
        }),
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoErrorsPlugin()
    ]
};

if (NODE_ENV == 'production') {
    module.exports.plugins.push(
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings:     false,
                drop_console: true,
                unsafe:       true
            }
        })
    );
}

function getEntrySources(sources) {
    if (process.env.NODE_ENV !== 'production') {
        sources.unshift('react-hot-loader/patch');
        sources.unshift(`webpack-dev-server/client?http://${NODE_HOST}:${NODE_PORT}`);
        sources.unshift('webpack/hot/only-dev-server');
    }

    return sources;
}


Результат после запуска аналайзера webpack --json | webpack-bundle-size-analyzer
react: 658.9 KB (35.3%)
material-ui: 404.68 KB (21.7%)
lodash: 133.82 KB (7.18%)
react-router: 101.96 KB (5.47%)
sockjs-client: 98.54 KB (5.29%)
inline-style-prefixer: 54.42 KB (2.92%)
history: 49.02 KB (2.63%)
  warning: 1.76 KB (3.60%)
  <self>: 47.26 KB (96.4%)
json3: 42.28 KB (2.27%)
url: 36.04 KB (1.93%)
  punycode: 14.31 KB (39.7%)
  <self>: 21.74 KB (60.3%)
fbjs: 33.59 KB (1.80%)
react-proxy: 21.75 KB (1.17%)
bowser: 15.71 KB (0.843%)
react-tap-event-plugin: 9.95 KB (0.534%)
  fbjs: 2.56 KB (25.7%)
  <self>: 7.4 KB (74.3%)
url-parse: 9.44 KB (0.506%)
flux: 8.93 KB (0.479%)
  fbjs: 1.47 KB (16.5%)
  <self>: 7.46 KB (83.5%)
recompose: 8.59 KB (0.461%)
events: 8.13 KB (0.436%)
debug: 7.67 KB (0.412%)
style-loader: 6.99 KB (0.375%)
react-hot-loader: 5.69 KB (0.305%)
react-event-listener: 5.17 KB (0.278%)
querystring: 4.51 KB (0.242%)
node-libs-browser: 4.4 KB (0.236%)
  process: 4.4 KB (100%)
  <self>: 0 B (0.00%)
deep-equal: 3.8 KB (0.204%)
webpack: 3.36 KB (0.180%)
keycode: 2.7 KB (0.145%)
webpack-dev-server: 2.42 KB (0.130%)
ms: 2.28 KB (0.122%)
object-assign: 1.95 KB (0.104%)
warning: 1.76 KB (0.0947%)
invariant: 1.48 KB (0.0794%)
css-loader: 1.47 KB (0.0789%)
query-string: 1.45 KB (0.0776%)
keymirror: 1.38 KB (0.0740%)
hoist-non-react-statics: 1.35 KB (0.0727%)
querystringify: 1.27 KB (0.0682%)
requires-port: 753 B (0.0394%)
inherits: 672 B (0.0352%)
simple-assign: 281 B (0.0147%)
hyphenate-style-name: 271 B (0.0142%)
global: 243 B (0.0127%)
strict-uri-encode: 182 B (0.00953%)
strip-ansi: 161 B (0.00843%)
ansi-regex: 135 B (0.00707%)
react-dom: 63 B (0.00330%)
react-addons-create-fragment: 59 B (0.00309%)
react-addons-transition-group: 59 B (0.00309%)
<self>: 104.54 KB (5.61%)
  • Вопрос задан
  • 4284 просмотра
Пригласить эксперта
Ответы на вопрос 1
Задался тем же вопросом. Проанализировал сборку, там было много конструкций типа:
if(NODE_ENV !== "prodi=uction")...
Совершенно очевидно, что такого мусора быть не должно.
Поправил плагин webpack DefinePlugin, написав его таким образом:
new webpack.DefinePlugin({
        'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
    }),

(раньше был просто NODE_ENV': JSON.stringify(process.env.NODE_ENV))
Вес сборки уменьшился в 2 раза!
А у Вас этот плагин вообще не подключен.

П.С. Может, кому-то еще пригодится ответ.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы