const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
/* --------------------------------------- mode ----------------------------------------- */
// 告知 webpack 使用相应模式的内置优化
mode: "production", // "production" | "development" | "none"
/* --------------------------------------- entry ----------------------------------------- */
// 起点或是应用程序的起点入口。从这个起点开始,应用程序启动执行。如果传递一个数组,那么数组的每一项都会顺序执行。
entry: "./app/entry", // string | object | array
entry: ["./app/entry1", "./app/entry2"], // -->会把这两个入口文件打包到一个默认main.js里面
entry: { a: "./app/entry-a", b: ["./app/entry-b1", "./app/entry-b2"] }, // -->打包输出a.js和b.js
// 把第三方库(如lodash)提取出来打包,同时又不让依赖这个库的文件重复打包lodash
entry: {
main: {
import: ["./app/entry1", "./app/entry2"],
filename: 'channel1/[name].js', // 会把main.js打包到channel1文件夹下
dependOn: 'lodash' // 这里的lodash与下面的key保持一致(key可以随便命名)
},
main2: {
import: "./app/entry3",
filename: 'channel2/[name].js', // 会把main2.js打包到channel2文件夹下
dependOn: 'lodash' // 这里的lodash与下面的key保持一致(key可以随便命名)
},
lodash: 'lodash'
}, // -->打包会输出main.js和lodash.js
// 这里应用程序开始执行
// webpack 开始打包
/* --------------------------------------- output ----------------------------------------- */
// 指示 webpack 如何去输出、以及在哪里输出你的打包内容
output: {
// webpack 如何输出结果的相关选项
// 所有输出文件的目标路径
// 必须是绝对路径(使用 Node.js 的 path 模块)
path: path.resolve(__dirname, "dist"), // string
// 每个输出 bundle 的名称
filename: "bundle.js", // string 用于单个入口起点
filename: "[name].js", // 使用入口名称,用于多个入口点(entry point)
filename: "[id].bundle.js", // 使用内部 chunk id
filename: "[name].[hash].bundle.js", // 使用每次构建过程中,唯一的 hash 生成
filename: "[chunkhash].bundle.js", // 使用基于每个 chunk 内容的 hash, 用于长效缓存
filename: "js/[name].js", // 将所有js文件放到一个js文件夹当中
// 「入口分块(entry chunk)」的文件名模板(出口分块?)
// 资源的公共路径,默认为"",一般以/结尾
publicPath: "/assets/", // string
publicPath: "",
publicPath: "https://cdn.example.com/",
// 输出解析文件的目录,url 相对于 HTML 页面
// 导出库(exported library)的名称
library: "MyLibrary", // string,
// 导出库(exported library)的类型
libraryTarget: "umd", // 通用模块定义
libraryTarget: "umd2", // 通用模块定义
libraryTarget: "commonjs2", // exported with module.exports
libraryTarget: "commonjs-module", // 使用 module.exports 导出
libraryTarget: "commonjs", // 作为 exports 的属性导出
libraryTarget: "amd", // 使用 AMD 定义方法来定义
libraryTarget: "this", // 在 this 上设置属性
libraryTarget: "var", // 变量定义于根作用域下
libraryTarget: "assign", // 盲分配(blind assignment)
libraryTarget: "window", // 在 window 对象上设置属性
libraryTarget: "global", // property set to global object
libraryTarget: "jsonp", // jsonp wrapper
},
/* --------------------------------------- module ----------------------------------------- */
// 这些选项决定了如何处理项目中的不同类型的模块
module: {
// 关于模块配置
rules: [
// 模块规则(配置 loader、解析器等选项)
{
test: /\.jsx?$/,
include: [
path.resolve(__dirname, "app")
],
exclude: [
path.resolve(__dirname, "app/demo-files")
],
// 这里是匹配条件,每个选项都接收一个正则表达式或字符串
// test 和 include 具有相同的作用,都是必须匹配选项
// exclude 是必不匹配选项(优先于 test 和 include)
// 最佳实践:
// - 只在 test 和 文件名匹配 中使用正则表达式
// - 在 include 和 exclude 中使用绝对路径数组
// - 尽量避免 exclude,更倾向于使用 include
issuer: { test, include, exclude },
// issuer 条件(导入源)
enforce: "pre",
enforce: "post",
// 标识应用这些规则,即使规则覆盖(高级选项)
loader: "babel-loader",
// 应该应用的 loader,它相对上下文解析
// 为了更清晰,`-loader` 后缀在 webpack 2 中不再是可选的
// 查看 webpack 1 升级指南。
options: {
presets: ["es2015"]
},
// loader 的可选项
},
{
test: /\.html$/,
test: "\.html$"
use: [
// 应用多个 loader 和选项
"htmllint-loader",
{
loader: "html-loader",
options: {
/* ... */
}
}
]
},
{ oneOf: [ /* rules */ ] }, // 只使用这些嵌套规则之一
{ rules: [ /* rules */ ] }, // 使用所有这些嵌套规则(合并可用条件)
{ resource: { and: [ /* 条件 */ ] } }, // 仅当所有条件都匹配时才匹配
{ resource: { or: [ /* 条件 */ ] } },
{ resource: [ /* 条件 */ ] }, // 任意条件匹配时匹配(默认为数组)
{ resource: { not: /* 条件 */ } } // 条件不匹配时匹配
],
},
/* --------------------------------------- resolve ----------------------------------------- */
// 这些选项能设置模块如何被解析
resolve: {
// 解析模块请求的选项
// (不适用于对 loader 解析)
// 用于查找模块的目录
modules: [
"node_modules",
path.resolve(__dirname, "app")
],
// 使用的文件扩展名
extensions: [".js", ".json", ".jsx", ".css"], // 当我们引入文件时没有写文件扩展名,遇到同名文件时会按数组先后顺序进行匹配文件
// 模块别名列表
alias: {
"@": path.resolve(__dirname, "./src"), // 常用
"module": "new-module",
// 起别名:"module" -> "new-module" 和 "module/path/file" -> "new-module/path/file"
"only-module$": "new-module",
// 起别名 "only-module" -> "new-module",但不匹配 "only-module/path/file" -> "new-module/path/file"
"module": path.resolve(__dirname, "app/third/module.js"),
// 起别名 "module" -> "./app/third/module.js" 和 "module/file" 会导致错误
// 模块别名相对于当前上下文导入
},
/* 可供选择的别名语法 */
alias: [
{
name: "module",
// 旧的请求
alias: "new-module",
// 新的请求
onlyModule: true
// 如果为 true,只有 "module" 是别名
// 如果为 false,"module/inner/path" 也是别名
}
],
/* ---------高级解析选项-------- */
symlinks: true, // 遵循符号链接(symlinks)到新位置
descriptionFiles: ["package.json"], // 从 package 描述中读取的文件
mainFields: ["main"], // 从描述文件中读取的属性 // 当请求文件夹时
aliasFields: ["browser"], // 从描述文件中读取的属性 // 以对此 package 的请求起别名
enforceExtension: false, // 如果为 true,请求必不包括扩展名 // 如果为 false,请求可以包括扩展名
moduleExtensions: ["-module"],
enforceModuleExtension: false, // 类似 extensions/enforceExtension,但是用模块名替换文件
unsafeCache: true,
unsafeCache: {}, // 为解析的请求启用缓存 // 这是不安全,因为文件夹结构可能会改动 // 但是性能改善是很大的
cachePredicate: (path, request) => true, // predicate function which selects requests for caching
plugins: [ // ... ] // 应用于解析器的附加插件
},
/* --------------------------------------- optimization ----------------------------------------- */
// 优化
optimization: {
chunkIds: false,
usedExports: true, // 进行tree-shaking摇树,基于ESM,将没有使用的代码过滤掉
splitChunks: {
chunks: 'async', // 有效值为 all,async 和 initial。initial同步,async异步,all同步或者异步
minSize: 20000,
minRemainingSize: 0,
minChunks: 1,
maxAsyncRequests: 30, // 按需加载时的最大并行请求数
maxInitialRequests: 30, // 入口点的最大并行请求数
cacheGroups: { // 缓存组。满足这些条件就会打包输出一个chunk
element: {
name: 'element',
test: /[\\/]node_modules[\\/](element-ui)[\\/]/, // 将element再从node_modules拆分出来
priority: 20, // 权重
reuseExistingChunk: true,
},
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
reuseExistingChunk: true,
},
default: {
minChunks: 2, // 所有引用超过两次的模块分配到 default的bundle中
priority: -20,
reuseExistingChunk: true,
},
},
},
},
/* --------------------------------------- performance ----------------------------------------- */
// 性能
performance: {
hints: "warning", // 枚举
hints: "error", // 性能提示中抛出错误
hints: false, // 关闭性能提示
maxAssetSize: 200000, // 整数类型(以字节为单位)
maxEntrypointSize: 400000, // 整数类型(以字节为单位)
assetFilter: function(assetFilename) {
// 提供资源文件名的断言函数
return assetFilename.endsWith('.css') || assetFilename.endsWith('.js');
}
},
/* ----------------------------------------- devtool ------------------------------------------- */
// 此配置可以生成source map文件,和在浏览器中定位源代码位置。开发环境建议使用cheap-module-source-map,生产环境建议关闭此配置
devtool: "source-map", // enum // 通过在浏览器调试工具(browser devtools)中添加元信息(meta info)增强调试
devtool: "inline-source-map", // 嵌入到源文件中
devtool: "eval-source-map", // 将 SourceMap 嵌入到每个模块中
devtool: "hidden-source-map", // SourceMap 不在源文件中引用
devtool: "cheap-source-map", // 没有模块映射(module mappings)的 SourceMap 低级变体(cheap-variant)
devtool: "cheap-module-source-map", // 有模块映射(module mappings)的 SourceMap 低级变体
devtool: "eval", // 没有模块映射,而是命名模块。以牺牲细节达到最快。
// 通过在浏览器调试工具(browser devtools)中添加元信息(meta info)增强调试
// 牺牲了构建速度的 `source-map' 是最详细的。
/* ----------------------------------------- context ------------------------------------------- */
context: __dirname, // string(绝对路径!)
// webpack 的主目录
// entry 和 module.rules.loader 选项
// 相对于此目录解析
/* ----------------------------------------- target ------------------------------------------- */
target: "web", // 枚举
target: "webworker", // WebWorker
target: "node", // node.js 通过 require
target: "async-node", // Node.js 通过 fs and vm
target: "node-webkit", // nw.js
target: "electron-main", // electron,主进程(main process)
target: "electron-renderer", // electron,渲染进程(renderer process)
target: (compiler) => { /* ... */ }, // 自定义
// 包(bundle)应该运行的环境
// 更改 块加载行为(chunk loading behavior) 和 可用模块(available module)
/* ---------------------------------------- externals ------------------------------------------ */
// 外部扩展
// 不要遵循/打包这些模块,而是在运行时从环境中请求他们。
// 为了减小bundle体积,从而把一些不变的第三方库用cdn的形式引进来(index.html中script标签引入)
// 能实现类似已经install到项目中的方式来引用这些库
externals: { // 常用方式
jquery: 'jQuery' // key的值必须与我们引入库的名称一致(与import $ from 'jquery'中的jquery一致)
// value的值来源于引入cdn链接后暴露在window对象中的变量名称:jQuery(或$)
},
// 不需要在index.html中手动引入cdn链接的方式
externalsType: 'script',
externals: {
jquery: [
'https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js', // 第一个参数是cdn链接
'jQuery' // 第二个参数是引入cdn链接后暴露在window对象中的变量名称:jQuery(或$)
]
},
/* ----------------------------------------- stats ------------------------------------------- */
// 配置构建命令行时的显示日志
stats: "errors-only",
stats: { //object
assets: true,
colors: true,
errors: true,
errorDetails: true,
hash: true,
// ...
},
// 精确控制要显示的 bundle 信息
/* ----------------------------------------- devServer ------------------------------------------- */
// webpack-dev-server 能够用于快速开发应用程序
devServer: {
proxy: { // 开启代理
'/api': {
target: 'localhost:3000',
ws: false,
changeOrigin: true,
pathRewrite: {
'^/api': '' //重写接口访问
}
}
},
port: 3000, // 端口号
host: '0.0.0.0', // 开发服务器主机,通过此配置,同一局域网下其他人也可以访问你本地开启的服务,或者手机调试pc端(通过ip+端口访问)
contentBase: path.join(__dirname, 'public'), // boolean | string | array, static file location
compress: true, // 一切服务都启用gzip压缩
headers: { // 添加响应头
'x-access-token': 'abc123'
},
historyApiFallback: true, // 在使用history路由时,任意的 404 响应都可以被替代为 index.html
hot: true, // 模块热替换,页面修改时,实现局部更新
https: false, // true for self-signed, object for cert authority
// ...
},
/* ----------------------------------------- plugins ------------------------------------------- */
// 附加插件列表
// plugins 选项用于以各种方式自定义 webpack 构建过程
// 下面是多页面配置,传入了两个HtmlWebpackPlugin实例,并且配置不同,会打包输出index.html和index2.html。
// 如果只配置一个HtmlWebpackPlugin实例则会打包成一个html(默认叫index.html)
plugins: [
new HtmlWebpackPlugin({ // 传入插件的new实例,还可以进行更多配置
template: './index.html',
inject: 'body',
filename: '/channel1/index.html', // 打包成index.html并放到channel1文件夹里面(这就与上面对应的入口文件打包到一起了)
chunks: ['main', 'lodash'], // chunks决定打包后的index.html引入哪些chunk(entry对象的每一项打包后就是一个对应的chunk)
}),
new HtmlWebpackPlugin({ // 传入插件的new实例,还可以进行更多配置
template: './index2.html',
inject: 'body',
filename: '/channel2/index2.html', // 打包成index2.html并放到channel2文件夹里面
chunks: ['main2', 'lodash'], // index2.html会引入main2.js和lodash.js
}),
],
}
更详细配置请参阅官方文档。
网友评论