在 webpack
中配置中 output
属性的最低要求是,将它的值设置为一个对象,里面包含一系列配置项,指示 webpack
如何去输出、以及在哪里输出你的的资源。
output.filename
filename
属性,决定打包好的资源输出到 output.path
选项指定目录位置的文件名,如果只输出一个文件,可以把 filename
属性写成静态不变的名称。
module.exports = {
output:"bundle.js"
}
但是,当有多个入口起点、代码拆分或插件从而创建多个输出文件时,应该使用模板变量来为每个输出赋予不同的名称。
使用入口名称:
module.exports = {
entry:{
index:"./src/a.js",
main:"./src/b.js"
},
output:{
filename:"[name].bundle.js"
}
}
上面配置里,输出文件中的 [name]
指代入口起点键值对里的键,即:index
和main
。从而输出的文件名分别为index.bundle.js
和main.bundle.js
。
使用内部 chunk id:
filename: "[id].bundle.js"
使用 hash 生成
filename: "[name].[hash].bundle.js"
使用 chunk 内容的 hash:
filename: "[chunkhash].bundle.js"
webpack
输出文件名有如下内置的模板变量:
模板 | 描述 |
---|---|
[hash] | 模块标识符(module identifier)的 hash |
[chunkhash] | chunk 内容的 hash |
[name] | 模块名称 |
[id] | 模块标识符(module identifier) |
[query] | 模块的 查询参数,例如,文件名 ? 后面的字符串 |
注意,这些变量虽用于文件名,但是你还是可以使用像
"js/[name]/bundle.js"
这样的文件夹结构。
[hash]
和 [chunkhash]
的长度可以使用 [hash:16]
来指定(默认为20)。或者,通过指定output.hashDigestLength
在全局配置长度。
hash & chunkhash & contenthash
hash
:webpack
在打包时会生成一个唯一的标识符来指代本次打包过程。相同编译打包过程中的模块共有这个标识符,也就是说同一打包过程产出的产物的hash
值都是一样的。
chunkhash
:指的是webpack
根据每个chunk
生成的标识符。不同的chunk
其chunkhash
不同,当每个chunk
所依赖的模块内容改变后,打包出来的chunkhash
会发生变化。没做修改的chunk
则chunkhash
值不变。
contenthash
:根据文件内容来定义的标识符,如果一个js
文件里面引入了css
文件,修改了js
,但没修改css
,想让css
的打包不变能继续利用缓存。我们使用mini-css-extract-plugin
插件。
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [
new MiniCssExtractPlugin({
filename: 'css/main.[contenthash:7].css'
})
],
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader"
]
}
]
}
}
output.chunkFilename
chunk
是指webpack
在進行模块的依赖分析時,代码分割出来的代码块。
output.chunkFilename
配置没有入口起点的 Chunk
输出时的文件名称(代码拆分或插件等),只用于指定在运行过程中(runtime)生成的 Chunk
在输出时的文件名称。chunkFilename
支持和 filename
一致的内置模板变量。
默认使用 [id].js
或从 output.filename
中推断出的值([name]
会被预先替换为 [id]
或 [id].
)
module.exprots = {
entry: {
main:'./src/index.js',
a:['./src/a.js','./src/c.js'],
},
output: {
filename: "js/[name].[hash].js",
path:path.resolve(__dirname,"./dist"),
chunkFilename:'js/[name].[id].[chunkhash].js'
}
}
output.path
output.path
配置输出文件存放的目录,必须是表示绝对路径的字符串。
const path = require('path')
module.exports = {
//...
entry: {
main:'./src/index.js',
a:['./src/a.js','./src/c.js'],
},
output: {
filename: "js/[hash]/[name].js",
path:path.resolve(__dirname,"./dist"),
publicPath:"/",
chunkFilename:'js/[name]/[id].[chunkhash].js'
}
//...
}
上面示范中,filename
、chunkFilename
不光指定文件名,其实可以解析目录结构的。
output.path
支持且仅支持一个模板变量:[hash]
path:path.resolve(__dirname,".//[hash]dist"),
output.publicPath
在一个项目里可能会有一些构建出的资源需要异步加载/按需加载,在项目条件允许时,我们通常把静态资源(图片、js、css、视频等)存放入CDN。这时,output.publicPath
选项就非常重要了。
output.publicPath
配置发布到线上资源的 URL
前缀,是一个字符串。 默认值是空字符串 '',即使用相对路径。选项的值都会以 /
结束。
比如设置:
filename:'[name]_[chunkhash:8].js'
publicPath: 'https://cdn.example.com/assets/'
那么发布到线上的 HTML 在引入 JavaScript
文件时就需要:
<script src='https://cdn.example.com/assets/a_12345678.js'></script>
对于如下设置:
publicPath: "/assets/",
chunkFilename: "[id].chunk.js"
那么在请求此 chunk
时,类似:/assets/4.chunk.js
对于HTML加载图片可能会像这样输出:
<link href="/assets/spinner.gif" />
或者在加载 CSS 的一个图片时:
background-image: url(/assets/spinner.gif);
webpack-dev-server
也会默认从 publicPath
为基准,使用它来决定在哪个目录下启用服务,来访问 webpack
输出的文件。
output.publicPath
支持且仅支持一个模板变量:[hash]
publicPath: "https://cdn.example.com/assets/", // CDN(总是 HTTPS 协议)
publicPath: "//cdn.example.com/assets/", // CDN (协议相同)
publicPath: "/assets/", // 相对于服务(server-relative)
publicPath: "assets/", // 相对于 HTML 页面
publicPath: "../assets/", // 相对于 HTML 页面
publicPath: "", // 相对于 HTML 页面(目录相同)
在编译时无法确定输出文件的 publicPath
,可以留空,然后在入口文件处使用自由变量 __webpack_public_path__
,以便在运行时进行动态设置。
__webpack_public_path__ = myRuntimePublicPath
output.crossOriginLoading
该属性只适合于配置里设置了target
为web
情况,Webpack
输出的部分代码块可能需要异步加载/按需加载,而这些异步加载是通过 JSONP
向 HTML
中插入一个 <script src="url"></script>
标签来加载异步资源。output.crossOriginLoading
本质就是来设置这个script
标签的crossorigin
属性。
crossOriginLoading: false
: 禁用跨域加载(默认)crossOriginLoading: "anonymous"
- 不会带上用户的 Cookies 启用跨域加载crossOriginLoading: "use-credentials"
- 带上用户的 Cookies 启用跨域加载
output.libraryTarget
当用webpack
构建一个能被其他模板引入使用的库时,用这些选项来配置如何把库暴露出来。此选项与分配给 output.library
的值一同使用。下面的所有示例,都假定将 output.library
的值配置为 MyLibrary
。
暴露为一个变量
var
这是output.libraryTarget
默认值。
libraryTarget: "var"
当设置为var
时,打包好的库里将入口文件的返回值赋予给output.library
配置的变量名。
var MyLibrary = _entry_return_;
当使用
var
选项时,将output.library
设置为空,会因为没有变量导致无法赋值。其打包后的文件内容直接为入口文件的返回值。
当引入这个库时,直接使用库名称即可
MyLibrary.doSomething();
assign
libraryTarget: "assign"
- 这将产生一个隐含的全局变量,可能会潜在地重新分配到全局中已存在的值。打包好的库文件里库名没用使用var
申明
MyLibrary = _entry_return_;
如果 MyLibrary
在作用域中未在前面代码进行定义,则你的 library
将被设置在全局作用域内。
当使用此选项时,将
output.library
设置为空,将产生一个破损的输出bundle
。
对象上赋值暴露
将入口起点的返回值赋值给一个特定对象的属性下。对象为output.libraryTarget
值,其属性为output.library
的值。
如果 output.library
赋值为空字符串,则默认行为是,将入口起点返回的所有属性都赋值给output.libraryTarget
设置的对象,通过如下代码片段:
(function(e, a) { for(var i in a) e[i] = a[i]; }(${output.libraryTarget}, _entry_return_)
注意,不设置
output.library
将导致由入口起点返回的所有属性,都会被赋值给给定的对象;这里并不会检查现有的属性名是否存在。
this
libraryTarget: "this"
- 入口起点的返回值将分配给 this
的一个属性(此名称由 output.library
定义)下,this
的含义取决于你:
this["MyLibrary"] = _entry_return_;
// 在一个单独的 script……
this.MyLibrary.doSomething();
MyLibrary.doSomething(); // 如果 this 是 window
window
libraryTarget: "window"
- 入口起点的返回值将使用 output.library
中定义的值,分配给 window
对象的这个属性下。
window["MyLibrary"] = _entry_return_;
window.MyLibrary.doSomething();
global
libraryTarget: "global"
- 入口起点的返回值将使用 output.library
中定义的值,分配给 global
对象的这个属性下。
global["MyLibrary"] = _entry_return_;
global.MyLibrary.doSomething();
commonjs
libraryTarget: "commonjs"
- 入口起点的返回值将使用 output.library
中定义的值,分配给 exports
对象。这个名称也意味着,模块用于 CommonJS
环境:
exports["MyLibrary"] = _entry_return_;
require("MyLibrary").doSomething();
commonjs2
libraryTarget: "commonjs2"
- 入口起点的返回值将分配给 module.exports
对象。这个名称也意味着模块用于 CommonJS
环境:
module.exports = _entry_return_;
require("MyLibrary").doSomething();
注意,output.library
会被省略,因此对于此特定的 output.libraryTarget
,无需再设置 output.library
。
CommonJS2 和 CommonJS 规范很相似,差别在于 CommonJS 只能用
exports
导出,而 CommonJS2 在 CommonJS 的基础上增加了module.exports
的导出方式。
output.library
output.library
的值的作用,取决于output.libraryTarget
选项的值;注意,output.libraryTarget
的默认选项是 var
,所以如果使用以下配置选项:
output: {
library: "MyLibrary"
}
如果生成的输出文件,是在 HTML 页面中作为一个 script 标签引入,则变量 MyLibrary
将与入口文件的返回值绑定。
如果将数组作为
entry
,那么只会暴露数组中的最后一个模块。如果将对象作为entry
,还可以使用数组语法暴露
output.libraryExport
配置通过libraryTarget
那些模块将被暴露出来,默认值是一个命名空间或者是入口文件返回的默认模块,下面的示例演示了配置为libraryTarget: "var"
时的效果,其实可以配置为任何其他选项。
libraryExport: "default"
- 把入口起点默认的输出分配目标库:
// if your entry has a default export of `MyDefaultModule`
var MyDefaultModule = _entry_return_.default;
libraryExport: "MyModule"
- 指定的模块被分配给目标库:
var MyModule = _entry_return_.MyModule;
libraryExport: ["MyModule", "MySubModule"]
- 数组作为一个模块的路径来理解,并把这个模块分配给目标库:
var MySubModule = _entry_return_.MyModule.MySubModule;
像上面那样配置libraryExport
,那么可以像下面这样来使用生成的库
MyDefaultModule.doSomething();
MyModule.doSomething();
MySubModule.doSomething();