Webpack configuration

Webpack configuration

To view all document pages:Full stack developmentFor more information.

Original link:Chapter 2 Configuration, the original advertising mode box block, reading experience is not good, so organize the text, easy to find.

There are two ways to configure a Webpack:

  1. Describe the configuration through a JavaScript file, such as usingwebpack.config.jsConfiguration in file;
  2. When executing a Webpack executable, it is passed in through command line arguments, such aswebpack --devtool source-map.

The two methods can be combined with each other, for example, through commands when executing a Webpack.webpack --config webpack-dev.config.jsSpecify the configuration file before going.webpack-dev.config.jsSome configurations are described in the document.

According to configurationAffected functionsTo divide, can be divided into:

  • EntryThe entrance of the configuration module;
  • OutputConfigure how to output the final desired code;
  • ModuleConfiguring rules for processing modules;
  • ResolveConfigure rules for finding modules;
  • PluginsConfigure extensions;
  • DevServerConfigure DevServer;;
  • Other configuration itemsOther scattered configuration items;
  • Overall configuration structureDescribe the structure of each configuration item as a whole;
  • Multiple configuration typesThe configuration file can return not only one Object, but also other return forms.
  • Configuration summaryFind the rules for configuring Webpack and reduce the burden of thinking.

Entry

When searching for files with relative paths, the Webpack will take the context as the root directory, and the context defaults to the current working directory where the Webpack was started.

If you want to change the default configuration of context, you can set it in the configuration file:

module.exports = {
  context: path.resolve(__dirname, 'app')
}

Note that the context must be a string of absolute paths. In addition, you can also use the parameters when starting the Webpack.webpack --contextTo set the context.

Chunk name

The Webpack will give each generated Chunk a name, which is related to the configuration of Entry:

  • If entry is astringOrarray, only one Chunk will be generated, and the name of Chunk ismain;
  • If entry is aobject, there may be more than one Chunk, when the name of the Chunk isobjectThe name of the key in the key-value pair.

Configure dynamic Entry

If there are multiple pages in the project that need to configure an Entry for each page Entry, but the number of these pages may continue to grow, then the entry configuration will be affected by other factors, resulting in a static value that cannot be written. The solution is to set Entry as a function to dynamically return the above-mentioned configuration. The code is as follows:

// 同步函数
entry: () => {
  return {
    a:'./pages/a',
    b:'./pages/b',
  }
};
// 异步函数
entry: () => {
  return new Promise((resolve)=>{
    resolve({
       a:'./pages/a',
       b:'./pages/b',
    });
  });
};

Output

outputConfigure how to output the final desired code.outputIs aobject, which contains a series of configuration items:

filename

output.filenameThe name of the configuration output file, which is of type string. If there is only one output file, it can be written as static:

filename: 'bundle.js'

However, when there are multiple Chunk to output, templates and variables are needed. As mentioned earlier, the Webpack will give each Chunk a name, and the output file name can be distinguished according to the Chunk name:

filename: '[name].js'

In the code[name]On behalf of the use of built-innameVariable to replace[name]In this case, you can think of it as a string module function, and each Chunk to be output will use this function to splice out the name of the output file.

variable name Meaning
id Unique identifier of Chunk, starting from 0
name Chunk’s name
hash Hash value for unique identification of Chunk
chunkhash Hash value of Chunk content

among themhashAndchunkhashThe length of is specifiable.[hash:8]On behalf of the 8-bit Hash value, the default is 20 bits.

Note that the ExtractTextWebpackPlugin plug-in is usedcontenthashTo represent hash values instead ofchunkhashThe reason is that the content extracted by ExtractTextWebpackPlugin is the code content itself rather than Chunk composed of a group of modules.

chunkFilename

output.chunkFilenameConfigure the file name of Chunk with no entry when outputting.chunkFilenameAnd abovefilenameVery similar, but chunkFilename is only used to specify the name of the file generated during runtime when Chunk is output. The usual Chunk scenario generated at run time is in use.CommonChunkPluginUseimport('path/to/module')Dynamic loading isochronous. ChunkFilename supports built-in variables consistent with filename.

path

output.pathThe configuration output file is stored in a local directory and must be an absolute path of type string. JspathModule to get absolute path:

path: path.resolve(__dirname, 'dist_[hash]')

publicPath

In complex projects, there may be some constructed resources that need to be loaded asynchronously, and the corresponding URL address is required to load these asynchronous resources.

output.publicPathConfigure the URL prefix to be published to online resources as string. The default value is an empty string''That is, relative paths are used.

Upload the constructed resource file to CDN service to speed up the page opening. The configuration code is as follows:

