- Concepts
- Guides
- Getting Started
- Installation
- Migrating from v1 to v2
- Code Splitting
- Code Splitting - CSS
- Code Splitting - Libraries
- Code Splitting - Async
- Building for Production
- Caching
- Development
- Development - Vagrant
- Dependency Management
- Shimming
- Authoring Libraries
- Improving Build Performance
- Comparison with other bundlers
- Handling Compatibility
- Using environment variables
- Hot Module Replacement - React
- Lazy Loading - React
- Public Path
- Integration with task/test runners
- Tree Shaking
- webpack & Typescript
- DOCUMENTATION(Configuration)
- Introduction
- Configuration Languages
- Configuration Types
- Entry and Context
- Output
- output.chunkFilename
- output.crossOriginLoading
- output.hashFunction
- output.hashDigest
- output.hashDigestLength
- output.hashSalt
- output.filename
- output.hotUpdateChunkFilename
- output.hotUpdateFunction
- output.hotUpdateMainFilename
- output.jsonpFunction
- output.library
- output.libraryTarget
- output.path
- output.pathinfo
- output.publicPath
- output.sourceMapFilename
- output.sourcePrefix
- output.strictModuleExceptionHandling
- output.umdNamedDefine
- Module
- Resolve
- resolve
- resolve.alias
- resolve.aliasFields
- resolve.descriptionFiles
- resolve.enforceExtension
- resolve.enforceModuleExtension
- resolve.extensions
- resolve.mainFields
- resolve.mainFiles
- resolve.modules
- resolve.unsafeCache
- resolveLoader
- resolveLoader.moduleExtensions
- resolve.plugins
- resolve.symlinks
- resolve.cachePredicate
- Plugins
- DevServer
- devServer
- devServer.clientLogLevel
- devServer.compress
- devServer.contentBase
- devServer.filename
- devServer.headers
- devServer.historyApiFallback
- devServer.host - CLI only
- devServer.hot
- devServer.hotOnly
- devServer.https
- devServer.inline
- devServer.lazy
- devServer.noInfo
- devServer.overlay
- devServer.port
- devServer.proxy
- devServer.progress
- devServer.public
- devServer.publicPath
- devServer.quiet
- devServer.setup
- devServer.staticOptions
- devServer.stats
- devServer.watchContentBase
- devServer.watchOptions
- Devtool
- Watch and WatchOptions
- Externals
- Node
- Performance
- Stats
- Other Options
Concepts
Introduction
webpack is a module bundler for modern JavaScript applications.
Four Core Concepts: entry, output, loaders, and plugins.
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.
Output
tell webpack the name of our bundle and where we want it to be emitted to.
Loaders
webpack treats every file (.css, .html, .scss, .jpg, etc.) as a module.Loaders in webpack transform these files into modules(as they are added to your dependency graph). They have two purposes:
- Identify what files should be transformed by a certain loader. (test property)
- Transform that file so that it can be added to your dependency graph (and eventually your bundle). (use property)
Plugins
plugins are most commonly used performing actions and custom functionality on “compilations” or “chunks” of your bundled modules.
example:webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm
const webpack = require('webpack'); //to access built-in plugins
const path = require('path');
const config = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{test: /\.(js|jsx)$/, use: 'babel-loader'}
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin(),
new HtmlWebpackPlugin({template: './src/index.html'})
]
};
module.exports = config;
Entry Points
there are multiple ways to define the entry property in your webpack configuration.
Single Entry (Shorthand) Syntax
const config = {
entry: './path/to/my/entry/file.js'
};
Passing an array of file paths to the entry property creates what is known as a “multi-main entry”. This is useful when you would like to inject multiple dependent files together and graph their dependencies into one “chunk”.
Object Syntax
const config = {
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
};
this is the most scalable way of defining entry/entries in your application.
Scenarios
- 1.Separate App and Vendor Entries
const config = { entry: { app: './src/app.js', vendors: './src/vendors.js' } };
this tells webpack to create dependency graphs starting at both app.js and vendors.js. These graphs are completely separate and independent of each other.
- 2.Multi Page Application
const config = { entry: { pageOne: './src/pageOne/index.js', pageTwo: './src/pageTwo/index.js', pageThree: './src/pageThree/index.js' } };
telling webpack that we would like 3 separate dependency graphs. Use
CommonsChunkPlugin
to create bundles of shared application code between each page.
Output
tell webpack how to write the compiled files to disk.while there can be multiple entry points, only one output configuration is specified.
Usage
The minimum requirements for the output property is to set its value to an object including two things :filename,path.
const config = {
output: {
filename: 'bundle.js',
path: '/home/proj/public/assets'
}
};
Options
output.chunkFilename
: The filename of non-entry chunks as a relative path inside the output.path directory.(非入口文件的命名规则,在按需加载(异步)模块的时候,这样的文件是没有被列在entry中的,如使用CommonJS的方式异步加载模块)output.crossOriginLoading
: enables cross-origin loading of chunks.output.devtoolLineToLine
: Enable line-to-line mapped mode for all/specified modules.output.filename
: Specifies the name of each output file on disk.filename is used solely for naming the individual files.(可以指定文件的hash值,如filename: '[name].js',
,可选的项包括:[name]
、[hash]
、[chunkhash]
)output.hotUpdateChunkFilename
: The filename of theHot Update Chunks
. They are inside the output.path directory.Default:"[id].[hash].hot-update.js"
.output.hotUpdateFunction
: The JSONP function used by webpack for async loading of hot update chunks.Default:"webpackHotUpdate"
.output.hotUpdateMainFilename
: The filename of the Hot Update Main File. Default:"[hash].hot-update.json"
.output.jsonpFunction
: The JSONP function used by webpack for async loading of chunks. Default:"webpackJsonp"
.(A shorter function may reduce the file size a bit. Use a different identifier when having multiple webpack instances on a single page.)output.library
: If set, export the bundle as library. output.library is the name.output.libraryTarget
: format to export the library : var,this,commonjs,commonjs2,amd,umd.output.path
: The output directory as an absolute path (required). ```js // config.js output: { path: “/home/proj/public/assets”, publicPath: “/assets/” }
// index.html
* `output.sourceMapFilename` : The filename of the SourceMaps for the JavaScript files.Default: `"[file].map"`.
## Loaders
Loaders are transformations that are applied on the source code of a module.
the following specifications define the identical loader usage:
```js
{test: /\.css$/, loader: 'css-loader'}
// or equivalently
{test: /\.css$/, use: 'css-loader'}
// or equivalently
{test: /\.css$/, use: {
loader: 'css-loader',
options: {}
}}
Configuration
There are three ways to use loaders in your application:
- via configuration
module: { rules: [ { test: /\.css$/, use: [ { loader: 'style-loader'}, { loader: 'css-loader', options: { modules: true } } ] } ] }
- explicit in the require statement
// Separate loaders from the resource with ! require('style-loader!css-loader?modules!./styles.css');
It’s possible to overwrite any loaders in the configuration by prefixing the entire rule with ! Options can be passed with a query parameter, just like on the web (?key=value&foo=bar). It’s also possible to use a JSON object (?{“key”:”value”,”foo”:”bar”}).
- via CLI
webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'
Loader Features
- Loaders can be chained. They are applied in a pipeline to the resource. A chain of loaders are compiled chronologically. The first loader in a chain of loaders returns a value to the next. At the end loader, webpack expects JavaScript to be returned.
- Loaders can be synchronous or asynchronous.
- Loaders run in Node.js and can do everything that’s possible there.
- Loaders accept query parameters. This can be used to pass configuration to the loader.
- Loaders can also be configured with an options object.
- Normal modules can export a loader in addition to the normal main via package.json with the loader field.
- Plugins can give loaders more features.
- Loaders can emit additional arbitrary files.
Resolving Loaders
Loaders follow the standard module resolution. In most cases it will be loaders from the module path (node_modules). The loader name convention and precedence search order is defined by resolveLoader.moduleTemplates within the webpack configuration API.
Plugins
Plugins are the backbone of webpack. webpack itself is built on the same plugin system that you use in your webpack configuration! They also serve the purpose of doing anything else that a loader cannot do.
Anatomy
A webpack plugin is a JavaScript object that has an apply property. This apply property is called by the webpack compiler, giving access to the entire compilation lifecycle.
// ConsoleLogOnBuildWebpackPlugin.js
function ConsoleLogOnBuildWebpackPlugin() {
};
ConsoleLogOnBuildWebpackPlugin.prototype.apply = function(compiler) {
compiler.plugin('run', function(compiler, callback) {
console.log("The webpack build process is starting!!!");
callback();
});
};
Usage
Since plugins can take arguments/options, you must pass a new instance to the plugins property in your webpack configuration.
plugins: [
new webpack.optimize.UglifyJsPlugin(),
new HtmlWebpackPlugin({template: './src/index.html'})
]
Configuration
webpack’s configuration file is a JavaScript file that exports an object(it’s a standard Node.js CommonJS module,).
You should NOT use the following things. Technically you could use them, but it’s not recommended:
- Access CLI arguments, when using the webpack CLI (instead write your own CLI, or use –env)
- Export non-deterministic values (calling webpack twice should result in the same output files)
- Write long configurations (instead split the configuration into multiple files)
The Simplest Configuration,Multiple Targets,Using TypeScript,Using JSX.略。
Modules
In modular programming, developers break programs up into discrete chunks of functionality called a module.
What is a webpack Module
In contrast to Node.js modules, webpack modules can express their dependencies in a variety of ways:
- An ES2015 import statement
- A CommonJS require() statement
- An AMD define and require statement
- An @import statement inside of a css/sass/less file.
- An image url in a stylesheet (url(…)) or html (<img src=…>) file.
Supported Module Types
略。
Module Resolution
A resolver is a library which helps in locating a module by its absolute path.
webpack can resolve three kinds of file paths:
- Absolute paths
import "/home/me/file"; import "C:\\Users\\me\\file";
- Relative paths
import "../src/file1"; import "./file2";
- Module paths
import "module"; import "module/lib/file";
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 configuration option.Once the path is resolved based on the above rule, the resolver checks to see if the path points to a file or a directory.
If the path points to a file:
- If the path has a file extension, then the file is bundled straightaway.
- Otherwise, the file extension is resolved using the
resolve.extensions
option, which tells the resolver which extensions (eg - .js, .jsx) are acceptable for resolution.
If the path points to a folder: then the following steps are taken to find the right file with the right extension:
- If the folder contains a
package.json
file, then fields specified inresolve.mainFields
configuration option are looked up in order, and the first such field in package.json determines the file path. - If there is no package.json or if the main fields do not return a valid path, file names specified in the
resolve.mainFiles
configuration option are looked for in order, to see if a matching filename exists in the imported/required directory . - The file extension is then resolved in a similar way using the resolve.extensions option.
Resolving Loaders
This follows the same rules as those specified for file resolution. But the resolveLoader configuration option can be used to have separate resolution rules for loaders.
Caching
Every filesystem access is cached, so that multiple parallel or serial requests to the same file occur faster. In watch mode, only modified files are evicted from the cache. If watch mode is off, then the cache gets purged before every compilation.
Dependency Graph
Any time one file depends on another, webpack treats this as a dependency.(This allows webpack to take non-code assets, such as images or web fonts, and also provide them as dependencies).
When webpack processes your application, it starts from a list of modules defined on the command line or in its config file. Starting from these entry points, webpack recursively builds a dependency graph that includes every module your application needs, then packages all of those modules into a small number of bundles - often, just one - to be loaded by the browser.
Targets
webpack offers multiple deployment targets that you can set in your webpack configuration. Each target has a variety of deployment/environment specific additions, support to fit its needs.
module.exports = {
target: 'node'
};
In the example above, using node webpack will compile for usage in a Node.js-like environment (uses Node.js require to load chunks and not touch any built in modules like fs or path).
Hot Module Replacement
Hot Module Replacement (HMR) exchanges, adds, or removes modules while an application is running without a page reload.
How It Works
From The App View
- The app code asks the HMR runtime to check for updates.
- The HMR runtime downloads the updates (asynchronously) and tells the app code that an update is available.
- The app code then asks the HMR runtime to apply the updates.
- The HMR runtime applies the update (synchronously).
From The Compiler (webpack) View In addition to the normal assets, the compiler needs to emit an “update” to allow updating from previous version to the new version. The “update” consists of two parts:
- The update manifest (JSON)
- One or more update chunks (JavaScript) The manifest contains the new compilation hash and a list of all update chunks.Each update chunk contains code for all updated modules in the respective chunk (or a flag indicating that the module was removed).The compiler makes sure that module IDs and chunk IDs are consistent between these builds. It typically stores these IDs in memory (for example, when using webpack-dev-server), but it’s also possible to store them in a JSON file.
From The Module View HMR is an opt-in feature that only affects modules containing HMR code. One example would be patching styling through the style-loader. In order for patching to work, style-loader implements the HMR interface; when it receives an update through HMR, it replaces the old styles with the new ones. a single handler can handle an update to a complete module tree. If a single module in this tree is updated, the complete module tree is reloaded (only reloaded, not transferred).
From The HMR Runtime View 略。
What It Can Be Used For
webpack-dev-server supports a hot mode in which it tries to update with HMR before trying to reload the whole page.
Guides
Getting Started
webpack simplifies your workflow by quickly constructing a dependency graph of your application and bundling them in the right order.
略。
Installation
If you are using npm scripts in your project, npm will try to look for webpack installation in your local modules for which this installation technique is useful.
"scripts": {
"start": "webpack --config mywebpack.config.js"
}
This is standard and recommended practice.
Note that a global webpack installation is not a recommended practice. This locks you down to a specific version of webpack and might fail in projects that use a different version.
Migrating from v1 to v2
略。
Code Splitting
split your code into various bundles which you can then load on demand.
Resource splitting for caching and parallel loads
- Vendor code splitting :
CommonsChunkPlugin
. - CSS splitting :
ExtractTextWebpackPlugin
.
On demand code-splitting
While resource splitting of the previous kind requires the user to specify the split points upfront in the configuration, one can also create dynamic split points in the application code. using import() or require.ensure().
Code Splitting - CSS
Importing CSS
// Import the CSS file like a JavaScript module
import 'bootstrap/dist/css/bootstrap.css';
Using css-loader
module.exports = {
module: {
rules: [{
test: /\.css$/,
use: 'css-loader'
}]
}
}
As a result, the CSS is bundled along with JavaScript.This has the disadvantage that you will not be able to utilize the browser’s ability to load CSS asynchronously and parallel. Instead, your page will have to wait until your whole JavaScript bundle is loaded, to style itself.
Using ExtractTextWebpackPlugin
you can generate a new bundle specifically for all the CSS modules and add them as a separate tag in the index.html:
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
module: {
rules: [{
test: /\.css$/,
use: ExtractTextPlugin.extract({
use: 'css-loader'
})
}]
},
plugins: [
new ExtractTextPlugin('styles.css'),
]
}
Code Splitting - Libraries
略。
Code Splitting - Async
split your bundle into chunks which can be downloaded asynchronously at a later time.
Dynamic import: import()
The ES2015 Loader spec defines import() as method to load ES2015 modules dynamically on runtime.import() takes the module name as argument and returns a Promise: import(name) -> Promise
.
webpack treats import() as a split-point and puts the requested module in a separate chunk.
fully dynamic statements, such as import(foo), will fail because webpack requires at least some file location information. This is because foo could potentially be any path to any file in your system or project. The import() must contain at least some information about where the module is located, so bundling can be limited to a specific directory or set of files.
For example, import(./locale/${language}.json
) will cause every .json file in the ./locale directory to be bundled into the split-point.
Chunk names
Since webpack 2.4.0, chunk names for dynamic imports can be specified using a “magic comment”.
import(/* webpackChunkName: "my-chunk-name" */ 'module');
Usage with Babel
If you want to use import with Babel, you’ll need to install/add the syntax-dynamic-import
plugin .
npm install --save-dev babel-core babel-loader babel-plugin-syntax-dynamic-import babel-preset-es2015
webpack.config.js
module.exports = {
entry: './index-es2015.js',
output: {
filename: 'dist.js',
},
module: {
rules: [{
test: /\.js$/,
exclude: /(node_modules)/,
use: [{
loader: 'babel-loader',
options: {
presets: [['es2015', {modules: false}]],
plugins: ['syntax-dynamic-import']
}
}]
}]
}
};
Usage with Babel and async/await
npm install --save-dev babel-plugin-transform-async-to-generator babel-plugin-transform-regenerator babel-plugin-transform-runtime
index-es2017.js
async function determineDate() {
const moment = await import('moment');
return moment().format('LLLL');
}
determineDate().then(str => console.log(str));
webpack.config.js
module.exports = {
entry: './index-es2017.js',
output: {
filename: 'dist.js',
},
module: {
rules: [{
test: /\.js$/,
exclude: /(node_modules)/,
use: [{
loader: 'babel-loader',
options: {
presets: [['es2015', {modules: false}]],
plugins: [
'syntax-dynamic-import',
'transform-async-to-generator',
'transform-regenerator',
'transform-runtime'
]
}
}]
}]
}
};
require.ensure()
require.ensure() is specific to webpack and superseded by import(). 略。
Building for Production
Running:
webpack -p
or:
webpack --optimize-minimize --define process.env.NODE_ENV="'production'"
This performs the following steps:
- Minification(using UglifyJsPlugin)
- Runs the LoaderOptionsPlugin
- Sets the Node environment variable
Specifying –optimize-minimize on the command line, the following plugin configuration is added:
plugins:[
new webpack.optimize.UglifyJsPlugin({
sourceMap: options.devtool && (options.devtool.indexOf("sourcemap") >= 0 || options.devtool.indexOf("source-map") >= 0)
})
]
We encourage you to have Source Maps enabled in production. They are useful for debugging and to run benchmark tests. webpack can generate inline Source Maps included in the bundles or separated files.
Running webpack -p (or –define process.env.NODE_ENV=”‘production’”) invokes the DefinePlugin
in the following way:
plugins:[
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
]
The DefinePlugin performs search-and-replace operations on the original source code. Any occurrence of process.env.NODE_ENV in the imported code is replaced by “production”. Thus, checks like if (process.env.NODE_ENV !== ‘production’) console.log(‘…’) are evaluated to if (false) console.log(‘…’) and finally minified away using UglifyJS.
The manual way: Configuring webpack for multiple environments
the easiest way is to write separate js files for each environment. Have the following snippet in your webpack.config.js:
function buildConfig(env) {
return require('./config/' + env + '.js')(env)
}
module.exports = buildConfig;
And from our package.json, where we build our application using webpack, the command goes like this:
"build:dev": "webpack --env=dev --progress --profile --colors",
"build:dist": "webpack --env=prod --progress --profile --colors",
we passed the environment variable to our webpack.config.js file. The environment variable is then passed to buildConfig method which simply loads the right js file for the build.
An advanced approach would be to have a base configuration file, put in all common functionalities, and then have environment specific files and simply use ‘webpack-merge’ to merge them. This would help to avoid code repetitions.
For example, you could have all your base configurations like resolving your js, ts, png, jpeg, json and so on.. in a common base file : base.js
module.exports = function() {
return {
entry: {
'polyfills': './src/polyfills.ts',
'vendor': './src/vendor.ts',
'main': './src/main.ts'
},
output: {
path: path.join(__dirname, '/../dist/assets'),
filename: '[name].bundle.js',
publicPath: publicPath,
sourceMapFilename: '[name].map'
},
resolve: {
extensions: ['.ts', '.js', '.json'],
modules: [path.join(__dirname, 'src'), 'node_modules']
},
module: {
rules: [{
test: /\.ts$/,
use: [
'awesome-typescript-loader',
'angular2-template-loader'
],
exclude: [/\.(spec|e2e)\.ts$/]
}, {
test: /\.css$/,
use: ['to-string-loader', 'css-loader']
}, {
test: /\.(jpg|png|gif)$/,
use: 'file-loader'
}, {
test: /\.(woff|woff2|eot|ttf|svg)$/,
use: {
loader: 'url-loader',
options: {
limit: 100000
}
}
}],
},
plugins: [
new ForkCheckerPlugin(),
new webpack.optimize.CommonsChunkPlugin({
name: ['polyfills', 'vendor'].reverse()
}),
new HtmlWebpackPlugin({
template: 'src/index.html',
chunksSortMode: 'dependency'
})
],
};
}
And then merge this base config with an environment specific configuration file using ‘webpack-merge’.
prod.js
const webpackMerge = require('webpack-merge');
const commonConfig = require('./base.js');
module.exports = function() {
return webpackMerge(commonConfig(), {
plugins: [
new webpack.LoaderOptionsPlugin({
minimize: true,
debug: false
}),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production')
}
}),
new webpack.optimize.UglifyJsPlugin({
beautify: false,
mangle: {
screw_ie8: true,
keep_fnames: true
},
compress: {
screw_ie8: true
},
comments: false
})
]
})
}
Caching
To enable long-term caching of static resources produced by webpack:
- Use
[chunkhash]
to add a content-dependent cache-buster to each file. - Extract the webpack manifest into a separate file.
- Ensure that the entry point chunk containing the bootstrapping code doesn’t change hash over time for the same set of dependencies.
The problem
Each webpack build generates a unique hash which can be used to compose a filename, by including output placeholders.But the problem here is, builds after any file update will update all filenames and clients will have to re-download all application code.
Generating unique hashes for each file
webpack allows you to generate hashes depending on file contents, by replacing the placeholder [hash] with [chunkhash].
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.
Get filenames from webpack compilation stats
In order to reference a correct file(with right hash) in the HTML, we’ll need information about our build. This can be extracted from webpack compilation stats by using this plugin
plugins: [
function() {
this.plugin("done", function(stats) {
require("fs").writeFileSync(
path.join(__dirname, "build", "stats.json"),
JSON.stringify(stats.toJson()));
});
}
]
Alternatively, just use one of these plugins to export JSON files:
- webpack-manifest-plugin
- assets-webpack-plugin
Deterministic hashes
To minimize the size of generated files, webpack uses identifiers instead of module names. During compilation, identifiers are generated, mapped to chunk filenames and then put into a JavaScript object called chunk manifest
. To generate identifiers that are preserved over builds, webpack supplies the NamedModulesPlugin
(recommended for development) and HashedModuleIdsPlugin
(recommended for production).The chunk manifest (along with bootstrapping/runtime code) is then placed into the entry chunk and it is crucial for webpack-packaged code to work.
The problem with this, is the same as before: Whenever we change any part of the code it will, even if the rest of its contents wasn’t altered, update our entry chunk to include the new manifest. we should use ChunkManifestWebpackPlugin
, which will extract the manifest to a separate JSON file. This replaces the chunk manifest with a variable in the webpack runtime. But we can do even better; we can extract the runtime into a separate entry by using CommonsChunkPlugin.
the final webpack.config.js:
var path = require("path");
var webpack = require("webpack");
var ChunkManifestPlugin = require("chunk-manifest-webpack-plugin");
var WebpackChunkHash = require("webpack-chunk-hash");
module.exports = {
entry: {
vendor: "./src/vendor.js", // vendor reference file(s)
main: "./src/index.js" // application code
},
output: {
path: path.join(__dirname, "build"),
filename: "[name].[chunkhash].js",
chunkFilename: "[name].[chunkhash].js"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: ["vendor", "manifest"], // vendor libs + extracted manifest
minChunks: Infinity,
}),
new webpack.HashedModuleIdsPlugin(),
new WebpackChunkHash(),
new ChunkManifestPlugin({
filename: "chunk-manifest.json",
manifestVariable: "webpackManifest"
})
]
};
The manifestVariable option is the name of the global variable where webpack will look for the manifest JSON. This should be defined before we require our bundle in HTML:
<script>
//<![CDATA[
window.webpackManifest = {"0":"main.5f020f80c23aa50ebedf.js","1":"vendor.81adc64d405c8b218485.js"}
//]]>
</script>
Development
webpack-dev-server and webpack-dev-middleware use in-memory compilation, meaning that the bundle will not be saved to disk. This makes compiling faster and results in less mess on your file system. 开发工具介绍,略。
Development - Vagrant
略。
Dependency Management
略。
Shimming
different ways to help webpack understand these broken modules. 略。
Authoring Libraries
If you are the author of a JavaScript library and are looking to streamline your bundle strategy then this document will help you. 略。
Improving Build Performance
空。
Comparison with other bundlers
略。
Handling Compatibility
空。
Using environment variables
The standard approach in Node.js modules can be applied: Set an environment variable when running webpack and refer to the variables using Node’s process.env. The variable NODE_ENV is commonly used as de-facto standard.
module.exports = {
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: process.env.NODE_ENV === 'production'
})
]
};
Hot Module Replacement - React
HMR is particularly useful in applications using a single state tree since components are “dumb” and will reflect the latest application state, even after their source is changed and they are replaced.
Project Config
npm install --save-dev webpack webpack-dev-server
npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react
npm install --save-dev style-loader css-loader
npm install --save react react-dom react-hot-loader@next
.babelrc:
{
"presets": [
["es2015", {"modules": false}],
// webpack understands the native import syntax, and uses it for tree shaking
"react"
// Transpile React components to JavaScript
],
"plugins": [
"react-hot-loader/babel"
// Enables React code to work with HMR.
]
}
Setting Babel’s module plugin to false helps fix many issues.
webpack.config.js:
const { resolve } = require('path');
const webpack = require('webpack');
module.exports = {
context: resolve(__dirname, 'src'),
entry: [
'react-hot-loader/patch',
// activate HMR for React
'webpack-dev-server/client?http://localhost:8080',
// bundle the client for webpack-dev-server
// and connect to the provided endpoint
'webpack/hot/only-dev-server',
// bundle the client for hot reloading
// only- means to only hot reload for successful updates
'./index.js'
// the entry point of our app
],
output: {
filename: 'bundle.js',
// the output bundle
path: resolve(__dirname, 'dist'),
publicPath: '/'
// necessary for HMR to know where to load the hot update chunks
},
devtool: 'inline-source-map',
devServer: {
hot: true,
// enable HMR on the server
contentBase: resolve(__dirname, 'dist'),
// match the output path
publicPath: '/'
// match the output `publicPath`
},
module: {
rules: [
{
test: /\.jsx?$/,
use: [ 'babel-loader', ],
exclude: /node_modules/
},
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader?modules', ],
},
],
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
// enable HMR globally
new webpack.NamedModulesPlugin(),
// prints more readable module names in the browser console on HMR updates
],
};
- Setting set devServer: { hot: true } causes webpack will expose the module.hot API to our code
- We use the module.hot hook to enable HMR for specific resources (App.js in this example). The most important property here is module.hot.accept, which specifies how to handle changes to specific dependencies.
- Whenever src/components/App.js or its dependencies are changed module.hot.accept will fire the render method. The render method will even fire when App.css is changed because it is included in App.js.
src/index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import { AppContainer } from 'react-hot-loader';
// AppContainer is a necessary wrapper component for HMR
import App from './components/App';
const render = (Component) => {
ReactDOM.render(
<AppContainer>
<Component/>
</AppContainer>,
document.getElementById('root')
);
};
render(App);
// Hot Module Replacement API
if (module.hot) {
module.hot.accept('./components/App', () => {
render(App)
});
}
Lazy Loading - React
略。
Public Path
specify the base path for all the assets on your application.
output: {
path: "/home/proj/cdn/assets/[hash]",
publicPath: "http://cdn.example.com/assets/[hash]/"
}
Another possible use case is to set the public path on the fly. webpack exposes a global variable that let’s you do that, it’s called webpack_public_path. So in your application entry point, you can simply do this:
__webpack_public_path__ = process.env.ASSET_PATH;
Integration with task/test runners
webpack is a module bundler, like Browserify or Brunch. It is not a task runner. Make, Grunt, or Gulp are task runners. Task runners handle automation of common development tasks such as linting, building, or testing your project. Compared to bundlers, task runners have a higher level focus.
Often webpack users use npm scripts as their task runner. Even though webpack core focuses on bundling, you can find a variety of extensions that allow you to use it in a task runner kind of way.
Tree Shaking
先略。
webpack & Typescript
To start using webpack with Typescript you need a couple of things:
- Install the Typescript compiler in your project.
- Install a Typescript loader (in this case we’re using ts-loader).
- Create a tsconfig.json file to contain our TypeScript compilation configuration.
- Create webpack.config.js to contain our webpack configuration.
npm install --save-dev typescript ts-loader
详略。
DOCUMENTATION(Configuration)
Introduction
webpack is fed via a configuration object. All the available configuration options are specified below:
Configuration Languages
define you configuration files in any language. 略。
Configuration Types
Exporting a function to use –env
module.exports = function(env) {
return {
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: env.production // compress only in production build
})
]
};
};
Exporting a Promise
module.exports = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
entry: './app.js',
/* ... */
})
}, 5000)
})
}
Exporting multiple configurations
module.exports = [{
output: {
filename: './dist-amd.js',
libraryTarget: 'amd'
},
entry: './app.js',
}, {
output: {
filename: './dist-commonjs.js',
libraryTarget: 'commonjs'
},
entry: './app.js',
}]
Entry and Context
context
The base directory, an absolute path, for resolving entry points and loaders from configuration.By default the current directory is used.
entry
The point or points to enter the application. A dynamically loaded module is not an entry point.
If a string or array of strings is passed, the chunk is named main
. If an object is passed, each key is the name of a chunk, and the value describes the entrypoint for the chunk.
Output
instructing webpack on how and where it should output your bundles, assets and anything else you bundle or load with webpack.
output.chunkFilename
determines the name of on-demand loaded chunk files.
output.crossOriginLoading
Only used when target is web, which uses JSONP for loading on-demand chunks, by adding script tags.
output.hashFunction
output.hashDigest
output.hashDigestLength
output.hashSalt
output.filename
determines the name of each output bundle. The default value is “[name].js”. notes:
- this option is called filename but you are still allowed to something like “js/[name]/bundle.js” to create a folder structure.
- this options does not affect output files for on-demand-loaded chunks. For these files the output.chunkFilename option is used.
- It also doesn’t affect files created by loaders. For these files see loader options.
- The lengths of [hash] and [chunkhash] can be specified using [hash:16] (defaults to 20). (Alternatively, specify output.hashDigestLength to configure the length globally.)
- When using the ExtractTextWebpackPlugin, use [contenthash] to obtain a hash of the extracted file (neither [hash] nor [chunkhash] work).
output.hotUpdateChunkFilename
output.hotUpdateFunction
output.hotUpdateMainFilename
output.jsonpFunction
Only used when target is web, which uses JSONP for loading on-demand chunks. This needs to be changed if multiple webpack runtimes (from different compilation) are used on the same webpage.
output.library
output.libraryTarget
output.path
The output directory as an absolute path.
output.pathinfo
Tell webpack to include comments in bundles with information about the contained modules. This option defaults to false and should not be used in production, but it’s very useful in development when reading the generated code.
output.publicPath
specifies the public URL of the output directory when referenced in a browser. A relative URL is resolved relative to the HTML page (or
The webpack-dev-server also takes a hint from publicPath, using it to determine where to serve the output files from.
output.sourceMapFilename
only used when devtool uses a SourceMap option which writes an output file.
output.sourcePrefix
Change the prefix for each line in the output bundles.
output.strictModuleExceptionHandling
Tell webpack to remove a module from the module instance cache (require.cache) if it throws an exception when it is required.It defaults to false for performance reasons.
output.umdNamedDefine
Module
determine how the different types of modules within a project will be treated.
module.noParse
Prevent webpack from parsing any files matching the given regular expression(s). Ignored files should not have calls to import, require, define or any other importing mechanism. This can boost build performance when ignoring large libraries.
noParse: /jquery|lodash/
module.rules
An array of Rules which are matched to requests when modules are created. These rules can modify how the module is created. They can apply loaders to the module, or modify the parser.
Rule
A Rule can be separated into three parts — Conditions, Results and nested Rules.
Rule conditions
There are two input values for the conditions:resource and issuer.When we import “./style.css” from app.js, the resource is /path/to/style.css and the issuer is /path/to/app.js. In a Rule the properties test, include, exclude and resource are matched with the resource and the property issuer is matched with the issuer. When using multiple conditions, all conditions must match.
Rule results
Rule results are used only when the Rule condition matches.There are two output values of a Rule:
- Applied loaders: An array of loaders applied to the resource.
- Parser options: An options object which should be used to create the parser for this module.
Nested rules
Nested rules can be specified under the properties rules and oneOf. These rules are evaluated when the Rule condition matches.
Rule.enforce
Specifies the category of the loader(“pre” | “post”). No value means normal loader.There is also an additional category “inlined loader” which are loaders applied inline of the import/require.
- All loaders are sorted in the order post, inline, normal, pre and used in this order.
- All normal loaders can be omitted (overridden) by prefixing ! in the request.
- All normal and pre loaders can be omitted (overridden) by prefixing -! in the request.
- All normal, post and pre loaders can be omitted (overridden) by prefixing !! in the request.
- Inline loaders and ! prefixes should not be used as they are non-standard. They may be use by loader generated code.
Rule.exclude
is a shortcut to Rule.resource.exclude.
Rule.include
is a shortcut to Rule.resource.include.
Rule.issuer
A Condition matched with the issuer.
Rule.loader
is a shortcut to Rule.use: [ { loader } ].
Rule.loaders
is an alias to Rule.use. (It exists for compatibility reasons. Use Rule.use instead.)
Rule.oneOf
An array of Rules from which only the first matching Rule is used when the Rule matches.
Rule.options / Rule.query
are shortcuts to Rule.use: [ { options } ]. (Rule.query only exists for compatibility reasons. Use Rule.options instead.)
Rule.parser
An object with parser options. All applied parser options are merged.
Rule.resource
A Condition matched with the resource.
Rule.resourceQuery
A Condition matched with the resource query. The condition matches against a string that starts with a question mark (“?exampleQuery”).
Rule.rules
An array of Rules that is also used when the Rule matches.
Rule.test
is a shortcut to Rule.resource.test.
Rule.use
A list of UseEntries which are applied to modules. Each entry specifies a loader to be used.
assing a string (i.e. use: [ "style-loader" ]
) is a shortcut to the loader property (i.e. use: [ { loader: "style-loader "} ]
).
Loaders can be chained by passing multiple loaders, which will be applied from right to left (last to first configured).
Condition
Conditions can be one of these:
- A string: To match the input must start with the provided string. I. e. an absolute directory path, or absolute path to the file.
- A RegExp: It’s tested with the input.
- A function: It’s called with the input and must return a truthy value to match.
- An array of Conditions: At least one of the Condition must match.
- A object: All properties must match. Each property has a defined behavior.
ie:
{ test: Condition }
: The Condition must match. The convention is the provide a RegExp or array of RegExps here, but it’s not enforced.{ include: Condition }
: The Condition must match. The convention is the provide a string or array of strings here, but it’s not enforced.{ exclude: Condition }
: The Condition must NOT match. The convention is the provide a string or array of strings here, but it’s not enforced.{ and: [Condition] }
: All Conditions must match.{ or: [Condition] }
: Any Condition must match.{ not: Condition }
: The Condition must NOT match.
UseEntry
It must have a loader property being a string. It is resolved relative to the configuration context with the loader resolving options (resolveLoader).It can have a options property being a string or object. This value is passed to the loader, which should interpret it as loader options.
{
loader: "css-loader",
options: {
modules: true
}
}
Module Contexts
(Deprecated)
Resolve
change how modules are resolved.
resolve
Configure how modules are resolved. For example, when calling import “lodash” in ES2015, the resolve options can change where webpack goes to look for “lodash”.
resolve.alias
alias: {
Utilities: path.resolve(__dirname, 'src/utilities/'),
Templates: path.resolve(__dirname, 'src/templates/')
}
// Now, instead of using relative paths when importing like so:
import Utility from '../../utilities/utility';
// you can use the alias:
import Utility from 'Utilities/utility';
A trailing $ can also be added to the given object’s keys to signify an exact match:
alias: {
xyz$: path.resolve(__dirname, 'path/to/file.js')
}
import Test1 from 'xyz'; // Success, file.js is resolved and imported
import Test2 from 'xyz/file.js'; // Error, /path/to/file.js/file.js is invalid
resolve.aliasFields
Specify a field to be parsed.
resolve.descriptionFiles
The JSON files to use for descriptions.
descriptionFiles: ["package.json"]
resolve.enforceExtension
If true, it will not allow extension-less files. So by default require(‘./foo’) works if ./foo has a .js extension, but with this enabled only require(‘./foo.js’) will work.
resolve.enforceModuleExtension
Whether to require to use an extension for modules .
resolve.extensions
Automatically resolve certain extensions. which is what enables users to leave off the extension when importing:
import File from '../path/to/file'
Using this will override the default array, meaning that webpack will no longer try to resolve modules using the default extensions. For modules that are imported with their extension, e.g. import SomeFile from “./somefile.ext”, to be properly resolved, a string containing “*” must be included in the array.
resolve.mainFields
this option will determine which fields in it’s package.json are checked.
resolve.mainFiles
The filename to be used while resolving directories. Default:
mainFiles: ["index"]
resolve.modules
Tell webpack what directories should be searched when resolving modules. A relative path will be scanned similarly to how Node scans for node_modules, by looking through the current directory as well as it’s ancestors (i.e. ./node_modules, ../node_modules, and on). With an absolute path, it will only search in the given directory.
defaults to:
modules: ["node_modules"]
resolve.unsafeCache
Enable aggressive, but unsafe, caching of modules.
resolveLoader
used only to resolve webpack’s loader packages.
{
modules: ["node_modules"],
extensions: [".js", ".json"],
mainFields: ["loader", "main"]
}
resolveLoader.moduleExtensions
The extensions which are tried when resolving a module (e.g. loaders).
resolve.plugins
A list of additional resolve plugins which should be applied.
resolve.symlinks
Whether to resolve symlinks to their symlinked location.
resolve.cachePredicate
A function which decides whether a request should be cached or not.
Plugins
customize the webpack build process in a variety of ways. webpack comes with a variety built-in plugins available under webpack.[plugin-name].
DevServer
webpack-dev-server.
devServer
This set of options is picked up by webpack-dev-server and can be used to change its behavior in various ways.
devServer: {
contentBase: path.join(__dirname, "dist"),
compress: true,
port: 9000
}
devServer.clientLogLevel
Possible values are none, error, warning or info (default).
devServer.compress
Enable gzip compression for everything served.
devServer.contentBase
Tell the server where to serve content from. This is only necessary if you want to serve static files. devServer.publicPath will be used to determine where the bundles should be served from, and takes precedence. It is also possible to serve from multiple directories.
devServer.filename
This option lets you reduce the compilations in lazy mode. By default in lazy mode, every request results in a new compilation. With filename, it’s possible to only compile when a certain file is requested.If output.filename is set to bundle.js and filename is used like this:
lazy: true,
filename: "bundle.js"
It will now only compile the bundle when /bundle.js is requested. filename has no effect when used without lazy mode.
devServer.headers
Adds headers to all requests.
devServer.historyApiFallback
When using the HTML5 History API, the index.html page will likely have to be served in place of any 404 responses. Enable this by passing:
historyApiFallback: true
By passing an object this behavior can be controlled further using options like rewrites:
historyApiFallback: {
rewrites: [
{ from: /^\/$/, to: '/views/landing.html' },
{ from: /^\/subpage/, to: '/views/subpage.html' },
{ from: /./, to: '/views/404.html' }
]
}
devServer.host - CLI only
Specify a host to use. By default this is localhost.
devServer.hot
Enable webpack’s Hot Module Replacement feature.
devServer.hotOnly
Enables Hot Module Replacement without page refresh as fallback in case of build failures.
devServer.https
https: {
key: fs.readFileSync("/path/to/server.key"),
cert: fs.readFileSync("/path/to/server.crt"),
ca: fs.readFileSync("/path/to/ca.pem"),
}
devServer.inline
Toggle between the dev-server’s two different modes. By default the application will be served with inline mode enabled. This means that a script will be inserted in your bundle to take care of live reloading, and build messages will appear in the browser console.
It is also possible to use iframe mode, which uses an <iframe> under a notification bar with messages about the build. To switch to iframe mode:
inline: false
Inline mode is recommended when using Hot Module Replacement.
devServer.lazy
When lazy is enabled, the dev-server will only compile the bundle when it gets requested. watchOptions will have no effect when used with lazy mode.
devServer.noInfo
Errors and warnings will still be shown.
devServer.overlay
Shows a full-screen overlay in the browser when there are compiler errors or warnings.
devServer.port
Specify a port number to listen for requests on.
devServer.proxy
proxy: {
"/api": "http://localhost:3000"
}
devServer.progress
Output running progress to console.
devServer.public
devServer.publicPath
devServer.quiet
nothing except the initial startup information will be written to the console.
devServer.setup
Here you can access the Express app object and add your own custom middleware to it. For example, to define custom handlers for some paths:
setup(app){
app.get('/some/path', function(req, res) {
res.json({ custom: 'response' });
});
}
devServer.staticOptions
configure advanced options for serving static files from contentBase.
devServer.stats
precisely control what bundle information gets displayed.
devServer.watchContentBase
Tell the server to watch the files served by the devServer.contentBase option. File changes will trigger a full page reload.
devServer.watchOptions
Control options related to watching the files.
webpack uses the file system to get notified of file changes. In some cases this does not work. For example, when using Network File System (NFS). Vagrant also has a lot of problems with this. In these cases, use polling:
watchOptions: {
poll: true // If this is too heavy on the file system, you can change this to an integer to set the interval in milliseconds.
}
Devtool
controls if and how Source Maps are generated. 略。
Target
webpack can compile for multiple environments or targets. To understand what a target is in detail, read the concepts. 略。
Watch and WatchOptions
watch
Watch mode is turned off by default.In webpack-dev-server and webpack-dev-middleware watch mode is enabled by default.
watchOptions
A set of options used to customize watch mode:
watchOptions: {
aggregateTimeout: 300,
ignored: /node_modules/
poll: 1000
}
Externals
provides a way of excluding dependencies from the output bundles.
Prevent bundling of certain imported packages and instead retrieve these external dependencies at runtime.
For example, to include jQuery from a CDN instead of bundling it:
// index.html
...
<script src="https://code.jquery.com/jquery-3.1.0.js"
integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
crossorigin="anonymous"></script>
...
// webpack.config.js
externals: {
jquery: 'jQuery'
}
the code shown below will still work:
import $ from 'jquery';
$('.my-element').animate(...);
externals accepts various syntax and interprets them in different manners:
-
string jQuery in the externals indicates that your bundle will need jQuery variable in the global form.
- array
externals: { subtract: ['./math', 'subtract'] }
- object
- function
- regex
Node
configure whether to polyfill or mock certain Node.js globals and modules. This allows code originally written for the Node.js environment to run in other environments like the browser. This feature is provided by webpack’s internal NodeStuffPlugin
.
node.console
node.process
node.global
node.__filename
node.__dirname
node.Buffer
node.setImmediate
略。
Performance
allows you to control how webpack notifies you of assets and entrypoints that exceed a specific file limit.
For example if you have an asset that is over 250kb, webpack will emit a warning notifiying you of this.
performance.hints
performance.maxEntrypointSize
performance.maxAssetSize
performance.assetFilter
Stats
precisely control what bundle information gets displayed. This can be a nice middle ground if you don’t want to use quiet or noInfo because you want some bundle information, but not all of it. For webpack-dev-server, this property needs to be in the devServer object.
Other Options
This page is still a work in progress. 略。