关于 Webpack 的学习与使用
关于 Webpack 的学习与使用
概念
入口 (entry)
入口起点(entry point) 指示 webpack 应该使用哪个模块,来作为构建其内部 [依赖图(dependency graph)] 的开始。
进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的
默认值是 ./src/index.js
但你可以通过在 webpack configuration (opens in a new tab) 中配置 entry 属性,来指定一个(或多个)不同的入口起点
输出(output)
output 属性告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件。
主要输出文件的默认值是 ./dist/main.js,其他生成文件默认放置在 ./dist 文件夹中
// webpack.config.js
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js',
},
};
loader
webpack 只能理解 JavaScript 和 JSON 文件,这是 webpack 开箱可用的自带能力。
loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效 [模块],以供应用程序使用,以及被添加到依赖图中。
// webpack.config.js
const path = require('path');
module.exports = {
output: {
filename: 'my-first-webpack.bundle.js',
},
module: {
rules: [
{
// 识别出哪些文件会被转换
test: /\.txt$/,
// 定义出在进行转换时,应该使用哪个 loader
use: 'raw-loader'
}
],
},
};
以上配置中,对一个单独的 module 对象定义了 rules 属性,里面包含两个必须属性:test 和 use。这告诉 webpack 编译器(compiler) 如下信息
“嘿,webpack 编译器,当你碰到「在 require()/import 语句中被解析为 '.txt' 的路径」时,在你对它打包之前,先 use(使用) raw-loader 转换一下。”
插件(plugin)
loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量
想要使用一个插件,你只需要 require() 它,然后把它添加到 plugins 数组中。多数插件可以通过选项(option)自定义。你也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 new 操作符来创建一个插件实例
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack'); // 用于访问内置插件
module.exports = {
module: {
rules: [{ test: /\.txt$/, use: 'raw-loader' }],
},
plugins: [
// `html-webpack-plugin` 为应用程序生成一个 HTML 文件,
// 并自动将生成的所有 bundle 注入到此文件中
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
};模式(mode)
通过选择 development, production 或 none 之中的一个,来设置 mode 参数,你可以启用 webpack 内置在相应环境下的优化。其默认值为 production
module.exports = {
mode: 'production',
};浏览器兼容性(browser compatibility)
Webpack 支持所有符合 ES5 标准 (opens in a new tab) 的浏览器(不支持 IE8 及以下版本)。webpack 的 import() 和 require.ensure() 需要 Promise。如果你想要支持旧版本浏览器,在使用这些表达式之前,还需要 提前加载 polyfill (opens in a new tab)
环境(environment)
Webpack 5 运行于 Node.js v10.13.0+ 的版本
入口起点(entry points)
单个入口(简写)语法
用法:entry: string | [string]
module.exports = {
// 简写
entry: './path/to/my/entry/file.js',
// 等效 默认值是./src/index.js
entry: {
main: './path/to/my/entry/file.js',
}
};我们也可以将一个文件路径数组传递给 entry 属性,这将创建一个所谓的 "multi-main entry"。
在你想要一次注入多个依赖文件,并且将它们的依赖关系绘制在一个 "chunk" 中时,这种方式就很有用
module.exports = {
entry: ['./src/file_1.js', './src/file_2.js'],
output: {
filename: 'bundle.js',
},
};对象语法
用法:entry: { <entryChunkName> string | [string] } | {}
module.exports = {
entry: {
app: './src/app.js',
adminApp: './src/adminApp.js',
},
};对象语法会比较繁琐。然而,这是应用程序中定义入口的最可扩展的方式
webpack-merge 自定义扩展 (opens in a new tab)
“webpack 配置的可扩展” 是指,这些配置可以重复使用,并且可以与其他配置组合使用。这是一种流行的技术,用于将关注点从环境(environment)、构建目标(build target)、运行时(runtime)中分离。然后使用专门的工具(如 [webpack-merge])将它们合并起来。
当你通过插件生成入口时,你可以传递空对象 {} 给 entry
描述入口的对象
用于描述入口的对象。你可以使用如下属性:
-
dependOn: 当前入口所依赖的入口。它们必须在该入口被加载前被加载。 -
filename: 指定要输出的文件名称。 -
import: 启动时需加载的模块。 -
library: 指定 library 选项,为当前 entry 构建一个 library。 -
runtime: 运行时 chunk 的名字。如果设置了,就会创建一个新的运行时 chunk。在 webpack 5.43.0 之后可将其设为false以避免一个新的运行时 chunk。 -
publicPath: 当该入口的输出文件在浏览器中被引用时,为它们指定一个公共 URL 地址。请查看 output.publicPath (opens in a new tab)。
module.exports = {
entry: {
a2: 'dependingfile.js',
b2: {
dependOn: 'a2',
import: './src/app.js',
},
},
};常见场景
分离app(应用程序)和vendor(第三方库)入口
// webpack.config.js
module.exports = {
entry: {
main: './src/app.js',
vendor: './src/vendor.js',
},
};// webpack.prod.js
module.exports = {
output: {
filename: '[name].[contenthash].bundle.js',
},
};// webpack.dev.js
module.exports = {
output: {
filename: '[name].bundle.js',
},
};这是什么? 这是告诉 webpack 我们想要配置 2 个单独的入口点(例如上面的示例)。
为什么? 这样你就可以在 vendor.js 中存入未做修改的必要 library 或文件(例如 Bootstrap, jQuery, 图片等),然后将它们打包在一起成为单独的 chunk。内容哈希保持不变,这使浏览器可以独立地缓存它们,从而减少了加载时间
在 webpack < 4 的版本中,通常将 vendor 作为一个单独的入口起点添加到 entry 选项中,以将其编译为一个单独的文件(与 CommonsChunkPlugin 结合使用)。
而在 webpack 4 中不鼓励这样做。而是使用 [optimization.splitChunks] 选项,将 vendor 和 app(应用程序) 模块分开,并为其创建一个单独的文件。不要 为 vendor 或其他不是执行起点创建 entry
webpack4之后可以使用optimization.splitChunks 将vendor和app分离
多页面应用程序
module.exports = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js',
},
};这是什么? 我们告诉 webpack 需要三个独立分离的依赖图(如上面的示例)。
为什么? 在多页面应用程序中,server 会拉取一个新的 HTML 文档给你的客户端。页面重新加载此新文档,并且资源被重新下载。然而,这给了我们特殊的机会去做很多事,例如使用 [optimization.splitChunks] 为页面间共享的应用程序代码创建 bundle。由于入口起点数量的增多,多页应用能够复用多个入口起点之间的大量代码/模块,从而可以极大地从这些技术中受益
多页应用中可以有哪些工程优化手段?
可以使用 optimization.splitChunks 为页面间共享的应用程序代码创建bundle 由于入口起点数量的增多,多页应用能够复用多个入口起点之间的大量代码/模块,从而可以极大地从这些技术中受益
输出(output)
可以通过配置 output 选项,告知 webpack 如何向硬盘写入编译文件。
注意,即使可以存在多个 entry 起点,但只能指定一个 output 配置
用法
在 webpack 配置中,output 属性的最低要求是,将它的值设置为一个对象,然后为将输出文件的文件名配置为一个 output.filename (opens in a new tab)
// 此配置将一个单独的 `bundle.js` 文件输出到 `dist` 目录中
module.exports = {
output: {
filename: 'bundle.js',
},
};多个入口起点
如果配置中创建出多于一个 "chunk"(例如,使用多个入口起点或使用像 CommonsChunkPlugin 这样的插件),则应该使用 占位符(substitutions) (opens in a new tab) 来确保每个文件具有唯一的名称
使用 '[name].bundle.js' [] 为占位符 来确保每个文件具有唯一的名称
module.exports = {
entry: {
app: './src/app.js',
search: './src/search.js',
},
output: {
filename: '[name].js',
path: __dirname + '/dist',
},
};
// 写入到硬盘:./dist/app.js, ./dist/search.js高级进阶
以下是对资源使用 CDN 和 hash 的复杂示例
module.exports = {
//...
output: {
path: '/home/proj/cdn/assets/[fullhash]',
publicPath: 'https://cdn.example.com/assets/[fullhash]/',
},
};publicPath 表示资源(assets)被引用的根路径,在生产环境下生效;可以是相对路径,也可以是绝对路径 path 目录对应一个 绝对路径
output config (opens in a new tab)