filename:'[name]_[chunkhash:8].js'
publicPath: 'https://cdn.example.com/assets/'

At this time, when introducing JavaScript files, HTML published online needs to:

<script src='https://cdn.example.com/assets/a_12345678.js'></script>

Be careful when using this configuration item. Any carelessness will result in 404 error in resource loading.

output.pathAndoutput.publicPathBoth support string templates, with only one built-in variable:hashHash value representing a compilation operation.

crossOriginLoading

Some code blocks output by the Webpack may need to be loaded asynchronously, while asynchronous loading is done throughJSONPIn this way.JSONPThe principle of is to dynamically insert an<script src="url"></script>Tag to load asynchronous resources.

output.crossOriginLoadingIs used to configure this asynchronously inserted tagcrossoriginValue.

Script taggedcrossoriginThe property can take the following values:

  • false(Default) Cookies; of users will not be brought when loading this script resource;
  • use-credentialsWhen loading this script resource, the user’s Cookies will be brought along.

Usually with settingscrossoriginTo get detailed error information when asynchronously loaded scripts are executed.

LibraryTarget and library

They are needed when using Webpack to build a library that can be imported and used by other modules.

  • output.libraryTargetConfigure how libraries are exported.
  • output.libraryConfigure the name of the export library.

If configuredoutput.library='LibraryName', the code to output and use is as follows:

// Webpack 输出的代码
var LibraryName = lib_code;

// 使用库的方法
LibraryName.doSomething();

Ifoutput.libraryIf it is empty, it will be directly output:lib_code

among themlib_codeThe code content guiding the outbound is a self-executing function with a return value.

They are usually used together.

output.libraryTargetIs an enumeration type of string and supports the following configuration.

Var (default)

The library will be compiled throughvarAssigned to PasslibraryThe variable that specifies the name.

commonjs

The written library will be exported through the CommonJS2 specification, and the output and use code are as follows:

// Webpack 输出的代码
module.exports = lib_code;

// 使用库的方法
require('library-name-in-npm').doSomething();

The CommonJS2 and CommonJS specifications are very similar, except that CommonJS can only be usedexportsExport, while CommonJS2 adds to CommonJSmodule.exportsThe export method of.

Inoutput.libraryTargetFor commonjs2, configureoutput.libraryThere will be no point.

this

The library will be compiled throughthisAssigned to PasslibraryThe specified name, output and code used are as follows:

// Webpack output code
this[‘LibraryName’] = lib_code;

//Method of using library
this.LibraryName.doSomething();

window

The library will be compiled throughwindowAssigned to PasslibraryThe specified name, that is, mount the library to thewindowOn, the output and use codes are as follows:

// Webpack 输出的代码
window['LibraryName'] = lib_code;

// 使用库的方法
window.LibraryName.doSomething();

global

The library will be compiled throughglobalAssigned to PasslibraryThe specified name, that is, mount the library to theglobalOn, the output and use codes are as follows:


// Webpack 输出的代码
global['LibraryName'] = lib_code;

// 使用库的方法
global.LibraryName.doSomething();

libraryExport

output.libraryExportConfigure which sub-modules of the modules to export need to be exported. It is only inoutput.libraryTargetSet tocommonjsOr ..commonjs2Only when it is used can it be meaningful.

If the module source code to be exported is:

export const a=1;
export default b=2;

Now you want the code that builds the output to export only thea, can putoutput.libraryExportset ataThen the code for building the output and how to use it will become as follows:

// Webpack 输出的代码
module.exports = lib_code['a'];

// 使用库的方法
require('library-name-in-npm')===1;

Module

Configure Loader

rulesThe reading and parsing rules of the configuration module are usually used for configuration.Loader. Its type is an array, and each item in the array describes how to process some files. Configure an itemrulesWhen roughly through the following ways:

  1. Condition matching: PasstestincludeexcludeThree configuration items to hit the file to which Loader applies the rule.
  2. Apply rules: Passes the selected fileuseConfiguration items to apply Loader, can only apply a Loader or according toFrom back to frontA set of loaders can be applied in the order of. at the same time, parameters can be passed in to loaders respectively.
  3. Reset order: the execution order of a set of LoaderThe default is from right to leftThroughenforceOption allows one of the Loader to be executed first or last.
