Skip to content

Instantly share code, notes, and snippets.

@tusharf5
Last active February 11, 2017 06:41
Show Gist options
  • Save tusharf5/8c87d4b519944dea7c888d30677cc042 to your computer and use it in GitHub Desktop.
Save tusharf5/8c87d4b519944dea7c888d30677cc042 to your computer and use it in GitHub Desktop.

entry

webpack creates a graph of all of your application's dependencies. The starting point of this graph is known as an entry point. The entry point tells webpack where to start and follows the graph of dependencies to know what to bundle. You can think of your application's entry point as the contextual root or the first file to kick off your app. Simple rule: one entry point per HTML page. SPA: one entry point, MPA: multiple entry points. Entry Points are also called chunks

entry: {
  home: "./home.js",
  about: "./about.js",
  contact: "./contact.js"
}

This will bundle all the files into three different files home.bundle.js, about.bundle.js, contact.bundle.js

If the entry file property is an array it will bundle all the array elements into one file name

entry: {
   home: ['./app.js','./vendor.js','./ext.js']
       }

This will bundle all the files into one home.bundle.js


context

By default the current directory is used, but it's recommended to pass a value in your configuration.

context: path.resolve(__dirname, "app")

Starting from the context folder It looks for entry filenames and reads the content. Every import (ES6) or require() (Node) dependency it finds as it parses the code, it bundles for the final build. It then searches those dependencies, and those dependencies’ dependencies, until it reaches the very end of the “tree”—only bundling what it needed to, and nothing else.


output

Once you've bundled all of your assets together, we still need to tell webpack where to bundle our application. The webpack output property describes to webpack how to treat bundled code.

  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js'
  }

Using entry name

filename: "[name].bundle.js"

Using internal chunk id

filename: "[id].bundle.js"

Using the unique hash generated for every build

filename: "[name].[hash].bundle.js"

Using hashes based on each chunks' content

filename: "[chunkhash].bundle.js"

Don’t use [chunkhash] in development since this will increase compilation time. Separate development and production configs and use [name].js for development and [name].[chunkhash].js in production.


rules

Loaders have two purposes in your webpack config.

1.Identify what files should be transformed by a certain loader. (test property) 2.Transform that file so that it can be added to your dependency graph (and eventually your bundle). (use property) 3.Webpack's loaders are always evaluated from right to left and from bottom to top 4.enforce can be set to either pre or post to push processing either before or after other loaders.

  module: {
    rules: [
      {
      // Match files against RegExp. This accepts
      // a function too.
      test: /\.(js|jsx)$/,
        
     // Restrict matching to a directory. This
     // also accepts an array of paths.
     //
     // Although optional, I prefer to set this for
     // JavaScript source as it helps with
     // performance and keeps the configuration cleaner.
     //
     // This accepts an array or a function too. The
     // same applies to `exclude` as well.
      include: path.join(__dirname, 'app'),
      /*
        exclude(path) {
          // You can perform more complicated checks
          // through functions if you want.
          return path.match(/node_modules/);
        },
      */
            
      // Apply loaders the matched files. These need to
      // be installed separately. In this case our
      // project would need *babel-loader*. This
      // accepts an array of loaders as well and
      // more forms are possible as discussed below.
      use: 'babel-loader',

      }
    ]
  }

To use more than one loader and to pass query params

use: [
    {
      loader: 'babel-loader',
      options: {
        cacheDirectory: true,
        presets: ['react', 'es2015'],
      },
    },
    // Add more loaders here
  ]

In the configuration above we have defined a rules property for a single module with two required properties: test, and use. This tells webpack's compiler the following:

Hey webpack compiler, when you come across a path that resolves to a '.js' or '.jsx' file inside of a require()/import statement, use the babel-loader to transform it before you add it to the bundle".

Given webpack 2 forbids arbitrary root level configuration, you have to use LoaderOptionsPlugin to manage it. The plugin exists for legacy compatibility and may disappear in a future release.

plugins: [
    new webpack.LoaderOptionsPlugin({
      sassLoader: {
        includePaths: [
          path.join(__dirname, 'style'),
        ],
      },
    }),
  ]

commonschunk plugin

This is important as you want to cache the non-updating humongous node_module libraries only once on the client's browser. Commons Chunk is smart. It will detect a piece of code which is used twice (minChunks) in your app dependencies and put it to a separate file which will not get updated unless it is changed. name is the name of entry chunk that you have provided and you can pass an array to it too

plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: 'commons',
      filename: 'commons.bundle.js',
      minChunks: 2,
    }),
  ]

This is cool if you don't want much headache but this is configurable which means you can get the most out of it. You can specify in your entry files which files do you want to bundle as common bundle. Things are in your control now.

new webpack.optimize.CommonsChunkPlugin({
                name: ['vendor', 'manifest'],
                minChunks: function (module) {
                   // this assumes your vendor imports exist in the node_modules directory
                   return module.context && module.context.indexOf('node_modules') !== -1;
                }
            })
        ]

You can do is write all the node_modules in a vendor chunk as array but that takes up a lot of time so the following code helps extracting that automatically. We can even extract out very frequently updating modules into another bundle to make sure not everything is downloaded when even a single module updates. Will add more...

 // Extract all 3rd party modules into a separate 'vendor' chunk
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks: ({ resource }) => /node_modules/.test(resource),
    }),
    
    // Generate a 'manifest' chunk to be inlined in the HTML template
    new webpack.optimize.CommonsChunkPlugin('manifest'),

    // Need this plugin for deterministic hashing
    // until this issue is resolved: https://github.com/webpack/webpack/issues/1315
    // for more info: https://webpack.js.org/how-to/cache/
    new WebpackMd5Hash(),
    
    // Creates a 'webpack-assets.json' file with all of the
    // generated chunk names so you can reference them
    new AssetsPlugin()
  ]

eslint

Skip build Dir .eslintignore

build/*

Define .eslintrc.js file We'll ensure that ESLint gets executed before anything else using the enforce field

 module: {
      rules: [
        {
          test: /\.js$/,
          enforce: 'pre',
          loader: 'eslint-loader',
          options: {
            emitWarning: true,
          },
        },
      ],
    }
    

Webpack does not allow arbitrary fields at configuration root level anymore. to access all functionality of the eslint-loader, you'll need to use LoaderOptionsPlugin as below.

 plugins: [
    new webpack.LoaderOptionsPlugin({
      options: {
        eslint: {
          // Fail only on errors
          failOnWarning: false,
          failOnError: true,

          // Disable/enable autofix
          fix: false,

          // Output to Jenkins compatible XML
          outputReport: {
            filePath: 'checkstyle.xml',
            formatter: require('eslint/lib/formatters/checkstyle'),
          },
        },
      },
    }),
  ]

Clean Build Dir

use clean-webpack-plugin to clean the build dir on each new build


Long Term Caching with known Issues


Manifesting files

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment