1

So I was able to reduce my bundle size from 13mb to 6.81mb

I did some optimizations like proper production configurations, optimizing libraries like lodash and replacing momentjs with date-fns.

Now got to a point where most packages do not exceed 1mb and most of them are dependencies installed by npm.

Using webpack-bundle-analyzer here is what my bundle looks like now

bundle analyzed

So do you guys think I can do something more to reduce the bundle size? Maybe remove jquery and go vanilla js? But then it's only 1mb... Is there something I can do to significantly optimize the size?

Some more details if you'd like

This is how do my build NODE_ENV=production webpack

const webpack = require('webpack')
const path = require('path')
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const OptimizeCSSAssets = require('optimize-css-assets-webpack-plugin')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin')

const config = {
  entry: ['babel-polyfill', './src/index.js'],
  output: {
    path: path.resolve(__dirname, './public'),
    filename: './output.js'
  },
  resolve: {
    extensions: ['.js', '.jsx', '.json', '.scss', '.css', '.jpeg', '.jpg', '.gif', '.png'], // Automatically resolve certain extensions
    alias: { // Create Aliases
      images: path.resolve(__dirname, 'src/assets/images')
    }
  },
  module: {
    rules: [
      {
        test: /\.js$/, // files ending with js
        exclude: /node-modules/,
        loader: 'babel-loader'
      },
      {
        test: /\.scss$/,
        use: ['css-hot-loader', 'style-loader', 'css-loader', 'sass-loader', 'postcss-loader']
      },
      {
        test: /\.jsx$/, // files ending with js
        exclude: /node-modules/,
        loader: 'babel-loader'
      },
      {
        test: /\.(jpe?g|png|gif|svg)$/i,
        loaders: [
          'file-loader?context=src/assets/images/&name=images/[path][name].[ext]',
          {
            loader: 'image-webpack-loader',
            query: {
              mozjpeg: {
                progressive: true
              },
              gifsicle: {
                interlaced: false
              },
              optipng: {
                optimizationLevel: 4
              },
              pngquant: {
                quality: '75-90',
                speed: 3
              }
            }
          }
        ],
        exclude: /node_modules/,
        include: __dirname
      }
    ]
  },
  plugins: [
    new ExtractTextWebpackPlugin('styles.css'),
    new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery'
    }),
    // make sure this one with urls is always the last one
    new webpack.DefinePlugin({
      DDP_URL: getDDPUrl(),
      REST_URL: getRESTUrl()
    }),
    new LodashModuleReplacementPlugin({collections: true})
  ],
  devServer: {
    contentBase: path.resolve(__dirname, './public'), // a directory or URL to serve HTML from
    historyApiFallback: true, // fallback to /index.html for single page applications
    inline: true, // inline mode, (set false to disable including client scripts (like live reload))
    open: true // open default browser while launching
  },
  devtool: 'eval-source-map' // enable devtool for bettet debugging experience
}

module.exports = config

if (process.env.NODE_ENV === 'production') {
  module.exports.plugins.push(
    // https://reactjs.org/docs/optimizing-performance.html#webpack
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production')
    }),
    new webpack.optimize.UglifyJsPlugin(),
    new OptimizeCSSAssets(),
    new BundleAnalyzerPlugin()
  )
}

function getDDPUrl () {
  const local = 'ws://localhost:3000/websocket'
  const prod = 'produrl/websocket'
  let url = local
  if (process.env.NODE_ENV === 'production') url = prod
  // https://webpack.js.org/plugins/define-plugin/
  // Note that because the plugin does a direct text replacement,
  // the value given to it must include actual quotes inside of the string itself.
  // Typically, this is done either with either alternate quotes,
  // such as '"production"', or by using JSON.stringify('production').
  return JSON.stringify(url)
}

function getRESTUrl () {
  const local = 'http://localhost:3000'
  const prod = 'produrl'
  let url = local
  if (process.env.NODE_ENV === 'production') url = prod
  // https://webpack.js.org/plugins/define-plugin/
  // Note that because the plugin does a direct text replacement,
  // the value given to it must include actual quotes inside of the string itself.
  // Typically, this is done either with either alternate quotes,
  // such as '"production"', or by using JSON.stringify('production').
  return JSON.stringify(url)
}

7
  • Are you running webpack -p right? Are you using uglifyjs plugin to remove the comments? Commented Mar 12, 2018 at 13:26
  • @The.Bear yup, I add my config and the command I use for more details. Commented Mar 12, 2018 at 13:38
  • 1
    I'll try adding {comments: false} now. As for production yes I am sure it is entering production. Commented Mar 12, 2018 at 14:09
  • 1
    @The.Bear so I added the console.log it is entering production. Passing {output: {comments: false}} changed nothing. If I pass it as true then the bundle size just increases by 0.01mb Commented Mar 12, 2018 at 14:14
  • 1
    @The.Bear incredible! disabling source maps reduced bundle size from 6mb to just 900kb! Answer the question so that I'll accept it. Commented Mar 13, 2018 at 8:36

1 Answer 1

1

Your problem is that you are including the devtool: 'eval-source-map' even when you run webpack production command. This will include the sourcemaps inside your final bundle. So, to remove it, you can do the following:

var config = {
  //... you config here
  // Remove devtool and devServer server options from here
}

if(process.env.NODE_ENV === 'production') { //Prod
   config.plugins.push(
       new webpack.DefinePlugin({'process.env.NODE_ENV': JSON.stringify('production')}),
       new OptimizeCSSAssets(),
       /* The comments: false will remove the license comments of your libs
       and you will obtain a real single line file as output */
       new webpack.optimize.UglifyJsPlugin({output: {comments: false}}),
   );
} else { //Dev
    config.devServer = {
        contentBase: path.resolve(__dirname, './public'), 
        historyApiFallback: true, 
        inline: true,
        open: true
    };
    config.devtool = 'eval-source-map'; 
}

module.exports = config
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.