module: {
  rules: [
    {
      // 命中 JavaScript 文件
      test: /\.js$/,
      // 用 babel-loader 转换 JavaScript 文件
      // ?cacheDirectory 表示传给 babel-loader 的参数,用于缓存 babel 编译结果加快重新编译速度
      use: ['babel-loader?cacheDirectory'],
      // 只命中src目录里的js文件,加快 Webpack 搜索速度
      include: path.resolve(__dirname, 'src')
    },
    {
      // 命中 SCSS 文件
      test: /\.scss$/,
      // 使用一组 Loader 去处理 SCSS 文件。
      // 处理顺序为从后到前,即先交给 sass-loader 处理,再把结果交给 css-loader 最后再给 style-loader。
      use: ['style-loader', 'css-loader', 'sass-loader'],
      // 排除 node_modules 目录下的文件
      exclude: path.resolve(__dirname, 'node_modules'),
    },
    {
      // 对非文本文件采用 file-loader 加载
      test: /\.(gif|png|jpe?g|eot|woff|ttf|svg|pdf)$/,
      use: ['file-loader'],
    },
  ]
}

When Loader needs to pass in many parameters, you can also use aObjectTo describe, for example, the abovebabel-loaderThe configuration has the following code:

use: [
  {
    loader:'babel-loader',
    options:{
      cacheDirectory:true,
    },
    // enforce:'post' 的含义是把该 Loader 的执行顺序放到最后
    // enforce 的值还可以是 pre,代表把 Loader 的执行顺序放到最前面
    enforce:'post'
  },
  // 省略其它 Loader
]

In the above exampletest include excludeThe configuration items of the three hit files only pass in a string or regular, but they all support array types, using the following:

{
  test:[
    /\.jsx?$/,
    /\.tsx?$/
  ],
  include:[
    path.resolve(__dirname, 'src'),
    path.resolve(__dirname, 'tests'),
  ],
  exclude:[
    path.resolve(__dirname, 'node_modules'),
    path.resolve(__dirname, 'bower_modules'),
  ]
}

Between each item in the array isOrIf the file path meets any condition in the array, it will be hit.

noParse

noParseConfiguration items enable the Webpack to ignore recursive parsing and processing of some files that do not adopt modularity, which has the advantage of improving construction performance. The reason is that some libraries, such as jQuery and ChartJS, are large and do not adopt modular standards. It is time-consuming and meaningless for Webpack to parse these files.

noParseIs an optional configuration item and needs to be of typeRegExp[RegExp]functionOne of them.

For example, if you want to ignore jQuery and ChartJS, you can use the following code:

// 使用正则表达式
noParse: /jquery|chartjs/

// 使用函数,从 Webpack 3.0.0 开始支持
noParse: (content)=> {
  // content 代表一个模块的文件路径
  // 返回 true or false
  return /jquery|chartjs/.test(content);
}

Note that neglected files should not containimportrequiredefineSuch as modular statements, otherwise it will cause the built code to contain modular statements that cannot be executed in the browser environment.

parser

Because the Webpack uses modular JavaScript files as its entry, it has built-in parsing capabilities for modular JavaScript and supportsAMDCommonJSSystemJSES6.

parserThe property allows finer-grained configuration of which module syntax is to be parsed and which is not, andnoParseConfiguration items differ in thatparserCan be accurate to the grammatical level, andnoParseYou can only control which files are not parsed.parserUse the following:

module: {
  rules: [
    {
      test: /\.js$/,
      use: ['babel-loader'],
      parser: {
      amd: false, // 禁用 AMD
      commonjs: false, // 禁用 CommonJS
      system: false, // 禁用 SystemJS
      harmony: false, // 禁用 ES6 import/export
      requireInclude: false, // 禁用 require.include
      requireEnsure: false, // 禁用 require.ensure
      requireContext: false, // 禁用 require.context
      browserify: false, // 禁用 browserify
      requireJs: false, // 禁用 requirejs
      }
    },
  ]
}

Resolve

After the Webpack is started, all dependent modules will be found from the configured portal modules.ResolveConfigure how the Webpack finds the file corresponding to the module. The Webpack has built-in JavaScript modular syntax parsing function. By default, the rules agreed in the modular standard will be used to find it, but you can also modify the default rules according to your own needs.

alias

resolve.aliasConfiguration items map the original import path to a new import path through aliases. For example, use the following configuration:

// Webpack alias 配置
resolve:{
  alias:{
    components: './src/components/'
  }
}

When you passimport Button from 'components/button'When importing, is actuallyaliasEquivalent replaced byimport Button from './src/components/button'.

AbovealiasThe meaning of configuration is to import thecomponentsReplace keywords with./src/components/.

Doing so may hit too many import statements.aliasAlso supports$Symbol to narrow the scope to hit only import statements that end with keywords:

resolve:{
  alias:{
    'react$': '/path/to/react.min.js'
  }
}

