configuration
- webpack 的配置文件,是导出一个对象的 JavaScript 文件
- 因为 webpack 配置是标准的 Node.js CommonJS 模块,你可以做到以下事情:
- 通过 require(...) 导入其他文件
- 使用 JavaScript 控制流表达式,例如 ?: 操作符
- 对常用值使用常量或变量
- 编写并执行函数来生成部分配置
entry
- 入口起点:指示webpack应该使用哪个模块来作为构建其内部依赖图的开始
- 每个HTML页面都有一个入口起点
- 单页面应用(SPA):一个入口起点,多页面应用(MPA):多个入口起点
- 动态加载模块不是入口起点
output
配置 output 选项可以控制 webpack 如何向硬盘写入编译文件;注意,即使可以存在多个入口起点,但只指定一个输出配置
-
多个入口起点:
如果配置创建了多个单独的 "chunk"(例如,使用多个入口起点或使用像 CommonsChunkPlugin 这样的插件),则应该使用占位符(substitutions)来确保每个文件具有唯一的名称
```
{
entry: {
app: './src/app.js',
search: './src/search.js'
},
output: {
filename: '[name].js',
path: __dirname + '/dist'
}
}// 写入到硬盘:./dist/app.js, ./dist/search.js
loader
- loader 让webpack有能力处理那些非JavaScript文件(webpack 自身只理解JavaScript )[转换某些类型的模块]
- test属性:标识出应该被对应loader进行转换的某些或某个文件
- use:进行转换时应该使用哪个loader
- loader 支持链式传递。能够对资源使用流水线(pipeline)。一组链式的 loader 将按照相反的顺序执行。loader 链中的第一个 loader 返回值给下一个 loader。在最后一个 loader,返回 webpack 所预期的 JavaScript
plugin
- 插件目的在于解决 loader 无法实现的其他事
- 插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量
- 使用:首先通过
require()
导入,然后将它添加到plugins数组中;当在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 new 操作符来创建它的一个实例 - 由于插件可以携带参数/选项,你必须在 webpack 配置中,向 plugins 属性传入 new 实例。
- 多数插件可以通过选项(option)来配置
file loader
即使含有
jsx
的语法的文件后缀是js
,webpack
在加载文件时test
的正则表达式依然要包含jsx
publicPath
确保
publicPath
总是以斜杆( / )开头和结尾
CommonsChunkPlugin
从应用程序bundle中提取vendor引用到vendor bundle,并把引用vendor的部分替换为
__webpack__require()
调用
module resolution
- resolver 是一个库(library),用于帮助找到模块的绝对路径
- 解析器(resolver)将检查路径是否指向文件或目录。如果路径指向一个文件:
- 如果路径具有文件扩展名,则被直接将文件打包
- 否则,将使用 [resolve.extensions] 选项作为文件扩展名来解析,此选项告诉解析器在解析中能够接受哪些扩展名(例如 .js, .jsx)
- 如果路径指向一个文件夹,则采取以下步骤找到具有正确扩展名的正确文件:
- 如果文件夹中包含 package.json 文件,则按照顺序查找 resolve.mainFields 配置选项中指定的字段。并且 package.json 中的第一个这样的字段确定文件路径
- 如果 package.json 文件不存在或者 package.json 文件中的 main 字段没有返回一个有效路径,则按照顺序查找 resolve.mainFiles 配置选项中指定的文件名,看是否能在 import/require 目录下匹配到一个存在的文件名
- 文件扩展名通过 resolve.extensions 选项采用类似的方法进行解析
- resolve.alias: 替换初始模块路径,来确保模块引入变得更简单; 例如一些位于 src/ 文件夹下的常用模块:
alias: { Utilities: path.resolve(__dirname, 'src/utilities/'), Templates: path.resolve(__dirname, 'src/templates/') }
output.filename
- 决定了每个输出 bundle 的名称
- 对于单个入口起点,filename 会是一个静态名称
filename: "bundle.js"
- 然而,当通过多个入口起点(entry point)、代码拆分(code splitting)或各种插件(plugin)创建多个 bundle,应该使用以下一种替换方式,来赋予每个 bundle 一个唯一的名称
- 使用入口名称:
filename: "[name].bundle.js"
- 使用内部 chunk id
filename: "[id].bundle.js"
- 使用每次构建过程中,唯一的 hash 生成
filename: "[name].[hash].bundle.js"
- 使用基于每个 chunk 内容的 hash:
filename: "[chunkhash].bundle.js"
output.chunkFileName
- 此选项决定了非入口(non-entry) chunk 文件的名称
CommonsChunkPlugin
通过将公共模块(chunk)拆出来,最终合成的文件(另一个chunk)能够在最开始的时候加载一次,便缓存到缓存中供后续使用
-
配置:
{ name: string, // or names: string[], // 这是 common chunk 的名称。已经存在的 chunk 可以通过传入一个已存在的 chunk 名称而被选择。 // 如果一个字符串数组被传入,这相当于插件针对每个 chunk 名被多次调用 // 如果该选项被忽略,同时 `options.async` 或者 `options.children` 被设置,所有的 chunk 都会被使用, // 否则 `options.filename` 会用于作为 chunk 名。 // When using `options.async` to create common chunks from other async chunks you must specify an entry-point // chunk name here instead of omitting the `option.name`. filename: string, // common chunk 的文件名模板。可以包含与 `output.filename` 相同的占位符。 // 如果被忽略,原本的文件名不会被修改(通常是 `output.filename` 或者 `output.chunkFilename`)。 // This option is not permitted if you're using `options.async` as well, see below for more details. minChunks: number|Infinity|function(module, count) => boolean, // 在传入 公共chunk(commons chunk) 之前所需要包含的最少数量的 chunks 。 // 数量必须大于等于2,或者少于等于 chunks的数量 // 传入 `Infinity` 会马上生成 公共chunk,但里面没有模块。 // 你可以传入一个 `function` ,以添加定制的逻辑(默认是 chunk 的数量) chunks: string[], // 通过 chunk name 去选择 chunks 的来源。chunk 必须是 公共chunk 的子模块。 // 如果被忽略,所有的,所有的 入口chunk (entry chunk) 都会被选择。 children: boolean, // 如果设置为 `true`,所有公共 chunk 的子模块都会被选择 deepChildren: boolean, // 如果设置为 `true`,所有公共 chunk 的后代模块都会被选择 async: boolean|string, // 如果设置为 `true`,一个异步的 公共chunk 会作为 `options.name` 的子模块,和 `options.chunks` 的兄弟模块被创建。 // 它会与 `options.chunks` 并行被加载。 // Instead of using `option.filename`, it is possible to change the name of the output file by providing // the desired string here instead of `true`. minSize: number, // 在 公共chunk 被创建立之前,所有 公共模块 (common module) 的最少大小。 }
-
给 minChunks 配置传入函数:
你也可以给 minChunks 传入一个函数。这个函数会被 CommonsChunkPlugin 插件回调,并且调用函数时会传入 module 和 count 参数;
module 参数代表每个 chunks 里的模块, 这些 chunks 是通过 name/names 参数传入的( 传入的chunk是没有被拆出来之前的公共模块; 配置中 name/names 字段的说明:
这是 common chunk 的名称。已经存在的 chunk 可以通过传入一个已存在的 chunk 名称而被选择
)
module 有两个有用的属性:
+ module.context:这个公共模块所在的目录,例如:'/my_project/node_modules/example-dependency'
+ module.resource: 这个公共模块的文件名,例如:'/my_project/node_modules/example-dependency/index.js'
> count 参数表示 module 被使用的 chunk 数量当你想要对 CommonsChunk 如何决定模块被打包到哪里的算法有更为细致的控制, 这个配置就会非常有用
new webpack.optimize.CommonsChunkPlugin({ name: 'my-single-lib-chunk', filename: 'my-single-lib-chunk.js', minChunks: function(module, count) { // 如果模块是一个路径,而且在路径中有 "somelib" 这个名字出现, // 而且它还被三个不同的 chunks/入口chunk 所使用,那请将它拆分到 // 另一个分开的 chunk 中,chunk 的 keyname 是 "my-single-lib-chunk",而文件名是 "my-single-lib-chunk.js" return module.resource && (/somelib/).test(module.resource) && count === 3; } });
> 正如上面看到的,这个例子允许你只将其中一个库移到一个分开的文件当中,当而仅当函数中的所有条件都被满足了
Manifest file
- 当编译器(compiler)开始执行、解析和映射应用程序时,它会保留所有模块的详细要点。这个数据集合称为 "Manifest",当完成打包并发送到浏览器时,会在运行时通过 Manifest 来解析和加载模块
- 分离manifest:将webpack的bootstrap(启动)逻辑提取到一个单独的文件中:
new webpack.optimize.CommonsChunkPlugin({ name: 'manifest', minChunks: Infinity });