Widget webpack optimization

by Troy Rhinehart

What is webpack?



"Webpack is a bundler for modules. The main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset


why we're using it


  • NPM Modules 
  • Babel/ES6 
  • LESS/PostCSS 
  • Assets 
  • Uglify/Compress 
  • Plugins/Loaders 
  • Build process 
  • Chunking/Hashing
  • Hot reload





size does matter

guac-widget-header




25kB

guac-widget-footer




542kB



WTH?


guac-widget-contact




912kB

guac-widget-about




2.12MB


what I found



  • Dependency issues
  • Build issues
  • Webpack config issues
  • Module Resolving Issues

peer dependencies



 
"peerDependencies": {
"@wsb/guac-widget-core": "^0.10.12",
"fluxible-addons-connect-props": "^0.1.1",
"keymirror": "^0.1.1",
"react": "^0.14.2"
}

dev dependencies




everything

actual dependencies




nothing

build issues


 
c:\git\projects\vnext\guac-widget-about>npm run pack

> @wsb/guac-widget-about@2.0.17 pack c:\git\projects\vnext\guac-widget-about
> webpack --verbose

 
c:\git\projects\vnext\guac-widget-about>npm run pack

> @wsb/guac-widget-about@2.0.18 pack c:\git\projects\vnext\guac-widget-about
> webpack -p

webpack cli


webpack 1.12.14
Usage: https://webpack.github.io/docs/cli.html

Options:
--help, -h, -?
--config
--context
--entry
--module-bind
--module-bind-post
--module-bind-pre
--output-path
--output-file
--output-chunk-file
--output-named-chunk-file
--output-source-map-file
--output-public-path
--output-jsonp-function
--output-pathinfo
--output-library
--output-library-target
--records-input-path
--records-output-path
--records-path
--define
--target
--cache
--watch, -w
--watch which closes when stdin ends
--watch-aggregate-timeout
--watch-poll
--hot
--debug
--devtool
--progress
--resolve-alias
--resolve-loader-alias
--optimize-max-chunks
--optimize-min-chunk-size
--optimize-minimize
--optimize-occurence-order
--optimize-dedupe
--prefetch
--provide
--labeled-modules
--plugin
--bail
--profile
-d (--debug --devtool sourcemap)
--output-pathinfo
-p (--optimize-minimize)
--json, -j
--colors, -c
--sort-modules-by
--sort-chunks-by
--sort-assets-by
--hide-modules
--display-exclude
--display-modules
--display-chunks
--display-error-details
--display-origins
--display-cached
--display-cached-assets
--display-reasons, --verbose, -v

webpack config


var webpack = require('webpack');

module.exports = {
entry: {
manifest: './src/manifest',
about1: './src/about1/',
about2: './src/about2/',
about3: './src/about3/'
},
externals: {
'react': 'commonjs react',
'@wsb/guac-widget-core': 'commonjs @wsb/guac-widget-core',
'@wsb/guac-dials': 'commonjs @wsb/guac-dials',
'fluxible-addons-connect-props': 'commonjs fluxible-addons-connect-props',
'lodash': 'commonjs lodash',
'keymirror': 'commonjs keymirror'
},
output: {
libraryTarget: 'umd',
path: './lib/',
filename: '[name].js'
},
module: {
loaders: [{ test: /\.jsx?$/, loader: 'babel', exclude: /node_modules/ }]
},
resolve: {
extensions: ['', '.js', '.jsx']
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production')
}
}),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
output: {
comments: false
}
})
]
};

externals


 
externals: {
'react': 'commonjs react',
'@wsb/guac-widget-core': 'commonjs @wsb/guac-widget-core',
'@wsb/guac-dials': 'commonjs @wsb/guac-dials',
'fluxible-addons-connect-props': 'commonjs fluxible-addons-connect-props',
'lodash': 'commonjs lodash',
'keymirror': 'commonjs keymirror'
}

plugins


plugins: [
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production')
}
}),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
output: {
comments: false
}
})
]

dedupe plugin

"Search for equal or similar files and deduplicate them in the output. This comes with some overhead for the entry chunk, but can reduce file size effectively.

This doesn’t change the module semantics at all. Don’t expect to solve problems with multiple module instance. They won’t be one instance after deduplication.

Note: Don’t use it in watch mode. Only for production builds."


Occurrence Order Plugin

"Assign the module and chunk ids by occurrence count. Ids that are used often get lower (shorter) ids. This make ids predictable, reduces to total file size and is recommended.  preferEntry (boolean) give entry chunks higher priority. This make entry chunks smaller but increases the overall size. (recommended)"


module resolving issues


import connectPropsToStores from 'fluxible-addons-connect-props/connectPropsToStores';
import NestedProp from '@wsb/guac-widget-core/lib/utils/NestedPropConnector';
import Website from '@wsb/guac-widget-core/lib/utils/WebsitePropConnector';
import Config from '@wsb/guac-widget-core/lib/utils/ConfigPropConnector';
import { NEUTRAL } from '@wsb/guac-widget-core/lib/constants/colorPackCategories';

 
import { utils, constants } from '@wsb/guac-widget-core';
import { connectPropsToStores } from 'fluxible-addons-connect-props';

const { NestedPropConnector: NestedProp, WebsitePropConnector: Website, ConfigPropConnector: Config } = utils;
const { colorPackCategories: { NEUTRAL } } = constants;





results

guac-widget-header



25kb

5.54kb

-77.84%


guac-widget-footer



542kb

3.86kb

-99.29%

guac-widget-contact



912kb

193kb

-78.84%

guac-widget-about



2.12MB

20kb

-99.06%

future optimizations



  • Move publish dependencies to widgets
  • Put all entries into a single entry
  • Split out bootstrapped raw dependency
  • Push widgets to Ceph/CDN



Questions?



thank you!

Widget Webpack Optimizations

By gingur

Widget Webpack Optimizations

  • 74