react$It will only hitreactAt the end of the import statement, that is, only theimport 'react'Replace keywords withimport '/path/to/react.min.js'.

mainFields

There are some third-party modules that provide some code for different environments. For example, two codes using ES5 and ES6 are provided respectively. The positions of these two codes are written inpackage.jsonThe document reads as follows:

{
  "jsnext:main": "es/index.js",// 采用 ES6 语法的代码入口文件
  "main": "lib/index.js" // 采用 ES5 语法的代码入口文件
}

Webpack will be based onmainFieldsTo decide which code to use first,mainFieldsThe default is as follows:

mainFields: ['browser', 'main']

The Webpack will go in the order in the array.package.jsonWhen searching in the file, only the first one found will be used.

If you want to give priority to the ES6 code, you can configure it as follows:

mainFields: ['jsnext:main', 'browser', 'main']

extensions

When the import statement does not have a file suffix, the Webpack will automatically take the suffix and try to access whether the file exists.resolve.extensionsUsed to configure the suffix list used in the attempt. The default is:

extensions: ['.js', '.json']

modules

resolve.modulesTo configure which directories the Webpack will go to look for third-party modules, the default is to go only.node_modulesLook under the catalog.

Sometimes some modules in your project will be heavily dependent on and imported by other modules. due to the uncertain location of other modules, the relative path of imported module files will be calculated for different files. this path is sometimes very long, like thisimport '../../../components/button'At this time you can usemodulesConfiguration item optimization, if those modules imported in large quantities are all in./src/componentsUnder the directory, putmodulesConfigured to:

modules:['./src/components','node_modules']

After that, you can simply passimport 'button'Import.

descriptionFiles

resolve.descriptionFilesThe configuration describes the file name of the third-party module, that ispackage.jsonDocuments. The default is as follows:

descriptionFiles: ['package.json']

enforceExtension

resolve.enforceExtensionIf configured totrueAll import statements must have a file suffix, such as before openingimport './foo'Can work normally, must be written after openingimport './foo.js'.

enforceModuleExtension

enforceModuleExtensionAndenforceExtensionThe effect is similar, butenforceModuleExtensionOnly rightnode_modulesThe following modules take effect.

enforceModuleExtensionCommon collocationenforceExtensionUse inenforceExtension:true, because most of the imported statements in the installed third-party modules do not have a file suffix, so at this time through the configurationenforceModuleExtension:falseTo be compatible with third-party modules.

Plugins

Plugin is used to extend the functions of Webpack. Various plugins allow Webpack to do almost anything related to construction.

Configure Plugin

Plugin’s configuration is simple.pluginsConfiguration items accept an array, and each item in the array is an instance of Plugin to be used. Plugin requires parameters to pass throughConstructorIncoming.

const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');

module.exports = {
  plugins: [
    // 所有页面都会用到的公共代码提取到 common 代码块中
    new CommonsChunkPlugin({
      name: 'common',
      chunks: ['a', 'b']
    }),
  ]
};

The difficulty in using Plugin lies in mastering the configuration items provided by Plugin itself, rather than how to access Plugin in Webpack.

DevServer

To configure DevServer, you must use thedevServerIn addition to passing in parameters, you can also pass in through command line parameters. Note that only throughDevServerIn the configuration file when starting the WebpackdevServerWill take effect because the functions corresponding to these parameters are all provided by DevServer and the Webpack itself does not know them.devServerConfiguration item.

hot

devServer.hotConfigure whether the module hot swap function is enabled.

DevServerThe default behavior is to realize real-time preview by automatically refreshing the entire page after discovering that the source code has been updated, and to realize real-time preview by replacing the old module with the new module without refreshing the entire page after turning on the module hot replacement function.

inline

DevServer’s real-time preview function relies on a proxy client injected into the page to accept commands from DevServer and be responsible for refreshing the page.

devServer.inlineIt is used to configure whether the proxy client is automatically injected into the Chunk to be run on the page. The default is automatic injection. DevServer will depend on whether you open it or not.inlineTo adjust its automatic refresh policy:

  • If oninline, DevServer will control web page refresh through proxy client when the changed code is built.
  • If closedinline, DevServer will have no direct control over the web pages to be developed. Then it will passiframeTo run the web page to be developed, refresh it when the changed code is built.iframeTo realize real-time preview.

If you want to use DevServer to refresh the web page automatically to realize real-time preview, the most convenient method is to open it directly.inline.

historyApiFallback

devServer.historyApiFallbackFor convenient development of single-page applications using the HTML5 History API.