如果在编译时,不知道最终输出文件的 publicPath 是什么地址,则可以将其留空,并且在运行时通过入口起点文件中的 __webpack_public_path__ 动态设置
__webpack_public_path__ = myRuntimePublicPath;
// 应用程序入口的其余部分loader
loader 用于对模块的源代码进行转换。loader 可以使你在 import 或 "load(加载)" 模块时预处理文件。
因此,loader 类似于其他构建工具中“任务(task)”,并提供了处理前端构建步骤的得力方式。
loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript 或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS 文件!
示例
例如,你可以使用 loader 告诉 webpack 加载 CSS 文件,或者将 TypeScript 转为 JavaScript。
为此,首先安装相对应的 loader
npm install --save-dev css-loader ts-loader
## or
yarn add css-loader ts-loader -D然后指示 webpack 对每个 .css 使用 css-loader (opens in a new tab),以及对所有 .ts 文件使用 ts-loader (opens in a new tab)
module.exports = {
module: {
rules: [
{ test: /\.css$/, use: 'css-loader' },
{ test: /\.ts$/, use: 'ts-loader' },
],
},
};使用loader
在你的应用程序中,有两种使用 loader 的方式:
- 配置方式 (opens in a new tab)(推荐):在 webpack.config.js 文件中指定 loader。
- 内联方式 (opens in a new tab):在每个
import语句中显式指定 loader。
Configuration
module.rules (opens in a new tab) 允许你在 webpack 配置中指定多个 loader。
这种方式是展示 loader 的一种简明方式,并且有助于使代码变得简洁和易于维护。同时让你对各个 loader 有个全局概览:
loader 从右到左(或从下到上)地取值(evaluate)/执行(execute)。
在下面的示例中,从 sass-loader 开始执行,然后继续执行 css-loader,最后以 style-loader 为结束。查看 loader 功能 (opens in a new tab) 章节,了解有关 loader 顺序的更多信息
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
// [style-loader](/loaders/style-loader)
{ loader: 'style-loader' },
// [css-loader](/loaders/css-loader)
{
loader: 'css-loader',
options: {
modules: true
}
},
// [sass-loader](/loaders/sass-loader)
{ loader: 'sass-loader' }
]
}
]
}
};内联方式(不推荐)
可以在 import 语句或任何 与 "import" 方法同等的引用方式 (opens in a new tab) 中指定 loader。
使用 ! 将资源中的 loader 分开。每个部分都会相对于当前目录解析
通过为内联
import语句添加前缀,可以覆盖 配置 (opens in a new tab) 中的所有 loader, preLoader 和 postLoader:
// 使用 `!` 前缀,将禁用所有已配置的 normal loader(普通 loader)
import Styles from '!style-loader!css-loader?modules!./styles.css';
// 使用 `!!` 前缀,将禁用所有已配置的 loader(preLoader, loader, postLoader)
import Styles from '!!style-loader!css-loader?modules!./styles.css';
// 使用 `-!` 前缀,将禁用所有已配置的 preLoader 和 loader,但是不禁用 postLoaders
import Styles from '-!style-loader!css-loader?modules!./styles.css';
选项可以传递查询参数,例如
?key=value&foo=bar,或者一个 JSON 对象,例如?{"key":"value","foo":"bar"}
loader 特性
- loader 支持链式调用。链中的每个 loader 会将转换应用在已处理过的资源上。一组链式的 loader 将按照相反的顺序执行。链中的第一个 loader 将其结果(也就是应用过转换后的资源)传递给下一个 loader,依此类推。最后,链中的最后一个 loader,返回 webpack 所期望的 JavaScript。
- loader 可以是同步的,也可以是异步的。
- loader 运行在 Node.js 中,并且能够执行任何操作。
- loader 可以通过
options对象配置(仍然支持使用query参数来设置选项,但是这种方式已被废弃)。 - 除了常见的通过
package.json的main来将一个 npm 模块导出为 loader,还可以在 module.rules 中使用loader字段直接引用一个模块。 - 插件(plugin)可以为 loader 带来更多特性。
- loader 能够产生额外的任意文件。
可以通过 loader 的预处理函数,为 JavaScript 生态系统提供更多能力。
用户现在可以更加灵活地引入细粒度逻辑,例如:压缩、打包、语言转译(或编译)和 更多其他特性 (opens in a new tab)。
解析 loader
loader 遵循标准 模块解析 (opens in a new tab) 规则。多数情况下,loader 将从 模块路径 (opens in a new tab) 加载(通常是从 npm install, node_modules 进行加载)。
我们预期 loader 模块导出为一个函数,并且编写为 Node.js 兼容的 JavaScript。
通常使用 npm 进行管理 loader,但是也可以将应用程序中的文件作为自定义 loader。
按照约定,loader 通常被命名为
xxx-loader(例如json-loader)。更多详细信息,请查看 编写一个 loader (opens in a new tab)
plugin
插件 是 webpack 的 支柱 (opens in a new tab) 功能。Webpack 自身也是构建于你在 webpack 配置中用到的 相同的插件系统 之上!
插件目的在于解决 loader (opens in a new tab) 无法实现的其他事。Webpack 提供很多开箱即用的 插件 (opens in a new tab)
如果在插件中使用了
webpack-sources(opens in a new tab) 的 package,请使用require('webpack').sources替代require('webpack-sources'),以避免持久缓存的版本冲突
剖析
webpack 插件是一个具有 apply (opens in a new tab) 方法的 JavaScript 对象。apply 方法会被 webpack compiler 调用,并且在 整个 编译生命周期都可以访问 compiler 对象。
ConsoleLogOnBuildWebpackPlugin.js
const pluginName = 'ConsoleLogOnBuildWebpackPlugin';
class ConsoleLogOnBuildWebpackPlugin {
apply(compiler) {
compiler.hooks.run.tap(pluginName, (compilation) => {
console.log('webpack 构建正在启动!');
});
}
}
module.exports = ConsoleLogOnBuildWebpackPlugin;compiler hook 的 tap 方法的第一个参数,应该是驼峰式命名的插件名称。建议为此使用一个常量,以便它可以在所有 hook 中重复使用
用法
由于插件可以携带参数/选项,你必须在 webpack 配置中,向 plugins 属性传入一个 new 实例。
取决于你的 webpack 用法,对应有多种使用插件的方式
配置方式
webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack'); // 访问内置的插件
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
filename: 'my-first-webpack.bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: 'babel-loader',
},
],
},
plugins: [
new webpack.ProgressPlugin(),
new HtmlWebpackPlugin({ template: './src/index.html' }),
],
};ProgressPlugin 用于自定义编译过程中的进度报告,HtmlWebpackPlugin 将生成一个 HTML 文件,并在其中使用 script 引入一个名为 my-first-webpack.bundle.js 的 JS 文件
Node API 方式
在使用 Node API 时,还可以通过配置中的 plugins 属性传入插件
some-node-script.js
const webpack = require('webpack'); // 访问 webpack 运行时(runtime)
const configuration = require('./webpack.config.js');
let compiler = webpack(configuration);
new webpack.ProgressPlugin().apply(compiler);
compiler.run(function (err, stats) {
// ...
});你知道吗:以上看到的示例和 webpack 运行时(runtime)本身 (opens in a new tab) 极其类似。webpack 源码 (opens in a new tab) 中隐藏有大量使用示例,你可以将其应用在自己的配置和脚本中
配置(Configuration)
你可能已经注意到,很少有 webpack 配置看起来完全相同。这是因为 webpack 的配置文件是 JavaScript 文件,文件内导出了一个 webpack 配置的对象 (opens in a new tab)。 webpack 会根据该配置定义的属性进行处理。
webpack 中配置规范 遵循CommonJS模块规范
由于 webpack 遵循 CommonJS 模块规范,因此,你可以在配置中使用:
- 通过
require(...)引入其他文件 - 通过
require(...)使用 npm 下载的工具函数 - 使用 JavaScript 控制流表达式,例如
?:操作符 - 对 value 使用常量或变量赋值
- 编写并执行函数,生成部分配置
请在合适的场景,使用这些功能。
webpack 中应该注意的配置
虽然技术上可行,但还是应避免如下操作:
- 当使用 webpack CLI 工具时,访问 CLI 参数(应编写自己的 CLI 工具替代,或者使用
--env(opens in a new tab)) - 导出不确定的结果(两次调用 webpack 应产生相同的输出文件)
- 编写超长的配置(应将配置文件拆分成多个)
接下来的示例中,展示了 webpack 配置如何实现既可表达,又可灵活配置,这主要得益于 配置即为代码
基本配置
const path = require('path');
module.exports = {
mode: 'development',
entry: './foo.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'foo.bundle.js',
},
};查看:配置章节 (opens in a new tab)中所有支持的配置选项
多个target
除了可以将单个配置导出为 object,function (opens in a new tab) 或 Promise (opens in a new tab) 以外,还可以将其导出为多个配置。
查看:导出多个配置 (opens in a new tab)
使用其他配置语言
Webpack 支持由多种编程和数据语言编写的配置文件。
模块(Modules)
在模块化编程 (opens in a new tab)中,开发者将程序分解为功能离散的 chunk,并称之为 模块。
每个模块都拥有小于完整程序的体积,使得验证、调试及测试变得轻而易举。
精心编写的 模块 提供了可靠的抽象和封装界限,使得应用程序中每个模块都具备了条理清晰的设计和明确的目的
何为 webpack 模块
与 Node.js 模块 (opens in a new tab)相比,webpack 模块 能以各种方式表达它们的依赖关系。下面是一些示例:
- ES2015
import(opens in a new tab) 语句 - CommonJS (opens in a new tab)
require()语句 - AMD (opens in a new tab)
define和require语句 - css/sass/less 文件中的
@import语句 (opens in a new tab)。 - stylesheet
url(...)或者 HTML<img src=...>文件中的图片链接
支持的模块类型
Webpack 天生支持如下模块类型:
- ECMAScript 模块 (opens in a new tab)
- CommonJS 模块
- AMD 模块
- Assets (opens in a new tab)
- WebAssembly 模块
通过 loader 可以使 webpack 支持多种语言和预处理器语法编写的模块。loader 向 webpack 描述了如何处理非原生_模块_,并将相关依赖引入到你的 bundles中。 webpack 社区已经为各种流行的语言和预处理器创建了 loader,其中包括:
- CoffeeScript (opens in a new tab)
- TypeScript (opens in a new tab)
- ESNext (Babel) (opens in a new tab)
- Sass (opens in a new tab)
- Less (opens in a new tab)
- Stylus (opens in a new tab)
- Elm (opens in a new tab)
当然还有更多!总得来说,webpack 提供了可定制,强大且丰富的 API,允许在 任何技术栈 中使用,同时支持在开发、测试和生产环境的工作流中做到 无侵入性。
关于 loader 的相关信息,请参考 loader 列表 (opens in a new tab) 或 自定义 loader (opens in a new tab)。
模块解析 (Module Resolution)
resolver 是一个帮助寻找模块绝对路径的库。
一个模块可以作为另一个模块的依赖模块,然后被后者引用,如下:
import foo from 'path/to/module';
// 或者
require('path/to/module');所依赖的模块可以是来自应用程序的代码或第三方库。
resolver 帮助 webpack 从每个 require/import 语句中,找到需要引入到 bundle 中的模块代码。
当打包模块时,webpack 使用 enhanced-resolve (opens in a new tab) 来解析文件路径。
webpack 中的解析规则
使用 enhanced-resolve,webpack 能解析三种文件路径:
绝对路径
import '/home/me/file';
import 'C:\\Users\\me\\file';
由于已经获得文件的绝对路径,因此不需要再做进一步解析
相对路径
import '../src/file1';
import './file2';在这种情况下,使用 import 或 require 的资源文件所处的目录,被认为是上下文目录。在 import/require 中给定的相对路径,会拼接此上下文路径,来生成模块的绝对路径
模块路径
在 resolve.modules (opens in a new tab) 中指定的所有目录中检索模块。 你可以通过配置别名的方式来替换初始模块路径,具体请参照 resolve.alias (opens in a new tab) 配置选项。
- 如果 package 中包含
package.json文件,那么在resolve.exportsFields(opens in a new tab) 配置选项中指定的字段会被依次查找,package.json中的第一个字段会根据 package 导出指南 (opens in a new tab)确定 package 中可用的 export。
一旦根据上述规则解析路径后,resolver 将会检查路径是指向文件还是文件夹。如果路径指向文件:
- 如果文件具有扩展名,则直接将文件打包。
- 否则,将使用
resolve.extensions(opens in a new tab) 选项作为文件扩展名来解析,此选项会告诉解析器在解析中能够接受那些扩展名(例如.js,.jsx)。
如果路径指向一个文件夹,则进行如下步骤寻找具有正确扩展名的文件:
- 如果文件夹中包含
package.json文件,则会根据resolve.mainFields(opens in a new tab) 配置中的字段顺序查找,并根据package.json中的符合配置要求的第一个字段来确定文件路径。 - 如果不存在
package.json文件或resolve.mainFields(opens in a new tab) 没有返回有效路径,则会根据resolve.mainFiles(opens in a new tab) 配置选项中指定的文件名顺序查找,看是否能在 import/require 的目录下匹配到一个存在的文件名。 - 然后使用
resolve.extensions(opens in a new tab) 选项,以类似的方式解析文件扩展名。
Webpack 会根据构建目标,为这些选项提供合理的默认 (opens in a new tab)配置
解析 loader
loader 的解析规则也遵循特定的规范。但是 resolveLoader (opens in a new tab) 配置项可以为 loader 设置独立的解析规则
缓存
每次文件系统访问文件都会被缓存,以便于更快触发对同一文件的多个并行或串行请求。
在 watch 模式 (opens in a new tab) 下,只有修改过的文件会被从缓存中移出。如果关闭 watch 模式,则会在每次编译前清理缓存。
欲了解更多上述配置信息,请查阅 Resolve API (opens in a new tab)
模块联邦(Module Federation)⌛️
依赖图(Dependency Graph)
每当一个文件依赖另一个文件时,webpack 都会将文件视为直接存在 依赖关系。
这使得 webpack 可以获取非代码资源,如 images 或 web 字体等。并会把它们作为 依赖 提供给应用程序。
当 webpack 处理应用程序时,它会根据命令行参数中或配置文件中定义的模块列表开始处理。
从 入口 (opens in a new tab) 开始,webpack 会递归的构建一个 依赖关系图,这个依赖图包含着应用程序中所需的每个模块,然后将所有模块打包为少量的 bundle —— 通常只有一个 —— 可由浏览器加载
对于 HTTP/1.1 的应用程序来说,由 webpack 构建的 bundle 非常强大。当浏览器发起请求时,它能最大程度的减少应用的等待时间。而对于 HTTP/2 来说,你还可以使用代码分割 (opens in a new tab)进行进一步优化
随着http/2 协议的普及我们可以通过 代码分割 来最大化并行加载大型前端应用的bundle
Further Reading
target
由于 JavaScript 既可以编写服务端代码也可以编写浏览器代码,所以 webpack 提供了多种部署 target,你可以在 webpack 的配置选项 (opens in a new tab)中进行设置。
webpack 的
target属性,不要和output.libraryTarget属性混淆。有关output属性的更多信息,请参阅 output 指南 (opens in a new tab)
用法
想设置 target 属性,只需在 webpack 配置中设置 target 字段
module.exports = {
target: 'node',
};在上述示例中,target 设置为 node,webpack 将在类 Node.js 环境编译代码。(使用 Node.js 的 require 加载 chunk,而不加载任何内置模块,如 fs 或 path)。
每个 target 都包含各种 deployment(部署)/environment(环境)特定的附加项,以满足其需求。具体请参阅 target 可用值 (opens in a new tab)
多 target
虽然 webpack 不支持 向 target 属性传入多个字符串,但是可以通过设置两个独立配置,来构建对 library 进行同构
const path = require('path');
const serverConfig = {
target: 'node',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'lib.node.js',
},
//…
};
const clientConfig = {
target: 'web', // <=== 默认为 'web',可省略
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'lib.js',
},
//…
};
module.exports = [serverConfig, clientConfig];上述示例中,将会在 dist 文件夹下创建 lib.js 和 lib.node.js 文件
资源
从上面选项可以看出,你可以选择部署不同的 target。下面是可以参考的示例和资源:
- compare-webpack-target-bundles (opens in a new tab):测试并查看 webpack target 的绝佳资源。同样包含错误上报。
- Boilerplate of Electron-React Application (opens in a new tab): 一个关于 electron 主进程和渲染进程构建过程的优秀示例
manifest
在使用 webpack 构建的典型应用程序或站点中,有三种主要的代码类型:
- 你或你的团队编写的源码。
- 你的源码会依赖的任何第三方的 library 或 "vendor" 代码。
- webpack 的 runtime 和 manifest,管理所有模块的交互。
本文将重点介绍这三个部分中的最后部分:runtime 和 manifest,特别是 manifest。