Technology moves fast! ⚑ Don't get left behind.🚢 Subscribe to our mailing list to keep up with latest and greatest in open source projects! πŸ†


Subscribe to our mailing list


Statistics on webpack-howto

Number of watchers on Github 9987
Number of open issues 56
Average time to close an issue 12 days
Main language JavaScript
Average time to merge a PR 29 days
Open pull requests 32+
Closed pull requests 4+
Last commit about 3 years ago
Repo Created almost 5 years ago
Repo Last Updated over 1 year ago
Size 469 KB
Organization / Authorpetehunt
Contributors12
Page Updated
Do you use webpack-howto? Leave a review!
View open issues (56)
View webpack-howto activity
View on github
Fresh, new opensource launches πŸš€πŸš€πŸš€
Trendy new open source projects in your inbox! View examples

Subscribe to our mailing list

Evaluating webpack-howto for your project? Score Explanation
Commits Score (?)
Issues & PR Score (?)

webpack-howto

Goal of this guide

This is a cookbook of how to get things done with webpack. This includes most things we use at Instagram and nothing we don't use.

My advice: start with this as your webpack docs, then look at the official docs for clarification.

Prerequisites

  • You know browserify, RequireJS or something similar
  • You see the value in:
    • Bundle splitting
    • Async loading
    • Packaging static assets like images and CSS

1. Why webpack?

  • It's like browserify but can split your app into multiple files. If you have multiple pages in a single-page app, the user only downloads code for just that page. If they go to another page, they don't redownload common code.

  • It often replaces grunt or gulp because it can build and bundle CSS, preprocessed CSS, compile-to-JS languages and images, among other things.

It supports AMD and CommonJS, among other module systems (Angular, ES6). If you don't know what to use, use CommonJS.

2. Webpack for Browserify people

These are equivalent:

browserify main.js > bundle.js
webpack main.js bundle.js

However, webpack is more powerful than Browserify, so you generally want to make a webpack.config.js to keep things organized:

// webpack.config.js
module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'       
  }
};

This is just JS, so feel free to put Real Code in there.

3. How to invoke webpack

Switch to the directory containing webpack.config.js and run:

  • webpack for building once for development
  • webpack -p for building once for production (minification)
  • webpack --watch for continuous incremental build in development (fast!)
  • webpack -d to include source maps

4. Compile-to-JS languages

webpack's equivalent of browserify transforms and RequireJS plugins is a loader. Here's how you can teach webpack to load CoffeeScript and Facebook JSX+ES6 support (you must npm install babel-loader coffee-loader):

See also the babel-loader installation instructions for additional dependencies (tl;dr run npm install babel-core babel-preset-es2015 babel-preset-react).

// webpack.config.js
module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'       
  },
  module: {
    loaders: [
      { test: /\.coffee$/, loader: 'coffee-loader' },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        query: {
          presets: ['es2015', 'react']
        }
      }
    ]
  }
};

To enable requiring files without specifying the extension, you must add a resolve.extensions parameter specifying which files webpack searches for:

// webpack.config.js
module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'       
  },
  module: {
    loaders: [
      { test: /\.coffee$/, loader: 'coffee-loader' },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        query: {
          presets: ['es2015', 'react']
        }
      }
    ]
  },
  resolve: {
    // you can now require('file') instead of require('file.coffee')
    extensions: ['', '.js', '.json', '.coffee'] 
  }
};

5. Stylesheets and images