This type of one-page application requires the server to return a corresponding HTML file for any hit route, for example, when accessinghttp://localhost/userAndhttp://localhost/homeReturn at all timesindex.htmlFile, browser-side JavaScript code will analyze the current page status from the URL and display the corresponding interface.

ConfigurationhistoryApiFallbackThe simplest way is:

historyApiFallback: true

This will cause any request to returnindex.htmlFile, which can only be used for applications with only one HTML file.

If your application consists of multiple single-page applications, it requires DevServer to return different HTML files according to different requests. the configuration is as follows:

historyApiFallback: {
  // 使用正则匹配命中路由
  rewrites: [
    // /user 开头的都返回 user.html
    { from: /^\/user/, to: '/user.html' },
    { from: /^\/game/, to: '/game.html' },
    // 其它的都返回 index.html
    { from: /./, to: '/index.html' },
  ]
}

contentBase

devServer.contentBaseConfigure the file root directory of the DevServer HTTP server. By default, it is the current execution directory, usually the root directory of the project. In general, you do not need to set it unless you have additional files to be served by DevServer. For example, you want to put thepublicThe directory is set as the file root directory of DevServer server. you can configure it as follows:

devServer:{
  contentBase: path.join(__dirname, 'public')
}

There are two types of files exposed by DevServer server through HTTP service, which need to be pointed out that may confuse you:

  • Expose local files.
  • Expose the results built by the Webpack. Since the built results are handed over to DevServer, you cannot find the built files locally when using DevServer.

contentBaseCan only be used to configure rules that expose local files. You can do this bycontentBase:falseTo close expose local files.

headers

devServer.headersConfiguration items can inject some HTTP response headers into HTTP responses using the following:

devServer:{
  headers: {
    'X-foo':'bar'
  }
}

host

devServer.hostThe configuration item is used to configure the address to which the DevServer service listens.

For example, if you want other devices in the LAN to access your local service, you can bring it with you when you start DevServer.--host 0.0.0.0.hostThe default value for is127.0.0.1That is, only the local can access DevServer’s HTTP service.

port

devServer.portThe configuration item is used to configure the port on which DevServer service listens. it is used by default8080Port. If8080The port is already occupied by other programs8081If8081Or is it occupied and used?8082And so on.

allowedHosts

devServer.allowedHostsConfigure a white list. Only the HOST of HTTP request will normally return in the list. Use the following:

allowedHosts: [
  // 匹配单个域名
  'host.com',
  'sub.host.com',
  // host2.com 和所有的子域名 *.host2.com 都将匹配
  '.host2.com'
]

disableHostCheck

devServer.disableHostCheckThe configuration item is used to configure whether to turn off HOST checking for HTTP requests for DNS rebinding.

DevServer only accepts local requests by default, and can accept requests from any HOST after shutdown. It is usually used with--host 0.0.0.0Use, because you want other devices to access your local service, but the access is directly through the IP address instead of HOST access, so you need to turn off HOST check.

https

DevServer uses HTTP protocol service by default, and it can also use HTTPS protocol service. In some cases you must use HTTPS, for example, HTTP2 and Service Worker must run on HTTPS. The easiest way to switch to HTTPS service is:

devServer:{
  https: true
}

DevServer will automatically generate an HTTPS certificate for you.

If you want to use your own certificate, you can configure it like this:

devServer:{
  https: {
    key: fs.readFileSync('path/to/server.key'),
    cert: fs.readFileSync('path/to/server.crt'),
    ca: fs.readFileSync('path/to/ca.pem')
  }
}

clientLogLevel

devServer.clientLogLevelConfigure the log level at the client, which will affect what you see in the browser developer tools console.

clientLogLevelYesenumeration type, which can take one of the following valuesnone | error | warning | info. The default isinfoLevel, which outputs all types of logs, is set tononeNo log can be output.

compress

devServer.compressConfigure whether gzip compression is enabled.booleanIs of type, which defaults tofalse.

open

devServer.openIt is used to automatically use the default browser on your system to open the web page to be developed when DevServer starts and is built for the first time. It also providesdevServer.openPageThe configuration item is used to open the webpage of the specified URL.

Other configuration items

Target

targetConfiguration items enable Webpack to build code for different operating environments. Target can be one of the following:

Target value describe
web For browsers(Default)All code is centralized in one file
node Js, userequireStatement to load Chunk code
async-node Js, load Chunk code asynchronously.
webworker For WebWorker
electron-main ForElectronMain thread
electron-renderer For Electron Rendering Threads

For example, when you set uptarget:'node'Js native module statement is imported into the source coderequire('fs')Will be retained,fsThe contents of the module will not be packed into Chunk.

