简介
看《深入浅出 webpack》总结一下常用的 webpack 的属性的含义并加了一些自己的链接,写在一个文件下更能有全局感受,更能理解各个属性中间的关系,重点要关注 entry
,output
,resolve
,module
, plugins
几部分
配置示例
这并不是一个拿来可用的配置,主要是为了更好理解常用的一些 webpack 属性的作用,所以每一行都有注释,放到一起,更能看到每一个属性在其中的作用
module.exports = {
// __dirname 值为所在文件的目录,context 默认为执行 webpack 命令所在的目录
context: path.resolve(__dirname, 'app'),
// 必填项,编译入口,webpack 启动会从配置文件开始解析, 如下三种(还有一种动态加载 entry 的方式就是给 entry 传入一个函数,这个在项目比较大,页面很多的情况下可以优化编译时间)
entry: './app/entry', // 只有一个入口,入口只有一个文件
entry: ['./app/entry1', './app/entry2'], // 只有一个入口,入口有两个文件
// 两个入口
entry: {
entry1: './app/entry1',
entry2: './app/entry2'
},
// 输出文件配置
output: {
// 输出文件存放的目录,必须是 string 类型的绝对路径
path: path.resolve(__dirname, 'dist'),
// 输出文件的名称
filename: 'bundle.js',
filename: '[name].js', // 配置了多个入口 entry 是 [name] 的值会被入口的 key 值替换,此处输出文件会输出的文件名为 entry1.js 和 entry2.js
filename: [chunkhash].js, // 根据 chunk 的内容的 Hash 值生成文件的名称,其他只还有 id,hash,hash 和 chunkhash 后面可以使用:number 来取值,默认为 20 位,比如[name]@[chunkhash:12].js,
// 文件发布到线上的资源的 URL 前缀,一般用于描述 js 和 css 位置,举个例子,打包项目时会导出一些 html, 那么 html 里边注入的 script 和 link 的地址就是通过这里配置的
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 页面(目录相同)// 当需要构建的项目可以被其他模块导入使用,会用到 libraryTarget 和 library
library: 'xxx', // 配置导出库的名称,但是和 libraryTarget 有关,如果是 commonjs2 默认导出这个名字就没啥用
// 从 webpack3.1.0 开始,可以为每个 target 起不同的名称
library: {
root: "MyLibrary",
amd: "my-library",
commonjs: "my-common-library"
},
libraryTarget: 'umd', // 导出库的类型,枚举值: umd、commonjs2、commonjs,amd、this、var(默认)、assign、window、global、jsonp(区别查看补充 2)
// 需要单独导出的子模块,这样可以直接在引用的时候使用子模块,默认的时候是_entry_return_
libraryExport: 'default', // __entry_return_.default
libraryExport: 'MyModule', // __entry_return_.MyModule
libraryExport: ['MyModule', 'MySubModule'], // 使用数组代表到指定模块的取值路径 __entry_return_.MyModule.MySubModule
// 配置无入口的 chunk 在输出时的文件名称,但仅用于在运行过程中生成的 Chunk 在输出时的文件名称,这个应该一般和插件的导出有关,支持和 filename 一样的内置变量
chunkFilename: '[id].js',
// 是否包含文件依赖相关的注释信息,不懂?请看补充 3,在 mode 为 development 的是默认为 true
pathinfo: true,
// JSONP 异步加载 chunk,或者拼接多个初始 chunk(CommonsChunkPlugin,AggressiveSplittingPlugin)
jsonpFunction: 'myWebpackJsonp',
// 此选项会向应盘写入一个输出文件,只在 devtool 启动了 sourceMap 选项时采用,默认为 `[file].map`, 除了和 filename 一样外还可以使用[file]
sourceMapFilename: '[file].map',
// 浏览器开发者工具里显示的源码模块名称,此选项仅在「devtool 使用了需要模块名称的选项」时使用,使用 source-map 调试,关联模块鼠标移动到上面的时候显示的地址(截不到图啊,醉了),默认这个值是有的,一般不需要关心
devtoolModuleFilenameTemplate: 'testtest://[resource-path]'
},
// 配置模块相关
module: {
rules: [ // 配置 loaders
{
test: /\.jsx?$/, // 匹配规则,匹配文件使用,一般使用正则表达值
include: [path.resolve(__dirname, 'app')], // 只会命中这个目录文件
exclude: [path.resolve(__diranme, 'app/demo-files')], // 命中的时候排除的目录
use: [ // 使用的 loader,每一项为一个 loader,从该数组的最后一个往前执行
'style-loader', // loader 的名称, 这样则是使用默认配置,可以在后面加! 配置属性,也可以用下面方式
{
loader: 'css-loader', // loader 的名称
options: {} // loader 接受的参数}
],
noParse: [// 不用解析和处理的模块 RegExp | [RegExp] | function(从 webpack 3.0.0 开始)/jquery|lodash/
]
}
]
},
// 配置插件,关于和 loader 区别见补充 4
plugins: [
// 压缩 js 的 plugin
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
drop_console: false,
}
}),
],
// 解析文件引用的模块的配置
resolve: {
// 模块的根目录, 默认从 node_modules 开始找
modules: [
'node_modules',
'browser_modules'
],
// 模块的后缀名,我们引入模块有时候不写扩展名,自动补充扩展名的顺序如下
extensions: ['.js', '.json', '.jsx', '.css'],
// 模块解析时候的别名
alias: {
// 那么导入模块时则可以写 import myComponent from '$component/myComponent';
$component: './src/component',
// 末尾加 $ 精确匹配
xyz$: path.resolve(__dirname, 'path/to/file.js')
},
// 此选项决定优先使用 package.json 配置哪份导出文件,详见补充 5
mainFields: ['jsnext:main', 'browser', 'main'],
// 是否强制导入语句写明后缀
enforceExtension: false,
// 是否将符号链接 (symlink) 解析到它们的符号链接位置(symlink location)
symlinks: true,
},
// 选择一种 source map 格式来增强调试过程。不同的值会明显影响到构建 (build) 和重新构建 (rebuild) 的速度。devtool: 'source-map',
// 配置输出代码的运行环境,可以为 async-node,electron-main,electron-renderer,node,node-webkit,web(默认),webworker
target: 'web',
externals: { // 使用来自于 js 运行环境提供的全局变量
jquery: 'jQuery'
},
// 控制台输出日志控制
stats: {
assets: true, // 添加资源信息
colors: true, // 控制台日志信息是否有颜色
errors: true, // 添加错误信息
errorDetails: true, // 添加错误的详细信息(就像解析日志一样)hash: true, // 添加 compilation 的哈希值
},
devServer: { // 本地开发服务相关配置
proxy: { // 代理到后端服务接口
'/api': 'http://localhost:3000'
},
contentBase: path.join(__dirname, 'public'), // 配置 devserver http 服务器文件的根目录
compress: true, // 是否开启 gzip 压缩
hot: true, // 是否开启模块热交换功能
https: false, // 是否开启 https 模式
historyApiFallback: true, // 是否开发 HTML5 History API 网页,不太理解 TODO
},
profile: true, // 是否捕捉 webpack 构建的性能信息,用于分析是什么原因导致的构建性能不佳
cache: false, // 缓存生成的 webpack 模块和 chunk,来改善构建速度。缓存默认在观察模式 (watch mode) 启用。cache: {
// 如果传递一个对象,webpack 将使用这个对象进行缓存。保持对此对象的引用,将可以在 compiler 调用之间共享同一缓存:cache: SharedCache // let SharedCache = {}},
watch: true, // 是否启用监听模式
watchOptions: { // 监听模式选项
ignored: /node_modules/, // 不监听的文件或文件夹,支持正则匹配,默认为空
aggregateTimeout: 300, 监听到变化后,300ms 再执行动作,节流,防止文件更新频率太快导致重新编译频率太快
poll: 1000 // 检测文件是否变化,间隔时间
},
// 输出文件的性能检查配置
perfomance: {
hints: 'warning', // 有性能问题时输出警告
hints: 'error', // 有性能问题时输出错误
hints: false, // 关闭性能检查
maxAssetSize: 200000, // 最大文件大小,单位 bytes
maxEntrypointSize: 400000, // 最大入口文件的大小,单位 bytes
// 此属性允许 webpack 控制用于计算性能提示的文件。assetFilter: function(assetFilename) {return assetFilename.endsWith('.css') || assetFilename.endsWith('.js');
}
}
}
补充
补充 1.chunkname 是什么
就是打包后代码块的名字
补充 2. 补充不同的库导出方式的区别
-
var
var MyLibrary = _entry_return_; // 在一个单独的 script…… MyLibrary.doSomething();
- assign 暴露到全局变量中,不要用
- this 分配给 this,感觉会放在全局的 this 上, 官网说取决于你
-
window 将模块放在 window 上
window["MyLibrary"] = _entry_return_; window.MyLibrary.doSomething();
- global 调动方式使用
global['myLibrary']
- commonjs
-
commonjs2
说一下这两种区别,其实这说到了 exports 和 module.exports 的区别,exports 是 module.exports 的一个引用module.exports = {}; exports = module.exports; exports['aaaa'] = 1; // 这样是可以的,在 module.exports 上加了一个属性 exports = 2; // 会导致 exports 脱离了对 module.exports 的引用 modules.exports = 2 // 这样 exports 的至最后就是 2
那么其实 commonjs 的规定就是使用
exports
进行导出,而我们经常使用module.exports
导出,webpack 此处的方式其实就是选择到底是用exports
导出还是module.exports
导出,区别在于
如果选择 commonjs// webpack 输出为 exports['LibraryName'] = _entry_return_; // 使用库的方法为 require('library-name-in-npm')['LibraryName'].doSomething(); // 原因其实就是这么导出最后其实是 // modules.exports = {[LibraryName]: _entry_return_ }
如果选择 commonjs2
// webpack 输出为 module.exports = _entry_return_; // 使用库的方法为 require('library-name-in-npm').doSomething();
-
amd
// webpack 输出 define("MyLibrary", [], function() {return _entry_return_; // 此模块返回值,是入口 chunk 返回的值}); // 使用 require(['MyLibrary'], function(MyLibrary) {// 使用 library 做一些事……});
-
umd 将你的模块暴露为所有模块定义下都可运行的方式
(function webpackUniversalModuleDefinition(root, factory) {if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports["MyLibrary"] = factory(); else root["MyLibrary"] = factory();})(typeof self !== 'undefined' ? self : this, function() {return _entry_return_; // 此模块返回值,是入口 chunk 返回的值});
-
jsonp 你的 library 的依赖将由 externals 配置定义。
MyLibrary(_entry_return_);
补充 3.pathinfo 到底是哪些玩意
补充 4.plugins 和 loader 什么区别?
我的理解是
loader 使用来识别出特定文件,并转换文件内容,方便 webpack 使用,比如 css 文件要解析,需要将其转换成 js 代码放到 js 中,才能被后续处理(当然可以省略),然后加入最后输出的 js 当中
plugin 是帮助 webpack 做一些额外的工作,补充一些 webpack 本身没有实现的功能,有种打补丁的意思,更专注于打包、编译、输出 js 文件等操作以及在某些阶段要额外做的一些操作,比如 html 插件将其链接地址插入 html
补充 5. 关于 mainFields 的解释
有一些第三方模块会针对不同的环境提供几份代码,例如分别提供了 ES5 和 ES6 两份代码,在 package.json
中代码如下:
{
"jsnext:main": "es/index.js", // 采用 es6 的入口文件
"main": "lib/index.js", // 采用 es5 语法的代码入口文件
}
那么 webpack 会根据 mainFields
数组里的顺序, 逐步找到文件