First update your code to require() your static assets (named as they would with node's require()):

require('./bootstrap.css');
require('./myapp.less');

var img = document.createElement('img');
img.src = require('./glyph.png');

When you require CSS (or less, etc), webpack inlines the CSS as a string inside the JS bundle and require() will insert a <style> tag into the page. When you require images, webpack inlines a URL to the image into the bundle and returns it from require().

But you need to teach webpack to do this (again, with loaders):

// webpack.config.js
module.exports = {
  entry: './main.js',
  output: {
    path: './build', // This is where images AND js will go
    publicPath: 'http://mycdn.com/', // This is used to generate URLs to e.g. images
    filename: 'bundle.js'
  },
  module: {
    loaders: [
      { test: /\.less$/, loader: 'style-loader!css-loader!less-loader' }, // use ! to chain loaders
      { test: /\.css$/, loader: 'style-loader!css-loader' },
      { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' } // inline base64 URLs for <=8k images, direct URLs for the rest
    ]
  }
};

6. Feature flags

We have code we want to gate only to our dev environments (like logging) and our internal dogfooding servers (like unreleased features we're testing with employees). In your code, refer to magic globals:

if (__DEV__) {
  console.warn('Extra logging');
}
// ...
if (__PRERELEASE__) {
  showSecretFeature();
}

Then teach webpack those magic globals:

// webpack.config.js

// definePlugin takes raw strings and inserts them, so you can put strings of JS if you want.
var definePlugin = new webpack.DefinePlugin({
  __DEV__: JSON.stringify(JSON.parse(process.env.BUILD_DEV || 'true')),
  __PRERELEASE__: JSON.stringify(JSON.parse(process.env.BUILD_PRERELEASE || 'false'))
});

module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'       
  },
  plugins: [definePlugin]
};

Then you can build with BUILD_DEV=1 BUILD_PRERELEASE=1 webpack from the console. Note that since webpack -p runs uglify dead-code elimination, anything wrapped in one of these blocks will be stripped out, so you won't leak secret features or strings.

7. Multiple entrypoints

Let's say you have a profile page and a feed page. You don't want to make the user download the code for the feed if they just want the profile. So make multiple bundles: create one main module (called an entrypoint) per page:

// webpack.config.js
module.exports = {
  entry: {
    Profile: './profile.js',
    Feed: './feed.js'
  },
  output: {
    path: 'build',
    filename: '[name].js' // Template based on keys in entry above
  }
};

For profile, insert <script src="build/Profile.js"></script> into your page. Do a similar thing for feed.

8. Optimizing common code

Feed and Profile share a lot in common (like React and the common stylesheets and components). webpack can figure out what they have in common and make a shared bundle that can be cached between pages:

// webpack.config.js

var webpack = require('webpack');

var commonsPlugin =
  new webpack.optimize.CommonsChunkPlugin('common.js');

module.exports = {
  entry: {
    Profile: './profile.js',
    Feed: './feed.js'
  },
  output: {
    path: 'build',
    filename: '[name].js' // Template based on keys in entry above
  },
  plugins: [commonsPlugin]
};

Add <script src="build/common.js"></script> before the script tag you added in the previous step and enjoy the free caching.

9. Async loading

CommonJS is synchronous but webpack provides a way to asynchronously specify dependencies. This is useful for client-side routers, where you want the router on every page, but you don't want to have to download features until you actually need them.

Specify the split point where you want to load asynchronously. For example:

if (window.location.pathname === '/feed') {
  showLoadingState();
  require.ensure([], function() { // this syntax is weird but it works
    hideLoadingState();
    require('./feed').show(); // when this function is called, the module is guaranteed to be synchronously available.
  });
} else if (window.location.pathname === '/profile') {
  showLoadingState();
  require.ensure([], function() {
    hideLoadingState();
    require('./profile').show();
  });
}

webpack will do the rest and generate extra chunk files and load them for you.

webpack will assume that those files are in your root directory when you load then into a html script tag for example. You can use output.publicPath to configure that.

// webpack.config.js
output: {
    path: "/home/proj/public/assets", //path to where webpack will build your stuff
    publicPath: "/assets/" //path that will be considered when requiring your files
}

Additional resources

Take a look at a real world example on how a successful team is leveraging webpack: http://youtu.be/VkTCL6Nqm6Y This is Pete Hunt at OSCon talking about webpack at Instagram.com

FAQ

webpack doesn't seem modular

webpack is extremely modular. What makes webpack great is that it lets plugins inject themselves into more places in the build process when compared to alternatives like browserify and requirejs. Many things that may seem built into the core are just plugins that are loaded by default and can be overridden (i.e. the CommonJS require() parser).

webpack-howto open issues Ask a question     (View All Issues)
  • over 2 years CSS files: Is there a difference between require() and import?
  • almost 3 years npm start introduce error
  • about 3 years Multiple entrypoints: what about components?
  • about 3 years Feature flags for different entry points
  • about 3 years webpack.optimize.CommonsChunkPlugin optimizes common stylesheets to an unexpected file name
  • about 3 years Capitalisation significance?
  • over 3 years Error in main.js when running: Module build failed: ReferenceError: [BABEL]
  • over 3 years Worth adding requirement of having webpack installed?
  • over 3 years How to use webpack async loading with Ionic 2 application ?
  • over 3 years Loaders: worth discussing "-loader" suffix?
  • over 3 years Best practices for depenendencies vs devDependencies
  • over 3 years Add description and link
  • over 3 years How to inject scripts to index html file in production?
  • over 3 years Require a image in CSS
  • almost 4 years Has someone translated this article(webpack-howto) into Chinese?
  • almost 4 years "Module not found: Error: Cannot resolve module" for react-router and react
  • about 4 years how do we load json
  • about 4 years React server-side rendering
  • about 4 years Feature flags always returns TRUE
  • about 4 years Require stylesheet
  • over 4 years How do I use webpack with jest?
  • over 4 years How to compile to memory
  • over 4 years Multiple entry-points with React Router
  • over 4 years Suggest updating readme regarding browserify, it can create multiple bundles but requires running twice
webpack-howto open pull requests (View All Pulls)
  • Add require parameter to `require.ensure` callback
  • Basic guide to aliasing and ignoring modules
  • Using ExtendedDefinePlugin
  • Add to declare a webpack variable
  • Use ES6 classes, modules. Minor edits to the docs. Flattened director…
  • Install babel-loader & coffee-loader as dev dependencies
  • Clarifies example by adding webpack as requirement
  • Fixed typo in Async loading section from `then` to `them`.
  • Fixes #30
  • replace jsx-loader to babel-loader
  • modify package.json
  • Suggesting additions to the readme
  • Added Turkish translation
  • Fix README-zh.md
  • fix typos
  • fix typo
  • clean up README.md a bit
  • added --bail option
  • Fix build errors described in #64
  • add Korean translation
  • fix typo in Chinese version
  • fix some translation errors
  • Fix typo: Css -> CSS
  • just for better πŸš€ πŸš€ πŸš€
  • Update README-zh.md
  • Update README-zh.md
  • Added pt-br translation
  • then -> them
  • Greek translation
  • Update to webpack 2.x
  • html-webpack-plugin
  • Update README-zh.md
webpack-howto list of languages used
Other projects in JavaScript