Devtool

devtoolConfigure how Webpack generates Source Map, the default value isfalseI.e. no Source Map is generated. if you want to generate Source Map for the built code to facilitate debugging, you can configure it as follows:

module.export = {
  devtool: 'source-map'
}

Watch and WatchOptions

The listening mode of Webpack was introduced earlier. It supports listening for file updates and recompiling when files change. The listening mode is turned off by default when using the Webpack, and the following configuration is required to turn it on:

module.export = {
  watch: true
}

When using DevServer, listening mode is turned on by default.

In addition, Webpack also provideswatchOptionsConfiguration items can be used to control the listening mode more flexibly as follows:

module.export = {
  // 只有在开启监听模式时,watchOptions 才有意义
  // 默认为 false,也就是不开启
  watch: true,
  // 监听模式运行时的参数
  // 在开启监听模式时,才有意义
  watchOptions: {
    // 不监听的文件或文件夹,支持正则匹配
    // 默认为空
    ignored: /node_modules/,
    // 监听到变化发生后会等300ms再去执行动作,防止文件更新太快导致重新编译频率太高
    // 默认为 300ms  
    aggregateTimeout: 300,
    // 判断文件是否发生变化是通过不停的去询问系统指定文件有没有变化实现的
    // 默认每1000豪秒去问1次
    poll: 1000
  }
}

Externals

External is used to tell which modules are not to be packaged in the code to be built by the Webpack, that is to say, these templates are provided by the external environment, and the Webpack can ignore them when packaging.

Some JavaScript operating environments may have built-in global variables or modules, such as the following code in your HTML HEAD tag:

<script src="path/to/jquery.js"></script>

After jQuery was introduced, global variablesjQueryIt will be injected into the JavaScript running environment of the web page.

If you want to import and use jQuery in source code that uses modularity, you may need to do this:

import $ from 'jquery';
$('.my-element');

After construction, you will find the contents of jQuery library contained in the output Chunk, which results in jQuery library appearing twice, wasting load flow, and it is better that the contents of jQuery library will not be contained in Chunk.

Externals configuration items are designed to solve this problem.

viaexternalsYou can tell that the Webpack JavaScript runtime environment has built-in those global variables. For these global variables, global variables are used directly instead of being packaged into code. To solve the above problems, it can be configured as followsexternals

module.export = {
  externals: {
    // 把导入语句里的 jquery 替换成运行环境里的全局变量 jQuery
    jquery: 'jQuery'
  }
}

ResolveLoader

ResolveLoader is used to tell the Webpack how to find Loader, because when using Loader, it is referenced by its package name. The Webpack needs to find the actual code of Loader according to the configured Loader package name to call Loader to process the source file.

The default configuration of ResolveLoader is as follows:

module.exports = {
  resolveLoader:{
    // 去哪个目录下寻找 Loader
    modules: ['node_modules'],
    // 入口文件的后缀
    extensions: ['.js', '.json'],
    // 指明入口文件位置的字段
    mainFields: ['loader', 'main']
  }
}

This configuration item is often used to load the local Loader.

Overall configuration structure

The previous chapters described the specific meaning of each configuration item separately, but did not describe their location and data structure. The following is a code to describe it clearly:

const path = require('path');

