All notes
Webpack

Installation


# Install only webpack
npm install -D webpack webpack-cli

npm install -D babel-loader babel-core babel-preset-env babel-preset-react webpack

Import libraries

JQuery

JQuery not being included into bundle.js generated by WebPack.



import $ from 'jquery';
window.jQuery = $;
window.$ = $;

// or add to webpack

const webpack = require('webpack'); //to access built-in plugins
new webpack.ProvidePlugin({
  $: 'jquery',
  jQuery: 'jquery'
})

Commandline

webpack


webpack --progress --colors --watch ./entry.js bundle.js

# Without any webpack.config.js, specify entry and output directly:
# webpack entry [more entry...] output
./node_modules/.bin/webpack src/index.js dist/bundle.js

# Development shortcut -d. Equals to --debug --devtool source-map --output-pathinfo
# Production shortcut -p. Equals to --optimize-minimize --optimize-occurrence-order. wcfNote: it's not --progress!

# Watch mode --watch, -w
# Display options --progress

# Configuration file --config example.config.js. webpack.config.js is the default.

# --bail
#  Report the first error as a hard error instead of tolerating it.

webpack.config.js:


var HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');

module.exports = {
  entry: {
    app: "./index.js",
    vendor: [ 'react', 'react-dom' ]
  },

  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: "bundle.js"
  },

  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          'css-loader'
        ]
      }
    ]
  },

  plugins: [
    new HtmlWebpackPlugin({
      title: 'Output Management',
      favicon: './favicon.ico'
    }),
    new webpack.HotModuleReplacementPlugin()
  ],

  devServer: {
    hot: true, // Tell the dev-server we're using HMR
    contentBase: path.resolve(__dirname, 'dist'),
    publicPath: '/'
  }
};

Debugging

Webpack Bundle Analyzer is started at
http://localhost:8888/

webpack-dev-server

webpack.github.io: webpack dev server.


# webpack.config.js

var path = require("path");
module.exports = {
  entry: {
    app: [
      "webpack-dev-server/client?http://localhost:8080/",
      "./app/main.js"
    ]
  },
  output: {
    path: path.resolve(__dirname, "build"), // Build path.
    publicPath: "/assets", // Mount path for dev server.
    filename: "bundle.js"
  }
};

npm install -D webpack webpack-dev-server

# --no-info: suppress boring information.
# --host, --port
# --open: opens the url in default browser (for webpack-dev-server versions > 2.0).

# This binds a small express server on localhost:8080 which serves your static assets as well as the bundle.
webpack-dev-server --progress --colors --open --compress --no-info --content-base build/

# Then goto:
# http://localhost:8080/ for inline automatic refresh mode (must add a small webpack-dev-server client entry to the bundle).
# http://localhost:8080/webpack-dev-server/ for iframe automatic refersh mode.

# --inline: embed the webpack-dev-server runtime into the bundle.
# --hot: adds the HotModuleReplacementPlugin and switch the server to hot mode.
# --hot --inline also adds the "webpack/hot/dev-server" entry.

# --https: serves webpack-dev-server over HTTPS Protocol. Includes a self-signed certificate that is used when serving the requests.
# --cert, --cacert, --key: Paths the certificate files.

# --client-log-level: controls the console log messages shown in the browser. Use error, warning, info or none.

publicPath

The modified bundle is served from memory at the relative path specified in publicPath, e.g. "localhost:8080/assets/bundle.js". It will not be written to your configured output directory.

Configuration

devtool

webpack.js.org.

This option controls if and how source maps are generated.

For development you typically want fast Source Maps at the cost of bundle size, but for production you want separate Source Maps that are accurate and support minimizing.

Development

module

github.io: webpack configuration module.



// test: A condition that must be met
// exclude: A condition that must not be met
// include: An array of paths or files where the imported files will be transformed by the loader
// loader: A string of “!” separated loaders

module: {
  loaders: [
    {
      // "test" is commonly used to match the file extension
      test: /\.jsx$/,

      // "include" is commonly used to match the directories
      include: [
        path.resolve(__dirname, "app/src"),
        path.resolve(__dirname, "app/test")
      ],

      // "exclude" should be used to exclude exceptions
      // try to prefer "include" when possible

      // the "loader"
      loader: "babel-loader" // or "babel" because webpack adds the '-loader' automatically
    }
  ]
}

