文章目录
概念
webpack就是一个用于javascript应用程序的静态模块打包工具。
从v4版本开始,webpack就可以不用引入配置文件进行打包,但是,它仍然有着高度可配置性。
entry
入口起点指示webpack该使用的模块,作为构建内部依赖图的开始。进入起点之后,webpack会找出入口起点依赖的模块和库。默认是./src/index.js
可以指定一个或多个不同的起点。
单个入口
文件名:webpack.config.js
module.exports = {
entry: './path/to/my/entry/file.js',
};
entry也能接收文件路径数组,这将创建一个所谓的 “multi-main entry”。在你想要一次注入多个依赖文件,并且将它们的依赖关系绘制在一个 “chunk” 中时,这种方式就很有用。
module.exports = {
entry: ['./src/file_1.js', './src/file_2.js'],
output: {
filename: 'bundle.js',
},
};
对象语法
module.exports = {
entry: {
app: './src/app.js',
adminApp: './src/adminApp.js',
},
};
写法比较繁琐,但是可见进行扩展
可扩展?
“webpack 配置的可扩展” 是指,这些配置可以重复使用,并且可以与其他配置组合使用。这是一种流行的技术,用于将关注点从环境(environment)、构建目标(build target)、运行时(runtime)中分离。然后使用专门的工具(如 webpack-merge)将它们合并起来。
描述入口对象的属性
- dependOn: 当前入口所依赖的入口。它们必须在该入口被加载前被加载。
- filename: 指定要输出的文件名称。
- import: 启动时需加载的模块。
- library: 指定 library 选项,为当前 entry 构建一个 library。
- runtime: 运行时 chunk 的名字。如果设置了,就会创建一个新的运行时 chunk。在 webpack 5.43.0 之后可将其设为 false 以避免一个新的运行时 chunk
- publicPath: 当该入口的输出文件在浏览器中被引用时,为它们指定一个公共 URL 地址。请查看 output.publicPath。
module.exports = {
entry: {
a2: 'dependingfile.js',
b2: {
dependOn: 'a2',
import: './src/app.js',
},
},
}
runtime 和 dependOn 不应在同一个入口上同时使用,所以如下配置无效,并且会抛出错误
为什么不能在同一个入口使用
runtime和dependOn都会从条目文件中删除运行时。一个原因是runtime将位于一个单独的文件中,以便其他实体可以重用它,另一个原因是运行时已经由依赖项加载。两者都没有意义,因为依赖关系在某种程度上会加载这个运行时。在同一个文件或运行时文件中,依赖项将加载它。如果希望同时指定依赖项并将运行时包含在单独的文件中,那么使用此示例,您必须在myEntry中指定myEntry属性,在mySecondEntry中指定dependOn属性
确保 runtime 不能指向已存在的入口名称,例如下面配置会抛出一个错误
module.exports = {
entry: {
a1: './a',
b1: {
runtime: 'a1',
import: './b',
},
},
};
dependOn 不能是循环引用的,下面的例子也会出现错误
module.exports = {
entry: {
a3: {
import: './a',
dependOn: 'b3',
},
b3: {
import: './b',
dependOn: 'a3',
},
},
};
output
output 属性告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件。主要输出文件的默认值是 ./dist/main.js,其他生成文件默认放置在 ./dist 文件夹中。
用法
output属性最低要求是将它的值设置为一个对象。
module.exports = {
output: {
filename: 'bundle.js',
},
};
此配置将一个单独的 bundle.js 文件输出到 dist 目录中。
多个入口
如果配置中创建出多于一个 “chunk”,则应该使用 占位符(substitutions) 来确保每个文件具有唯一的名称。
module.exports = {
entry: {
app: './src/app.js',
search: './src/search.js',
},
output: {
filename: '[name].js',
path: __dirname + '/dist',
},
};
// 写入到硬盘:./dist/app.js, ./dist/search.js
loader
webpack 只能理解 JavaScript 和 JSON 文件,这是 webpack 开箱可用的自带能力。loader 让
webpack 能够去处理其他类型的文件,并将它们转换为有效 模块,以供应用程序使用,以及被添加到依赖图中。
loader有俩属性:
test 属性,识别出哪些文件会被转换。
use 属性,定义出在进行转换时,应该使用哪个 loader。
const path = require('path');
module.exports = {
output: {
filename: 'my-first-webpack.bundle.js',
},
module: {
rules: [{ test: /\.txt$/, use: 'raw-loader' }],
},
};
**注:**使用正则表达式匹配文件时,你不要为它添加引号。也就是说,/.txt / 与 ′ / t ˙ x t / 与 '/\.txt /与′/t˙xt/’ 或 “/.txt$/” 不一样,前者指示 webpack 匹配任何以 .txt 结尾的文件,后者指示 webpack 匹配具有绝对路径 ‘.txt’ 的单个文件
plugin
loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量。
想要使用一个插件,你只需要 require() 它,然后把它添加到 plugins
数组中。多数插件可以通过选项(option)自定义。你也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 new
操作符来创建一个插件实例。
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack'); // 用于访问内置插件
module.exports = {
module: {
rules: [{ test: /\.txt$/, use: 'raw-loader' }],
},
plugins: [new HtmlWebpackPlugin({ template: './src/index.html' })]
//html-webpack-plugin 为应用程序生成一个 HTML 文件,并自动将生成的所有 bundle 注入到此文件中。
};
关于插件
webpack 插件是一个具有 apply 方法的 JavaScript 对象。apply 方法会被 webpack compiler 调用,并且在 整个 编译生命周期都可以访问 compiler 对象。
ConsoleLogOnBuildWebpackPlugin.js
const pluginName = 'ConsoleLogOnBuildWebpackPlugin';
class ConsoleLogOnBuildWebpackPlugin {
apply(compiler) {
compiler.hooks.run.tap(pluginName, (compilation) => {
console.log('webpack 构建正在启动!');
});
}
}
module.exports = ConsoleLogOnBuildWebpackPlugin;
compiler hook 的 tap 方法的第一个参数,应该是驼峰式命名的插件名称。建议为此使用一个常量,以便它可以在所有 hook 中重复使用。
Configuration
webpack 的配置文件是 JavaScript 文件,文件内导出了一个 webpack 配置的对象。
webpack 会根据该配置定义的属性进行处理。
在配置中使用:
通过 require(…) 引入其他文件 通过 require(…)
使用 npm 下载的工具函数
使用 JavaScript 控制流表达式,例如 ?: 操作符
对 value 使用常量或变量赋值
编写并执行函数,生成部分配置
应该避免如下操作
- 当使用 webpack CLI 工具时,访问 CLI 参数(应编写自己的 CLI 工具替代,或者使用 --env)
- 导出不确定的结果(两次调用 webpack 应产生相同的输出文件)
- 编写超长的配置(应将配置文件拆分成多个)
基本配置
const path = require('path');
module.exports = {
mode: 'development',
entry: './foo.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'foo.bundle.js',
},
};
模块
概念
模块是程序分解为功能离散的chunk
与 Node.js 模块相比,webpack 模块能以各种方式表达它们的依赖关系。下面是一些示例:
- ES2015 import 语句
- CommonJS require() 语句
- AMD define 和 require 语句
- css/sass/less 文件中的 @import 语句。
- stylesheet url(…) 或者 HTML 文件中的图片链接。
支持的模块
Webpack 天生支持如下模块类型:
- ECMAScript 模块
- CommonJS 模块
- AMD 模块
- Assets
- WebAssembly 模块
解析模块
resolver 是一个帮助寻找模块绝对路径的库。 一个模块可以作为另一个模块的依赖模块,然后被后者引用,如下:
import foo from 'path/to/module';
// 或者
require('path/to/module');
所依赖的模块可以是来自应用程序的代码或第三方库。 resolver 帮助 webpack 从每个 require/import 语句中,找到需要引入到 bundle 中的模块代码。 当打包模块时,webpack 使用 enhanced-resolve 来解析文件路径。
解析规则
使用 enhanced-resolve,webpack 能解析三种文件路径:
绝对路径
import '/home/me/file';
import 'C:\\Users\\me\\file';
相对路径
import '../src/file1';
import './file2';
在这种情况下,使用 import 或 require 的资源文件所处的目录,被认为是上下文目录。在 import/require 中给定的相对路径,会拼接此上下文路径,来生成模块的绝对路径。
模块路径
import 'module';
import 'module/lib/file';
解析 loader
loader 的解析规则也遵循特定的规范。但是 resolveLoader 配置项可以为 loader 设置独立的解析规则。
target
用法
想设置 target 属性,只需在 webpack 配置中设置 target 字段:
webpack.config.js
module.exports = {
target: 'node',
};
在上述示例中,target 设置为 node,webpack 将在类 Node.js 环境编译代码。(使用 Node.js 的 require 加载 chunk,而不加载任何内置模块,如 fs 或 path)。
每个 target 都包含各种 deployment(部署)/environment(环境)特定的附加项,以满足其需求。具体请参阅 target 可用值。
多个target
虽然 webpack 不支持 向 target 属性传入多个字符串,但是可以通过设置两个独立配置,来构建对 library 进行同构:
const path = require('path');
const serverConfig = {
target: 'node',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'lib.node.js',
},
//…
};
const clientConfig = {
target: 'web', // <=== 默认为 'web',可省略
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'lib.js',
},
//…
};
module.exports = [serverConfig, clientConfig];
上述示例中,将会在 dist 文件夹下创建 lib.js 和 lib.node.js 文件。
总结
webpack的打包结果里,实现了一套基于 webpack_require 和 webpack exports对象的一套模块化规范,通过把我们源码中的一个一个的文件, 做为一个一个的 key + function的形式存储进webpack_modules里, 同时会把我们在源码中写的所有模块化规范, 都改成webpak_require,以及改成他自己的exports ,加载的时候 就是执行对应的webpack_modules里的对应key的函数 ,这个函数执行完成以后就会把对应的exports对象里写满值 ,默认导出就会有一个default属性在expoprts对象上 具名导出就是具体的kev在exports对象上。