module.exports = {
    // entry 表示 入口,Webpack 执行构建的第一步将从 Entry 开始,可抽象成输入。
    // 类型可以是 string | object | array
    entry: './app/entry', // 只有1个入口,入口只有1个文件
    entry: ['./app/entry1', './app/entry2'], // 只有1个入口,入口有2个文件
    entry: { // 有2个入口
        a: './app/entry-a',
        b: ['./app/entry-b1', './app/entry-b2']
    },

    // 如何输出结果:在 Webpack 经过一系列处理后,如何输出最终想要的代码。
    output: {
        // 输出文件存放的目录,必须是 string 类型的绝对路径。
        path: path.resolve(__dirname, 'dist'),

        // 输出文件的名称
        filename: 'bundle.js', // 完整的名称
        filename: '[name].js', // 当配置了多个 entry 时,通过名称模版为不同的 entry 生成不同的文件名称
        filename: '[chunkhash].js', // 根据文件内容 hash 值生成文件名称,用于浏览器长时间缓存文件

        // 发布到线上的所有资源的 URL 前缀,string 类型
        publicPath: '/assets/', // 放到指定目录下
        publicPath: '', // 放到根目录下
        publicPath: 'https://cdn.example.com/', // 放到 CDN 上去

        // 导出库的名称,string 类型
        // 不填它时,默认输出格式是匿名的立即执行函数
        library: 'MyLibrary',

        // 导出库的类型,枚举类型,默认是 var
        // 可以是 umd | umd2 | commonjs2 | commonjs | amd | this | var | assign | window | global | jsonp ,
        libraryTarget: 'umd',

        // 是否包含有用的文件路径信息到生成的代码里去,boolean 类型
        pathinfo: true,

        // 附加 Chunk 的文件名称
        chunkFilename: '[id].js',
        chunkFilename: '[chunkhash].js',

        // JSONP 异步加载资源时的回调函数名称,需要和服务端搭配使用
        jsonpFunction: 'myWebpackJsonp',

        // 生成的 Source Map 文件名称
        sourceMapFilename: '[file].map',

        // 浏览器开发者工具里显示的源码模块名称
        devtoolModuleFilenameTemplate: 'webpack:///[resource-path]',

        // 异步加载跨域的资源时使用的方式
        crossOriginLoading: 'use-credentials',
        crossOriginLoading: 'anonymous',
        crossOriginLoading: false,
    },

    // 配置模块相关
    module: {
        rules: [ // 配置 Loader
            {
                test: /\.jsx?$/, // 正则匹配命中要使用 Loader 的文件
                include: [ // 只会命中这里面的文件
                    path.resolve(__dirname, 'app')
                ],
                exclude: [ // 忽略这里面的文件
                    path.resolve(__dirname, 'app/demo-files')
                ],
                use: [ // 使用那些 Loader,有先后次序,从后往前执行
                    'style-loader', // 直接使用 Loader 的名称
                    {
                        loader: 'css-loader',
                        options: { // 给 html-loader 传一些参数
                        }
                    }
                ]
            },
        ],
        noParse: [ // 不用解析和处理的模块
            /special-library\.js$/  // 用正则匹配
        ],
    },

    // 配置插件
    plugins: [],

    // 配置寻找模块的规则
    resolve: {
        modules: [ // 寻找模块的根目录,array 类型,默认以 node_modules 为根目录
            'node_modules',
            path.resolve(__dirname, 'app')
        ],
        extensions: ['.js', '.json', '.jsx', '.css'], // 模块的后缀名
        alias: { // 模块别名配置,用于映射模块
            // 把 'module' 映射 'new-module',同样的 'module/path/file' 也会被映射成 'new-module/path/file'
            'module': 'new-module',
            // 使用结尾符号 $ 后,把 'only-module' 映射成 'new-module',
            // 但是不像上面的,'module/path/file' 不会被映射成 'new-module/path/file'
            'only-module$': 'new-module',
        },
        alias: [ // alias 还支持使用数组来更详细的配置
            {
                name: 'module', // 老的模块
                alias: 'new-module', // 新的模块
                // 是否是只映射模块,如果是 true 只有 'module' 会被映射,如果是 false 'module/inner/path' 也会被映射
                onlyModule: true,
            }
        ],
        symlinks: true, // 是否跟随文件软链接去搜寻模块的路径
        descriptionFiles: ['package.json'], // 模块的描述文件
        mainFields: ['main'], // 模块的描述文件里的描述入口的文件的字段名称
        enforceExtension: false, // 是否强制导入语句必须要写明文件后缀
    },

    // 输出文件性能检查配置
    performance: {
        hints: 'warning', // 有性能问题时输出警告
        hints: 'error', // 有性能问题时输出错误
        hints: false, // 关闭性能检查
        maxAssetSize: 200000, // 最大文件大小 (单位 bytes)
        maxEntrypointSize: 400000, // 最大入口文件大小 (单位 bytes)
        assetFilter: function (assetFilename) { // 过滤要检查的文件
            return assetFilename.endsWith('.css') || assetFilename.endsWith('.js');
        }
    },

    devtool: 'source-map', // 配置 source-map 类型

    context: __dirname, // Webpack 使用的根目录,string 类型必须是绝对路径

    // 配置输出代码的运行环境
    target: 'web', // 浏览器,默认
    target: 'webworker', // WebWorker
    target: 'node', // Node.js,使用 `require` 语句加载 Chunk 代码
    target: 'async-node', // Node.js,异步加载 Chunk 代码
    target: 'node-webkit', // nw.js
    target: 'electron-main', // electron, 主线程
    target: 'electron-renderer', // electron, 渲染线程

    externals: { // 使用来自 JavaScript 运行环境提供的全局变量
        jquery: 'jQuery'
    },

    stats: { // 控制台输出日志控制
        assets: true,
        colors: true,
        errors: true,
        errorDetails: true,
        hash: true,
    },

    devServer: { // DevServer 相关的配置
        proxy: { // 代理到后端服务接口
            '/api': 'http://localhost:3000'
        },
        contentBase: path.join(__dirname, 'public'), // 配置 DevServer HTTP 服务器的文件根目录
        compress: true, // 是否开启 gzip 压缩
        historyApiFallback: true, // 是否开发 HTML5 History API 网页
        hot: true, // 是否开启模块热替换功能
        https: false, // 是否开启 HTTPS 模式
    },

    profile: true, // 是否捕捉 Webpack 构建的性能信息,用于分析什么原因导致构建性能不佳

    cache: false, // 是否启用缓存提升构建速度

    watch: true, // 是否开始
    watchOptions: { // 监听模式选项
        // 不监听的文件或文件夹,支持正则匹配。默认为空
        ignored: /node_modules/,
        // 监听到变化发生后会等300ms再去执行动作,防止文件更新太快导致重新编译频率太高
        // 默认为300ms
        aggregateTimeout: 300,
        // 判断文件是否发生变化是不停的去询问系统指定文件有没有变化,默认每秒问 1000 次
        poll: 1000
    },
};

