📃 前言:demo-webpack5代码地址:
🔗 gitee:code for demo-webpack@5
一、npx作用
在工程中,用到一些命令工具,若全局安装,无法有效控制命令工具的版本,因此常针对不同工程,采用局部安装命令工具的方式,此时直接使用命令会报错,因为命令工具安装在工程目录 node_modules/.bin/xx 中,npx 命令xxx 的作用就是直接在该目录下找命令工具,而非全局找
- 在工程 node_modules/.bin/xx 中使用命令行工具
在 package.json 中配置脚本可以省略 npx
{ "scripts":"webpack" // 等价于 npx webpack }
- 临时安装命令工具(非工程目录)并执行
当执行某个命令时,如果无法从本地工程中找到对应命令,则会把命令对应的包下载到一个临时目录,下载完成后执行,临时目录中的命令会在适当的时候删除
npx prettyjson 1.json上述命令会将包 prettyjson 安装到临时目录,并执行命令,如果包名和命令名称不一致,可以手动指定包名,如包名 @vue/cli,命令名称 vue ,可使用命令
npx -p @vue/cli vue create my-app
二、Eslint 代码规范
1、安装
npm i -D eslint
2、校验(使用 eslint 命名行工具)
# 单个文件校验
npx eslint 文件名
# 校验全部文件
npx eslint src/**
3、配置文件
- .eslintrc JSON文件
- .eslintrc.cjs 或 .eslintrc.js JS文件
- .eslintrc.yml yaml 文件
// .eslintrc.js
module.exports = {
rules:{
// 规则级别 'off'或0 - 关闭规则;'warn'或1 - 验证不通过警告;'error'或 2 - 验证不通过退出程序
// 规则名:规则级别
eqeqeq:2
}
}
三、typescript 配置文件
- 补充
1、约束类的类型可以使用 new () => object
// 约束一个类 const target:new (...args:any[]) => object
-
配置文件说明
-- tsconfig.json
{
// "extends":[], // 指定继承配置
// "files": [], // 指定编译的特定文件
// 编译选项
"compilerOptions": {
// 1、【语言与环境 Language and Environment】
"target": "ES2016", // 编译目标代码的版本标准,默认值 es3
"lib": ["esnext", "dom"], // ts需要引入的库,即类型申明文件,在TypeScript源码的lib目录下查看具体内容
"jsx": "preserve", // 指定自定义的 JSX 工厂函数库,用于处理 JSX 代码的转换:react(react@18以下);react-jsx(react@18)
/**
* jsx 不同取值用法
* preserve:适用于需要将JSX处理委托给其他工具(Babel)的场景
* react:转换成.js文件,将 JSX 语法转换成React.createElement,源代码必须导入react,适用于 react16及更早版本
* react-jsx:适用于 react17及以上版本,JSX 语法不会转换成React.createElement,源代码不用导入react,而是自动从react包中导入特殊函数并调用
*/
"jsxImportSource": "vue", // 保留 JSX 代码,不进行转换。这通常用于与 Babel 等工具链配合使用,一般vue中使用
// "useDefineForClassFields": false // 控制类字段的编译方式,指定是否使用 define 语法,确保类字段的行为符合最新的 ECMAScript 标准,默认值:target>=2022 true,其他默认false
// "noLib":true, // 禁止包含任何库文件,包括默认的 lib.d.ts,默认值为 false
// "experimentalDecorators":true, // 启用对装饰器的实验性支持,默认 false
// "emitDecoratorMetadata":true, // 启用对类型元数据reflect-metadata的支持,默认 false
// 2、【类型检查 Type Checking】
"strict": true, // 启用所有严格类型检查
// -- start
// "alwaysStrict" :false,// 启用严格模式,为每个文件添加 "use strict"
// "noImplicitAny": false, // 禁止隐式的 any 类型
"noImplicitThis": false, // 确保 this 的使用有明确的类型声明
"strictBindCallApply": true, // 确保 bind、call 和 apply 的参数符合函数签名的要求
"strictNullChecks": true, // 确保处理 null 和 undefined,减少潜在的运行时错误
"strictPropertyInitialization": true, // 防止类属性在实例化时未被正确初始化
// "strictFunctionTypes": false,// 确保函数参数和返回值类型严格匹配
// "useUnknownInCatchVariables":false, // 默认 catch 子句变量为unknown,而不是any。
// --end 上面的8个配置,会跟随 strict:true 自动开启
"noUnusedLocals": true, // 禁止存在未使用的局部变量
"noUnusedParameters": true, // 禁止存在未使用的函数参数
// "noFallthroughCasesInSwitch": false, // 防止在 switch 语句中遗漏 break 语句,从而减少潜在的逻辑错误
// 3、【模块相关 Module】
"module": "ESNext", // 编译结果的模块化标准,如果target设置为ES3或者ES5,默认为CommonJS
"moduleResolution": "Bundler", // 模块解析的模式,Node - node查找策略;bundler - ts@4.7+推荐使用,与打包工具(webpack、esbuild、rollup)配合
// 路径映射,一般用来和打包工具一起定义路径别名
// paths定义的路径映射并不会影响到编译之后的js文件,这个定义仅仅会阻止TypeScript报错,因为tsc编译器并不会处理模块说明符(也就是from "xxxx")里面的内容
"paths": {
"@/*": ["./src/*"]
},
"resolveJsonModule": true, // 允许导入 JSON 文件作为模块
// 需要设置noEmit或者emitDeclarationOnly为true
"allowImportingTsExtensions": true, // 允许在 import 语句中使用 .ts 和 .tsx 扩展名
// "baseUrl": "./", // 设置解析非相对路径模块的基础地址,默认是当前目录,这里./的路径是相对于tsconfig文件的地址的
// 4、【互操作约束 Interop Constraints】
"esModuleInterop": true, // 允许与CommonJS模块和Es module互操作,如果module是node16或nodenext,默认开启
"isolatedModules": true, // 确保 TypeScript 编译器和 Babel(或其他类似工具)之间的兼容性,特别是在使用单独编译模块时
// 当esModuleInterop:true时默认开启为true
"allowSyntheticDefaultImports": true, // 允许commonjs没有默认导出的代码使用ESM的默认导出行为
// "forceConsistentCasingInFileNames":true, // 引入模块文件时的文件名必须与文件系统中的文件名大小写一致
// 5、【生成文件,影响编译结果 Emit】
"noEmit": true, // 用于仅进行类型检查而不生成输出文件,比如在测试代码时
"removeComments": true, // 编译后的 .js 文件中删除注释
// "declaration":true, // 生成类型声明文件.d.ts
// "emitDeclarationOnly":false, 只生成类型声明文件.d.ts,不生成.js文件
// "declarationMap":true,// 为.d.ts文件创建源映射
// "outDir":null, // 指定输出目录,未指定默认为编译文件的同目录
// 6、【js 支持 Support js】
"allowJs": true, // 允许使用js文件
// "checkJs":true, // js 文件也进行类型检查
// 7、【其它 Other】
"skipLibCheck": true // 跳过库文件的类型检查
},
// 指定编译的文件或目录
"include": ["env.d.ts", "src/**/*", "src/**/*.vue", "types/auto-imports.d.ts"],
// 指定编译器需要排除的文件或文件夹,默认值 node_modules,bower_components,jspm_packages,outDir配置的对应目录
"exclude": ["src/**/__tests__/*"],
// 更精细的控制,指定项目间的依赖关系,明确主项目依赖于哪些子项目或模块,帮助 TypeScript 确定编译顺序,确保依赖项先编译
// 实现增量编译,提升效率,通常用于前后端部署在一起,且后端基于 node 开发时配置
// "references": [
// {
// "path": "./tsconfig.node.json" // node 环境
// },
// {
// "path": "./tsconfig.app.json" // 浏览器环境
// }
// ],
// ts-node 相关配置
"ts-node": {
"esm": true
}
}
四、Webpack 构建工具
📚【核心功能】
1、安装和使用
- 需要下载 webpack 和 命令行工具 webpack-cli
npm i -D webpack webpack-cli
webpack :核心包,包含前端工程构建过程所有 api
webpack-cli:命令行工具,可以通过命令调用核心包的 api,完成工程的构建
- 使用命令 webpack 默认从 "./src/index.js" 该目录为入口文件,分析工程依赖关系,最终打包到目录 "./dist/main.js"
可以使用 --mode 指定打包运行的环境,默认生产环境(production)
生产环境构建后的代码会压缩,开发环境不会
# 构建工程(默认生产环境),等价于 webpack --mode=production
webpack
# 指定开发环境构建
webpack --mode=development
2、配置文件
- webpack 默认读取 webpack.config.js 作为配置文件,也可以使用命令指定配置文件
# 指定配置文件
webpack --config 文件路径
配置文件内容使用 CommonJS 规范导出一个对象
问: webpack 支持多模块化规范,但配置文件导出的配置对象,为何必须使用 CommonJS 规范?
💡 因为工程中的整个模块文件在编译过程中只是读取,识别模块之间的依赖关系,最终生成打包文件,这些文件在编译过程中是不参与运行的,而配置文件 webpack.config.js 是要参与运行的,因为整个编译过程是在 node 环境中,而后缀名为 js 时,默认是按照 CommonJS 解析的,并且 webpack 内部导入 webpack.config.js 是用的CommonJS,因此只能使用 CommonJS 规范
node 环境中
1)默认情况下, .js 文件 — CommonJS 规范, .mjs 文件 — EsModule 规范
2)工程在 package.json 中设置了 type:"module" ,则 .js 文件 — Esmodule 规范, .cjs 文件 — CommonJs 规范
// 配置文件 webpack.config.js
const path = require('path');
module.exports = {
// 打包运行环境 development - 开发,production - 生产
mode:"development",
// 入口文件,通常是字符串(单入口),多入-单出时(字符串数组),多入-多出时(对象-{打包文件名:"路径"})
// 入口文件不配置,默认是 "./src/index.js"
entry:"./main.js",
// 出口文件
output:{
path:path.resolve(__dirname,'./dist'),// 打包的路径,默认是 ./dist
filename:"main.js", // 打包后的文件名称
}
}
3、devtool 配置
- source map 源码地图
在开发环境运用于调试用,运行打包后文件时,若报错,能定位打包前源码位置
- webpack 使用 devtool 配置来优化调试体验,有很多方式,使用的时候查看官网即可
4、编译过程
- 初始化
webpack 将 【cli参数】、【配置文件】、【默认配置】进行融合,形成最终配置文件,对配置的处理过程依托第三方库 yargs(分析命令行指令)
是编译过程的准备工作,即生成配置文件
- 编译
1)创建 chunk (块),通过入口文件找到所有依赖的统称,通常为一个(单入),也可以多个
每个 chunk 至少2个属性:
- name:默认为 main
- id:唯一编号,开发环境和name相同,生产环境是一个数字,从0开始
2)构建所有模块依赖,生成模块列表(模块id和转换后的代码)
3)产生 chunk assets,根据配置,生成最终生成文件的资源列表(文件名-文件内容)
👉 chunk hash 是根据所有chunk assets的内容生成的一个hash字符串(hash是一种算法,内容不变,得到的hash值不变)
4)将多个chunk 的 hash assets 合并到一起,产生一个总的 hash
- 输出
webpack 利用 node 的 fs 模块(文件处理模块),根据编译产生的总的 assets 生成不同的文件
- 总过程及术语
术语:
- module:模块,分割的代码单元,webpack 中的模块可以是任何内容的文件,不仅限于JS
- chunk:webpack 内部构建模块的块,一个 chunk 中包含多个模块,这些模块是从入口模块通过依赖分析得来的
- bundle:chunk 构建好模块后会生成chunk的资源清单,清单中的每一项就是一个bundle,可以认为 bundle 就是最终生成的文件
- hash:最终的资源清单(多个 chunk 生成的资源清单汇总)所有内容联合生成的 hash 值
- chunkhash:chunk 生成的资源清单内容联合生成的 hash 值
- chunkname:chunk 的名称,如果没有配置则使用 main
- id:通常指 chunk 的唯一编号,如果在开发环境下构建,和 chunkname 相同;如果是生产环境下构建,则使用一个从0开始的数字进行编号
5、入口和出口
- node 中路径说明
📍 ./
1)在模块化代码中,比如 ruquire( "./xx" ),表示当前 js 文件所在目录
2)在路径处理中,”./” 表示 node 运行目录
📍 __dirname 所有情况下,都表示当前运行 js 文件所在目录,是个绝对路径
-
多入多出中,出口文件的配置规则
💡 说明:output 中指定 filename 时,想将打包的文件放入子文件夹中,可以配置成 filename : 'scripts/[name].[hash:5].js',这样就放入子文件夹 scripts 中了
1)name - chunkname
2)hash - 总的资源 hash,通常用于解决缓存问题,内容不变,hash 不变
3)chunkhash - 使用 chunkhash
const { resolve } = require('path'); module.exports = { // 入口 entry:{ // 属性为 chunkname,值为入口模块路径 main:'./src/index.js', a:'./src/a.js', b:['./src/b/index.js','./src/b/other.js'] // 针对b有多个入口文件 }, // 出口 output:{ // 必须为绝对路径 path:resolve(__dirname,'dist/app'), // 出口文件名称,这里的 name 是占位符,对应替换为入口定义的 chunkname // filename:'[name].bundle.js' // hash:指定位数 filename:'[name].[hash:5].js' } }
6、扩展(loader、plugin)
webpack 只是分析模块依赖关系,生成模块列表,并根据配置文件,生成资源文件列表,最后将多个资源文件列表合并生成打包文件,而更多的功能,需要扩展 webpack loaders 和 webpack plugins
-
loader
-
loader 本质是一个函数,它的作用是将某个源码字符串(webpack 读取的源码当作字符串解析)转换成另一个源码字符串返回
-
loader 函数将在模块解析的过程中被调用,以得到最终的源码
- loader 配置
-
模块规则配置 module 中,运用的匹配规则 rules,多个规则对象是从上往下匹配,匹配到后统一加入一个数组(记作tempRules)中,当运行时相当于 tempRules.pop()
🎉 下列匹配到后,执行顺序是 loader4 > loader3 > loader2 > loader1
// 匹配到的规则后将 loader 放入数组 ['loader1','loader2','loader3','loader4'] module.exports = { module:{ rules:[ { test:/index.js$/,use:[ 'loader1','loader2' ] }, { test:/.js$/,use:[ 'loader3','loader4' ] }, ] } }
🍍 简要配置(对应loader函数参数用默认值)
modele.exports = {
// 模块处理配置
module:{
// 模块匹配规则,可以有多个
rules:[
{
test:/.js$/, // 模块匹配的正则
// 匹配到的模块应用的规则模块(使用哪些加载器)
use: ["模块路径1", "模块路径2"] // loader模块的路径,该字符串会被放置到require中
}
]
}
}
🍍🍍 完整配置(向对应loader函数传递额外参数)
可以使用第三方库 loader-utils 获取 options 中传递的参数,或生成文件路径等新版 loader-utils 少了很多方法,如 getOptions ,因为 webpack@5 在 loader 函数中,可以通过 this.query 获取配置 options
# 开发环境下载库 npm i -D loader-utils
modele.exports = {
// 模块处理配置
module:{
// 模块匹配规则,可以有多个
rules:[
{
test:/.js$/, // 模块匹配的正则
// 匹配到的模块应用的规则模块(使用哪些加载器)
use: [
{
loader:'模块路径1',// loader模块的路径,该字符串会被放置到require中
options:{ ... } // 传递的额外参数
}
]
}
]
}
}
🔧 自定义 loader
定义(CommonJs 定义函数并返回字符串源码)
因为 webpack 最终源码编译结果( js 文件)是一个立即执行函数,并在内部通过 eval( 源码字符串 ) 来执行代码,因此自定义 loader 返回的字符串源码中编写需要执行的逻辑
如果给自定义 loader 函数绑定静态属性 raw,那获取的数据格式不会转为字符串,而是原始格式
// 定义loader方法 function loaderFn(){ // ... } // 绑定 raw 并导出方法 loaderFn.raw = true; module.exports = loaderFn
--- img-loader.js
const loaderUtils = require('loader-utils');
console.log(loaderUtils);
/**
* 图片loader
* @param {Buffer} buffer 图片二进制数据
*/
function imgLoader(buffer) {
// 文件大小 KB
const size = buffer.byteLength / 1024;
console.log(`文件大小:${Math.floor(size)}KB`);
console.log(this.query);
// 通过 loader 上下文中的query,可以获取 loader 配置中的 options
const { limit = 1024 , name = '[contenthash:5].[ext]' } = this.query;
let content = '';
const { fileName, ext } = getFilePath.call(this, buffer,name);
if (size < limit) {
content = getBase64(buffer, ext);
} else {
content = fileName;
// 打包文件到最终目录
this.emitFile(fileName, buffer);
}
return `module.exports=`${content}``;
}
// 让loader 获取到的数据格式为原始格式(这里是 buffer)
imgLoader.raw = true;
/**
* 获取文件名称
* @param {Buffer} buffer 图片二进制数据
* @param {string} name 图片打包后文件名称格式
*/
function getFilePath(buffer,name) {
const fileName = loaderUtils.interpolateName(this, name, {
content: buffer
});
return { fileName, ext: fileName.replace(/.*./g, '') };
}
/**
* 获取图片base64格式
* @param {Buffer} buffer 图片二进制数据
* @param {string} ext 图片后缀
*/
function getBase64(buffer, ext) {
const fileExt = ext === 'jpg' ? 'jpeg' : ext;
return `data:img/${fileExt};base64,${buffer.toString('base64')}`;
}
module.exports = imgLoader;
✨✨🧑🏻使用
-
plugin
-
plugin 的作用是在编译过程中,嵌入一些额外的功能
-
plugin 的本质是一个带有 apply 方法的对象,通常写成一个构造函数的模式
-
const plugin = {
apply:function(){
// ...
}
}
// 通常为构造函数
module.exports = class MyPlugin{
apply(compiler){
// ...
}
}
// 插件实例
const myPlugin = new MyPlugin()
👉 使用 - 配置 plugins
const MyPlugin = require('./src/plugins/myPlugin.js')
module.exports = {
plugins:[
new MyPlugin()
]
}
🔧 自定义插件
apply 方法会在初始化阶段,创建好 compiler 对象后,将 compiler 对象作为参数传入并调用(apply 方法) ,整个构建过程中只有一个 compiler 对象,后续完成打包工作的是 compiler 对象内部创建的 compilation
compiler 对象提供了大量的钩子函数(hooks,可以理解为事件),plugin 的开发者可以注册这些钩子函数,参与 webpack 编译和生成。
你可以在apply方法中使用下面的代码注册钩子函数:
class MyPlugin{ apply(compiler){ compiler.hooks.事件名称.事件类型(name, function(compilation){ // 事件处理函数 // 可以通过 compilation.assets 获取到打包后生成的文件信息,是个对象 // 形如: {'文件名称':{ source(){return '源码字符串或文件二进制'},size(){return '文件字节数'} }} }) } }【事件类型】
- tap 注册一个同步的钩子函数,函数运行完毕则表示事件处理结束
- tapAsync 注册一个基于回调的异步的钩子函数,函数通过调用一个回调表示事件处理结束
- tapPromise 注册一个基于Promise的异步的钩子函数,函数通过返回的 Promise进入已决状态表示事件处理结束
module.exports = class FileListPlugin {
constructor(fileName) {
this._fileName = fileName;
}
// 插件方法
apply(compiler) {
console.log('插件运行');
// 注册生成打包文件前的事件
compiler.hooks.emit.tap('fileListPlugin', compilation => {
const fileContent = [];
for (const fileName in compilation.assets) {
// js文件源码字符串或文件二进制数据
const source = compilation.assets[fileName].source();
// 文件字节数
const size = compilation.assets[fileName].size();
fileContent.push(`--【${fileName}】\n文件大小:${size / 1024}KB\n`);
}
console.log(`生成文件${this._fileName}`);
const _size = fileContent.join('\n\n');
compilation.assets[this._fileName] = {
source() {
return _size;
},
size() {
return _size.length;
}
};
});
}
};
7、区分环境
-
配置文件
通常是导出一个配置对象,也可以是个方法,方法的返回值是一个配置对象,这个函数会在开始构建的时候调用,传入参数 env,这样可以根据判断等实现不同环境不同的配置
module.exports = function( env ){
return {
// 配置内容
}
}
- 上述 env 的值可通过终端命令控制
# webpack@4.x 的写法
npx webpack --env abc # env: "abc"
npx webpack --env.abc # env: {abc:true}
npx webpack --env.abc=1 # env: {abc:1}
npx webpack --env.abc=1 --env.bcd=2 # env: {abc:1, bcd:2}
# webpack@5.x 的写法,没有符号 .
npx webpack --env abc # env:{abc:true}
npx webpack --env abc=1 # env: {abc:1}
- 项目中针对不同环境若用到不同的环境变量,如 TITLE(标题差异)、GET_WAY(请求的网关不同)等,可以用第三方库 dotenv 读取 .env 或 .env 开头的文件,并在 webpack.config.js 配置文件中注入,则可以通过 process.env.xx 访问
1、package.json 文件中,通过脚本设置环境变量区分环境
2、dotenv 默认读取 .env 文件,可指定其它 .env 开头的文件
3、在 webpack.config.js 中注入环境变量
"scripts": {
"start": "webpack-dev-server --mode=development --node-env development",
"build": "webpack --mode=development --node-env production",
"build:prod": "webpack --mode=production --node-env production"
},
# 项目标题
TITLE = 开发环境-myapp
# 其它
const { resolve } = require('path');
const dotenv = require('dotenv');
// 当前环境变量
const NODE_ENV = process.env.NODE_ENV;
// 读取环境变量并注入,默认会注入 .env 文件(全局环境变量),多文件的同名环境变量,后者不会覆盖前者,一旦确定不再更改
dotenv.config({ path: resolve(__dirname, `.env.${NODE_ENV}`) });
8、其他细枝末节的配置
- 1)context
指定入口文件的绝对路径,通常入口文件配置中路径 './' 指当前运行终端的路径(即当前执行路径),配置了 context 会直接影响【入口 entry】和 loader 中的相对路径
entry:'./main.js',
// 指定入口绝对路径
context: path.resolve(__dirname, "app")
- 2)output 选项中其他配置
library 会将打包结果中,自执行函数的执行结果暴露给设置的值,如下的 'abc',相当于:
// 打包编译后的文件
var abc = ( function( modules ){ return ... } )( )
libraryTarget 默认值为 'var' ,配合 library 使用,以控制如何暴露入口包的导出结果
- var (默认值),暴露给一个普通变量
- window,暴露给 window 对象的一个属性
- global,暴露给 global 对象的一个属性
- this ,暴露给 this 的一个属性
- commonjs,暴露给 exports 的一个属性
// 出口配置
output:{
path:path.resolve( __dirname,'./dist' ),// 出口路径
filename:'[name].[hash:5].js',// 打包后文件名
library:'abc'
}
- 3)target 设置打包结果运行的环境
target
- web (默认值),web 环境中运行
- node ,node 环境中运行
- 4)module 选项中的其它配置
noparse ,正则匹配的模块不参与解析,通常用于大型单模块库(不依赖其他模块),以提升构建性能
module:{
noparse:/jquery/
}
- 5)resolve 用于控制模块解析过程
- modules 指定模块查找目录,默认 [ 'node_modules' ] ,即在导入模块时,路径没有写 './' 或 '../' 的,如 require( 'jquery' )
- extensions 译为扩展名,即指定解析过程中,自动补全的后缀名,webpack 会根据配置中 extensions ,自动补全后缀名,例如:require('./a') ,首先看有没有该文件,没有,webpack 会自动补全后缀 .js、 .json 看是否存在
- alias 路径别名
resolve:{
modules:['node_modules'],// 指定模块查找目录
extensions:['.js','.json'],// 指定补全文件后缀
// 路径别名
alias:{
'@':path.resolve(__dirname,'src'),
'_':dirname
}
}
- 6)externals (外观)作用是排除最终的 bundle 中配置的源码,如下排除 jquery 和 lodash 的导入,自己开发中仍然可以写 'import $ from 'jquery' 并使用,不会报错,而 webpack 编译后的代码(立即执行函数)中没有 jquery 的逻辑代码,转而导出的只是设置的字符串,通常该配置适用于通过 CDN 的方式引入的包,以减小构建体积,而书写源码里正常写
externals:{
jquery:'$',
lodash:'_'
}
- 7)publicPath,通常配置在 outPut 中,就是在编译过程中指定了一个路径字符串,在资源加载的代码中,会拼接在开头
output:{
publicPath:'/',// 通常配置成根路径
}
🧩 【常用扩展】
1、打包前清除之前的文件
- clean-webpack-plugin
- 但 webpack@5 内置了该插件,仅需通过配置 output.clean 为 true 即可,若排除部分文件的清除行为,可通过 output.clean.keep 控制保留文件
const { CleanWebpackPlugin } = require( 'clean-webpack-plugin' )
module.exports = {
output:{
// clean:true // 清除之前的打包文件
},
plugins:[
new CleanWebpackPlugin( )
]
}
2、自动生成页面
- html-webpack-plugin
const HtmlWebpackPlugin = require( 'html-webpack-plugin' )
module.exports = {
// 多入口
entry:{
list:'./src/list/list.js',
home:'./src/home/home.js'
},
plugins:[
new HtmlWebpackPlugin( {
template:'./public/index.html',// 指定模板,
filename:'index.html',// 指定打包后的文件名称
chunks:['list'] // 指定引入的 chunk
} )
]
}
3、复制静态资源
- copy-webpack-plugin
const CopyWebpackPlugin = require( 'copy-webpack-plugin' )
module.exports = {
plugins:[
new CopyWebpackPlugin([
// 每个对象就是一个复制规则
{
from:'./public',// 从哪个资源复制
to:'./' // 复制到哪个目录,该路径相对于output配置的打包路径
}
])
]
}
4、开发环境服务器
- webpack-dev-server 是 webpack 官方的模块,使用 express 开启一个开发服务器,并将模块打包放入内存中,当页面请求资源时,再给与响应打包资源
module.exports = {
devServer: {
port: 8080, // 监听端口
open: true, // 开启后默认打开页面,
openPage:'index.html',// 默认打开页面,默认值为 'index.html'
// 代理服务器
// proxy: {
// 代理规则
// '/api': {
// target: 'https://github.com',
// changeOrigin: true // 更改请求头中的 host 和 origin
// }
// }
// 上述配置方式在 webpack@4.x 中没问题,在 webpack@5.x中报错,提示 proxy 应配置为数组
proxy:[
{
context:['/api'],
target: 'http://github.com'
}
]
}
}
5、webpack 内置插件
所有 webpack 内置插件,都作为其静态属性存在,创建一个插件使用:
const webpack = requier('webpack'); // 创建一个插件 new webpack.插件名( options )
- DefinePlugin 常量定义插件
new webpack.DefinePlugin({
// 值为字符串,在编译后常量会替换为字符串的值
PI:`Math.PI`,// const PI = Math.PI
VISION:`'1.0.0'`
DOMAIN:JSON.Stringify('duyi.com')
})
- ProvidePlugin 自动导入常用的包
new webpack.ProvidePlugin({
$:'jquery',
_:'lodash'
})