Loaders

github.io: webpack loaders.


// Notice the ! syntax separating the loader from the module path.
// When chaining loaders, they are applied right to left (from the file, back): less - css - style.
require("style-loader!css-loader!less-loader!./my-styles.less");

// Loaders can accept query parameters:
require("loader?with=parameter!./file");

All kinds of loaders

file-loader: load files into the output directory, and returns the public URI of the file. By default the filename of the resulting file is the MD5 hash of the file's contents with the original extension of the required resource.

url-loader: transforms files into base64 URIs. It works like the file-loader, but can return a DataURL if the file is smaller than a byte limit.


//---------- file-loader

// bundle file
import img from './file.png'

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpg|gif)$/,
        use: [
          {
            loader: 'file-loader',
            options: {}
          }
        ]
      }
    ]
  }
}
// This will emit file.png as a file in the output directory.

//---------- url-loader

import img from './image.png'

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 8192
            }
          }
        ]
      }
    ]
  }
}

//---------- css-loader

import css from 'file.css';

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [ 'style-loader', 'css-loader' ]
      }
    ]
  }
}

//----- Or load to string:

{
   test: /\.css$/,
   use: [
     'to-string-loader',
     'css-loader'
   ]
}

// or
const css = require('./test.css').toString();
console.log(css); // {String}

// or extract CSS as a plain string resource
{
   test: /\.css$/,
   use: [
     'handlebars-loader', // handlebars loader expects raw resource string
     'extract-loader',
     'css-loader'
   ]
}

Plugins

HardSourceWebpackPlugin

github.com.


plugins: [
  new HardSourceWebpackPlugin()
]

Invalidate cache


rm -rf node_modules/.cache/hard-source

HtmlWebpackPlugin

The HtmlWebpackPlugin simplifies creation of HTML files to serve your webpack bundles. This is especially useful for webpack bundles that include a hash in the filename (e.g. bundle.xxxx.js) which changes every compilation.



var HtmlWebpackPlugin = require('html-webpack-plugin');
var path = require('path');
var webpackConfig = {
  entry: 'index.js',
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'index_bundle.js'
  },
  plugins: [new HtmlWebpackPlugin()]
};

// This will generate a file dist/index.html containing the following:
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>webpack App</title>
  </head>
  <body>
    <script src="index_bundle.js"></script>
  </body>
</html>

ProvidePlugin

Automatically load modules instead of having to import or require them everywhere.



const webpack = require('webpack'); //to access built-in plugins
plugins: [
  new webpack.ProvidePlugin({
    identifier: 'module1',
    // ...
  })
]

// or
new webpack.ProvidePlugin({
  identifier: ['module1', 'property1'],
  // ...
})

// Whenever the identifier is encountered as free variable in a module, the module is loaded automatically and the identifier is filled with the exports of the loaded module (of property in order to support named exports).

//---------- JQuery

new webpack.ProvidePlugin({
  $: 'jquery',
  jQuery: 'jquery'
})

// Then in any of our source code:
// in a module
$('#item'); // <= just works
jQuery('#item'); // <= just works
// $ is automatically set to the exports of module "jquery"

//---------- JQuery for Angular

// Angular looks for window.jQuery
new webpack.ProvidePlugin({
  'window.jQuery': 'jquery'
})

//---------- Lodash Map

new webpack.ProvidePlugin({
  _map: ['lodash', 'map']
})

Concepts

Module Resolution

webpack.js.org: module resolution.

Webpack uses enhanced-resolve to resolve file paths while bundling modules.

Webpack supports:


import foo from 'path/to/module'
// or
require('path/to/module')

Absolute paths

Since we already have the absolute path to the file, no further resolution is required.

Relative paths

The relative path specified in the import/require is joined to the context path to produce the absolute path to the module.

wcfTodo: how is the context path defined?

Module paths

Modules are searched for inside all directories specified in resolve.modules. You can replace the original module path by an alternate path by creating an alias for it using resolve.alias.