一、框架搭建
webpack-cli
此工具用于在命令行中运行 webpack
npm install webpack webpack-cli --save-dev
创建webpack.config.js
文件,这个是webpack的默认配置文件,会自动读取这个文件,当然也可以指定某个文件来读取,只需要在命令行中指定文件npx webpack --config xxx.js
//webpack.config.js
//最最基础的配置,导出一个空对象
module.exports = {
};
//或者
module.exports = (...args) =>{
//导出一个函数来返回配置对象,推荐使用这个,因为函数可以接受一下传进来的参数,也能做更多的操作
return {
}
}
二、entry入口
1. 单个入口
module.exports = {
entry: './path/to/my/entry/file.js', //简写
};
上面的写法是以下写法的简写
module.exports = {
entry: {
main: './path/to/my/entry/file.js', //完整写法
},
};
我们也可以定义多个主入口
module.exports = {
entry: ['./src/file_1.js', './src/file_2.js'],
output: {
filename: 'bundle.js',
},
};
2.对象语法入口
module.exports = {
entry: {
app: './src/app.js', // app 和 adminApp就是chunk的名字,也可以通过runtime来自定义
adminApp: './src/adminApp.js',
},
};
用于描述入口的对象。你可以使用如下属性
ependOn
: 当前入口所依赖的入口。它们必须在该入口被加载前被加载。filename
: 指定要输出的文件名称。import
: 启动时需加载的模块。library
: 指定 library 选项,为当前 entry 构建一个 library。runtime
: 运行时 chunk 的名字。如果设置了,就会创建一个新的运行时 chunk。在 webpack 5.43.0 之后可将其设为 false 以避免一个新的运行时 chunk。publicPath
: 当该入口的输出文件在浏览器中被引用时,为它们指定一个公共 URL 地址
三、出口(output)
即使可以存在多个entry
起点,但只能指定一个output
配置
//单个入口时,可以使用下面的方法
module.exports = {
output: {
filename: 'bundle.js',
},
};
如果配置中创建出多于一个 “chunk”(例如,使用多个入口起点或使用像CommonsChunkPlugin
这样的插件),则应该使用 占位符(substitutions) 来确保每个文件具有唯一的名称
module.exports = {
entry: {
app: './src/app.js',
search: './src/search.js',
},
output: {
filename: '[name].js',
path: __dirname + '/dist',
},
};
1. assetModuleFilename
给所有module.rules
中type等于assets的资源统一设置一个路径
module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.[fullhash:6].js",
path: path.resolve(__dirname, "dist"),
assetModuleFilename: "images/[name].[hash:8][ext]",
clean: true,
},
module: {
rules: [
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: "asset/resource",
}
],
},
};
2. asyncChunks
创建按需加载的异步 chunk
module.exports = {
//...
output: {
//...
asyncChunks: true,
},
};
3.chunkFilename
- 这个选项用来定义动态导入或异步加载的额外代码块(chunk)的文件名称。
- 当你的应用使用动态
import()
语法或者Code Splitting
技术时,Webpack 会生成额外的 chunks,并且这些 chunks 的文件名将由chunkFilename
定义。 - 这些额外的chunks可以是按需加载的内容或者是被分割出去的共享库。
module.exports = {
entry: {
main:"./src/index.js",
main2:"./src/index2.js"
},
output: {
filename: "[name].[fullhash:6].js", //这个选项控制上面entry输出的文件名
chunkFilename: '[name].[fullhash:6].js', //这里控制不了上面entry输出的的文件名,
},
};
module.exports = {
//...
output: {
chunkFilename: (pathData) => {
return pathData.chunk.name === 'main' ? '[name].js' : '[name]/[name].js';
},
},
};
4. chunkFormat
chunk 的格式(formats 默认包含 ‘array-push’ (web/WebWorker)、‘commonjs’ (node.js)、‘module’ (ESM),还有其他情况可由插件添加)
定义在webpack运行时产生的额外的chunk时候的格式
四、loader
在应用程序中,有两种使用 loader 的方式
配置方式
(推荐):在webpack.config.js
文件中指定 loader内联方式
:在每个 import 语句中显式指定 loader
1. 配置方式:
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
modules: true,
},
},
{ loader: 'sass-loader' },
],
},
],
},
};
2. 内联方式
多个loader之间使用!分割
import Styles from 'style-loader!css-loader?modules!./styles.css';
通过为内联 import 语句添加前缀,可以覆盖配置
中的所有普通loader,前置loader,后置loader
使用 ! 前缀,将禁用所有已配置的 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';
3. loader 特性
- loader 支持链式调用。链中的每个 loader 会将转换应用在已处理过的资源上。一组链式的 loader 将按照相反的顺序执行。链中的第一个 loader 将其结果(也就是应用过转换后的资源)传递给下一个 loader,依此类推。最后,链中的最后一个 loader,返回 webpack 所期望的 JavaScript。
- loader 可以是同步的,也可以是异步的。
- loader 运行在 Node.js 中,并且能够执行任何操作
- loader 可以通过
options
对象配置 - 除了常见的通过
package.json
的 main 来将一个 npm 模块导出为 loader,还可以在module.rules
中使用 loader 字段直接引用一个模块 - 插件(plugin)可以为 loader 带来更多特性
- loader 能够产生额外的任意文件
4.loader的执行顺序
- Pitching 阶段: loader 上的
pitch
方法,按照后置(post)
、行内(inline)
、普通(normal)
、前置(pre)
的顺序调用 - Normal 阶段:
loader
上的 常规方法,按照前置(pre)
、普通(normal)
、行内(inline)
、后置(post)
的顺序调用。模块源码的转换, 发生在这个阶段
五、plugins插件
webpack 插件是一个具有apply
方法的 JavaScript 对象。apply 方法会被 webpack compiler 调用,并且在 整个 编译生命周期都可以访问 compiler 对象
const pluginName = 'ConsoleLogOnBuildWebpackPlugin';
class ConsoleLogOnBuildWebpackPlugin {
apply(compiler) {
compiler.hooks.run.tap(pluginName, (compilation) => {
console.log('webpack 构建正在启动!');
});
}
}
module.exports = ConsoleLogOnBuildWebpackPlugin;
六、mode
提供 mode 配置选项,告知 webpack 使用相应模式的内置优化
1. 用法
只需在配置对象中提供 mode 选项
module.exports = {
mode: 'development',
};
或者从CLI
参数中传递
webpack --mode=development
选项 | 描述 |
---|---|
development | 会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 development. 为模块和 chunk 启用有效的名 |
production | 会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 production。为模块和 chunk 启用确定性的混淆名称,FlagDependencyUsagePlugin,FlagIncludedChunksPlugin,ModuleConcatenationPlugin,NoEmitOnErrorsPlugin 和 TerserPlugin |
none | 不使用任何默认优化选项 |
如果没有设置,webpack 会给 mode 的默认值设置为production
。
如果要根据 webpack.config.js 中的 mode 变量更改打包行为,则必须将配置导出为函数,而不是导出对象:
var config = {
entry: './app.js',
//...
};
module.exports = (env, argv) => {
if (argv.mode === 'development') {
config.devtool = 'source-map';
}
if (argv.mode === 'production') {
//...
}
return config;
};
七、module
1. generator
可以使用module.generator
在一个地方配置所有生成器的选项
module.exports = {
module: {
generator: {
asset: {
// asseet 模块的 generator 选项
// 自定义 asset 模块的 publicPath,自 webpack 5.28.0 起可用
publicPath: 'assets/',
// 将静态资源输出到相对于 'output.path' 的指定文件夹中,webpack 5.67.0 后可用
outputPath: 'cdn-assets/',
},
'asset/inline': {
// asset/内联模块的 generator 选项
},
'asset/resource': {
// asset/资源模块的 generator 选项
// 自定义 asset/resource 模块的 publicPath,自 webpack 5.28.0 起可用
publicPath: 'assets/',
// 将静态资源输出到相对于 'output.path' 的指定文件夹中,webpack 5.67.0 后可用
outputPath: 'cdn-assets/',
},
javascript: {
// 该模块类型尚不支持 generator 选项
},
'javascript/auto': {
// 同上
},
'javascript/dynamic': {
// 同上
},
'javascript/esm': {
// 同上
},
// 其他...
},
},
};
2. noParse
防止 webpack 解析那些任何与给定正则表达式相匹配的文件。忽略的文件中 不应该含有import
,require
,define
的调用,或任何其他导入机制。忽略大型的 library 可以提高构建性能
module.exports = {
//...
module: {
noParse: /jquery|lodash/,
},
};
module.exports = {
//...
module: {
noParse: (content) => /jquery|lodash/.test(content),
},
};
3. enforce
可能的值有:"pre"
| "post"
指定 loader 种类。没有值表示是普通 loader。
pre
前置,post
后缀
module: {
rules: [
{
enforce: "pre",
test: /\.css$/i,
use: ["style-loader", "css-loader"],
}
],
},
4. exclude
排除所有符合条件的模块
module: {
rules: [
{
enforce: "pre",
test: /\.css$/i,
exclude: /node_modules/, //排除node_modules里面的css文件
use: ["style-loader", "css-loader"],
}
],
},
5. include
引入符合以下任何条件的模块
module: {
rules: [
{
enforce: "pre",
test: /\.css$/i,
include: /node_modules/, //排除node_modules里面的css文件
use: ["style-loader", "css-loader"],
}
],
},
6. oneOf
当有规则匹配了,就不继续进行匹配
module: {
rules: [
{
oneOf: [
{
enforce: "pre",
test: /\.css$/i,
exclude: /node_modules/,
use: ["style-loader", "css-loader"],
},
{
test: /\.s[ac]ss$/i,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: "asset/resource",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024,
},
},
},
],
},
],
},
7. parser
module: {
rules: [
{
oneOf: [
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: "asset",
parser: {
dataUrlCondition: { //文件大小小于10kb会被转换为base64,前提是上面的type不能是asset/resource
maxSize: 10 * 1024,
},
generator:{
//给匹配到的资源在代码中添加上这个公共路径 background-image: url("../assets/imgs/progress.png")变成了
//http://127.0.0.1:5500/dist/cdn-assets/tabbar_active.cae5338e.png;
publicPath:"cdn-assets/",
outputPath:"cdn", //在filename上拼接这个路径,5.67.0+版本可用
filename: 'images/[name][ext]' //自定义输出路径和文件名
}
},
},
],
},
],
},
八、resolve
resolve:{
alias:{
"@": path.resolve(__dirname, "src") //别名
},
//用于控制是否允许省略文件扩展名。当设置为 true 时,Webpack会强制要求在导入模块时必须显式指定文件扩展名;
//当设置为 false 时,则允许省略文件扩展名
enforceExtension:false,
extensions: ['.js', ".mjs",'.json', '.ts'], //省略扩展名时,用于匹配的后缀
//上面那种写法会覆盖默认扩展名,意味着你必须把所有用到的扩展名补全,
//如果只想添加某个扩展名,并且也使用默认扩展名,就使用下面的方式
//extensions: ['.ts', '...']
},
九、optimization
module.exports = {
//...
optimization: {
splitChunks: { //代码分割,以下都是默认值
chunks: 'async',
minSize: 20000,
minRemainingSize: 0,
minChunks: 1,
maxAsyncRequests: 30,
maxInitialRequests: 30,
enforceSizeThreshold: 50000,
cacheGroups: {
defaultVendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
reuseExistingChunk: true,
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
},
};