Multiple configuration types

In addition to exporting an Object to describe the configuration required by the Webpack, there are other more flexible ways to simplify the configuration of different scenarios.

Export a Function

Most of the time you need to build multiple copies of code from the same source code, for example, one for development and one for publishing online.

If you export an Object to describe the configuration required by the Webpack, you need to write two files. One for the development environment and one for the online environment. And then pass at startupwebpack --config webpack.config.jsSpecify which profile to use.

By exporting a Function, the above requirements can be fulfilled by writing only one configuration file through JavaScript’s flexible control configuration.

How to export a Function is as follows:

const path = require('path');
const UglifyJsPlugin = require('webpack/lib/optimize/UglifyJsPlugin');

module.exports = function (env = {}, argv) {
    const plugins = [];

    const isProduction = env['production'];

    // 在生成环境才压缩
    if (isProduction) {
        plugins.push(
            // 压缩输出的 JS 代码
            new UglifyJsPlugin()
        )
    }

    return {
        plugins: plugins,
        // 在生成环境不输出 Source Map
        devtool: isProduction ? undefined : 'source-map',
    };
};

When you run the Webpack, you pass in 2 arguments to this function, which are:

  1. env: Webpack-specific environment variable for the current runtime.envIs an Object. When reading, directly access the property of Object, and set it with parameters when starting the Webpack. For example, the start command iswebpack --env.production --env.bao=fooWhen, thenenvThe value of is{"production":"true","bao":"foo"}.
  2. argv: Represents all parameters passed in through the command line when starting the Webpack, for example--config、--env、--devtool, can be passed throughwebpack -hLists all command line arguments supported by the Webpack.

As far as the above configuration files are concerned, the webpack, which executes the command during development, builds code that is convenient for debugging, and executes it when it is necessary to build code that is published online.webpack --env.productionBuild compressed code.

Export a function that returns Promise

In some cases, you cannot return an Object that describes the configuration synchronously. The Webpack also supports exporting a function that returns Promise, using the following:

module.exports = function(env = {}, argv) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({
        // ...
      })
    }, 5000)
  })
}

Export Multiple Configurations

In addition to exporting only one configuration, the Webpack also supports exporting an array that can contain each configuration and each configuration will be built once.

Use the following:

module.exports = [
  // 采用 Object 描述的一份配置
  {
    // ...
  },
  // 采用函数描述的一份配置
  function() {
    return {
      // ...
    }
  },
  // 采用异步函数描述的一份配置
  function() {
    return Promise();
  }
]

The above configuration will cause the Webpack to perform three different builds for the three configurations.

This is especially suitable for building a library to be uploaded to Npm warehouse with Webpack, because the library may need to contain codes in various modular formats, such as CommonJS and UMD.

Configuration summary

Judging from the previous configuration, there are many options, and many functions are built into the Webpack.

You don’t have to remember them all. You just need to understand the principles and core concepts of the Webpack to determine which module the options belong to, and then check the detailed usage documents.

In general, you can use the following experience to judge how to configure the Webpack:

  • WantSource fileAdd to the build process to be controlled and configured by Webpackentry.
  • Want to customizeThe location and name of the output file, configurationoutput.
  • Want to customizeStrategies for Finding Dependent Modules, configurationresolve.
  • Want to customizeStrategies for parsing and converting files, configurationmodule, usually configurationmodule.rulesLoader in.
  • Most other requirements may be implemented through Plugin, configurationplugin.