Node.js
:是一个基于Chrome V8 引擎的 JavaScript
运行环境
Node.js
官方地址: http://nodejs.org/zh-cn
注意:
JavaScript
的前端运行环境。Node.js
是JavaScript
的后端运行环境。Node.js
中无法调用DOM
和BOM
等浏览器内置API
操作步骤:
node 要执行的js文件
注意:
node xxx.js
这种格式模块化就是,把一个大文件拆分成若干个小文件,而且还能把小文件通过特定的语法组合到一起实现过程。
Node使用的是CommonJS规范
导出文件 - 导出
方式一:
module.exports = { 变量名, 方法名,…}
方式二:
exports.xx = xx
导入文件 - 导入
引入:let xxx = require(‘地址URL’)
console.log(xxx.变量名)
示例:
const PI = 3.141592645656475634534
function fn() {
console.log('我是一个方法');
}
// 1. 导出模块 - module.exports 的值是什么外部引入的就是什么
// 第一种方式倾向于导出一个整体
module.exports = {
PI,
fn
}
// exports是modules.exports(对象)引用
// 第二种倾向于导出多个内容
// exports.PI = PI
// exports.fn = fn
// 引入模块
let m1 = require('./02-m1')
console.log(m1.PI);
console.log(m1.fn);
内置模块是Node.js平台自带的一套基本API(功能模块)。也叫做核心模块
注意:
path
是Node本身提供的API,专门用来处理路径示例
// 第一步:先加载要使用的模块
const path = require('path') // 或 let path = require('path')
// 方法1:extname - 获取文件后缀
console.log(path.extname('index.html')) // .html
console.log(path.extname('readme.md')) // .md
// 方法2:join - 智能拼接路径
console.log(path.join('./', 'aa', 'cc', '../bb', 'c')) // aa\bb\c
console.log(path.join('./', 'html', 'index.html')) // html\index.html
// __dirname - 表示当前js文件的绝对路径
console.log(path.join(__dirname, 'css', 'index.css')) // F:\黑马程序员\前端就业班\07-node.js\day01\code\lianXi\css\index.css
示例
// 第一步:引入 fs 模块
const fs = require('fs')
// 方法1:readFile() - 读取文件
// 第一个形参:必填 - 读取文件的路径
// 第二个形参:可选 - 编码的格式
// 第三个形参:必填 - 回调,文件读取成功要做的那些事
fs.readFile('./test', 'utf-8', function (err,data) {
// 该回调函数里有两个形参
// 第一个形参:错误对象,当读取错误时会出现的对象,读取正确的时候为 null
// 第二个形参:读取文件的结果
// 如果读取错误返回一条错误信息 并结束
if (err !== null) return console.log('读取出错啦~')
// 执行完毕没错的时候执行
console.log(data)
})
// 方法2:writeFile() - 写入文件 注:会覆盖之前文件的内容
// 第一个形参:必填 - 写入文件的路径,没有会进行创建
// 第二个形参:必填 - 要写入的数据,可以放对象等等
// 第三个形参:可选 - 编码的格式,不写默认utf-8
// 第四个形参:可选 - 写入完成后的回调函数
fs.writeFile('./test2.txt', '这里是要写入的内容', function (err) {
if (err !== null) return console.log('写入出错了!!!')
console.log('写入成功~')
})
// 引入 http 模块
const http = require("http")
//引入 fs 模块
const fs = require("fs")
// 2. 创建服务器对象
const server = http.createServer()
// 3. 监听客户端的请求
server.on("request", function (request, response) {
// 当客户端请求,就会触发这个回调函数
// request请求对象,包含客户端请求时携带的一些信息(参数,路径,请求头。。。)
// 指定就是端口号后面的路径 - 获取get
console.log(request.url) // /favicon.ico
// 获取 请求方式
console.log(request.method) // GET
// response相应对象,返回数据时使用
console.log("有人访问了我们的服务器")
//相应给客户端
//相应数据
// response.end('{ "name" : "zs", "age" : 18}')
// 相应文件的写法
// 解决中文乱码
response.setHeader("Content-Type", "text/html;charset=utf-8")
fs.readFile("./index.html", "utf8", function (err, data) {
if (err !== null) {
return response.end("404")
}
response.end(data)
})
})
// 4. 启动服务器
// 第一个参数:端口号,必填
// 第二个参数:运行成功回调,选填
server.listen(80, function () {
console.log("服务器启动成功,运行在 http://127.0.0.1:80")
})
// 终止服务器运行 Ctrl+c
npm init
npm init -y
npm下载 淘宝源
npm config set registry https://registry.npm.taobao.org
# 初始化,需要输入项目信息(可以使用默认,但是项目名称不能为中文不然会报错),输入完成后,可以一路回车
npm init
# 初始化,直接全部采用默认信息
npm init -y
初始化完毕后的操作 - 这样下载国外网址的包会更快
建议在安装第三方模块之前,先执行如下命令。
下面的命令只需要执行一次即可(不管以后重启vscode还是重启电脑,都不需要执行第二次)
npm config set registry https://registry.npm.taobao.org
### 8.2 下载包
> npm install 包名
>
> npm install 模块名 模块名 模块名
>
> npm install -D 包名
>
> npm install -g 包名
>
> npm ls -g --depth 0
>
> npm install
- 下载安装第三方模块
```shell
# 正常的下载安装
npm inster 包名
# 下载指定版本依赖
npm i 包名@版本号
# 下载多个包
npm install 包名 包名 包名...
# 下载开发依赖
npm install -D 包名
# 或
npm install --save-d 包名
# 下载全局 - 下载工具性质的包,比如vue-cli(创建vue项目的脚手架工具)、nrm(切换下载源)
npm install -g nrm
# mac电脑(需要管理员权限) sudo npm install -g nrm
# 查看全局下载的包
npm ls -g --depth 0
# 根据package.json文件dependencies和devDependencies字段自动下载对应的包,在新接触一个项目后,第一件事就是使用该命令来安装依赖
npm install
# !!!所有的 install 都可以替换为 i
注意:
关于本地模块的说明
node_modules
文件夹中,同时还会生成一个记录下载的文件 package-lock.json
npm uninstall 包名
npm unin
# 删除指定第三方包
npm uninstall 包名
# 简化写法
npm un 包名
# 删除多个
npm un 包名 包名...
# 删除全局包
npm un -g 包名
// 1. 任何包第一步都需要引入,require里面直接写包名
const pkg = require('包名')
// 2. 参考文档使用包
// 2.1 去官方找,比较优秀的包都是官网的,例如:vue,react,angular,lodash...
// 2.2 npmjs.com 搜索包,包主页会有文档
// 2.3 百度搜
**作用:**用来切换下载镜像源
nrm ls
nrm user 源名
# 以列表的形式查看源
nrm ls
# 切换源
nrm use 源名
{
"name": "npm-test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "ipconfig"
},
"author": "",
"license": "ISC",
"dependencies": {
"cors": "^2.8.5",
"jquery": "^3.6.0",
"moment": "^2.29.3",
"sass": "^1.51.0"
}
}
name
- 项目名,不能有中文
version
- 版本号,只能数字和点
description
- 描述
main
- 项目的入口文件是哪一个文件
scripts
- 声明简化命令
{
"简化命令": "真实命令(命令行能用的名)",
"start": "node ./index.js",
// "start": "ipconfig"
}
// 执行简化命令,在命令行中输入 npm run 简化命令
// start特殊,start可以 npm run start 也可以 npm start
author
- 作者
license
- 许可证
dependencies
- 项目运行依赖(第三方包的信息,这里包含的包只要没有,项目就无法运行)
devDependencies
- 项目开发依赖(开发中会用到,在项目运行时不会用,例如:less,sass)
判断缓存中有没有,如果有,使用缓存中的内容
缓存中没有,那么表示第一次加载,加载完会缓存
判断模块名有没有带路径(./)
模块名中有路径,加载自定义模块(自己写的文件)const xx = require('./xx')
模块名没有路径,优先加载核心模块,如果没有核心模块,则加载第三方模块
加载第三方模块的查找方式
更多关于npm的命令:https://www.npmjs.cn/
在清楚了包的概念、以及如何下载和使用包之后,接下来,我们深入了解一下包的内部结构。
- sy123
- package.json (package.json包的配置文件)
- index.js (入口文件)
- README.md (说明文档)
一个规范的包结构,需要符合以下 3 点要求:
注意: 以上 3 点要求是一个规范的包结构必须遵守的格式,关于更多的约束,可以参考如下网址:
https://yarnpkg.com/zh-Hans/docs/package-json
{
"name": "sy123", // 包(模块)的名字,和文件夹同名。别人加载我们的包,找的就是这个文件夹
"version": "1.0.0",
"description": "This is a package by Laotang",
"main": "index.js", // 别人加载我们的模块用,require加载的就是这里指定的文件
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [ // 在npm网站中,通过关键字可以搜索到我们的模块,按情况设置
"laotang",
"itcast",
"test"
],
"author": "Laotang", // 作者
"license": "ISC" // 开源协议
}
注意,JSON文件不能有注释,下面加注释,是为了理解。
关于更多 license 许可协议相关的内容,可参考 https://www.jianshu.com/p/23e61804d81e
// 别人加载的就是我的 index.js
// 所以,必须在 index.js 中导出内容
function a() {
console.log('aaa')
}
function b() {
console.log('bbb')
}
module.exports = { a, b }
编写包的说明文档
包根目录中的 README.md 文件,是包的使用说明文档。通过它,我们可以事先把包的使用说明,以 markdown 的 格式写出来,方便用户参考。
README 文件中具体写什么内容,没有强制性的要求;只要能够清晰地把包的作用、用法、注意事项等描述清楚即可。
# 切换npm源 - 切换镜像源为npm(不能发布到淘宝,所以必须切换镜像源为npm主站)
npm use npm
# 登录npm - 按照提示输入账号、密码(输入的密码是看不见的,正常)、邮箱、邮箱收到的一次性密码
npm login
# 发布 - 执行命令的文件夹,必须是包的根目录
npm publish
# 在package.json中version,升级版本号
# 推送不上去,就使用 npm login 重新登录一下
npm publish
npm unpublish 包名 --force
是一种编程方式,将整体打碎,编程一个个的模块,每个模块是独立的功能,把模块合到一起拼成完成的项目。
AMD - 依赖前置。require.js
CMD - 依赖就近。sea.js
注意:非官方实现规范
CommonJs,require引入,module.exports导出
自定义模块
require('./要引入的js文件路径')
来源:自己编写
核心模块
require('包名')
来源:nodejs自带
第三方模块
require('包名')
来源:需要下载
npm install 包名
npm i 包名
npm i 包名 包名...
npm i 包名@版本号
# 下载开发依赖
npm i -D 包名
# 下载全局包
npm i -g 包名
是js官方退出,为了解决js在不同的平台没有同意模块化标准问题。
nodejs版本要在13版本以上,在package.json中声明 type: "module"
export default 要导出的内容
import 自定义名称 from ‘路径.js’
场景:导出一个内容
示例
导出文件 01-module.js
const PI = 3.1415926256252236
function fn() {
console.log(111)
}
export default {
PI,
fn
}
导入文件 01-导入.js
import m1 from './01-module.js'
console.log(m1)
export let a = 1
import { 导出变量名 } from ‘路径.js’
示例
导出文件 02-module.js
// export 后面直接跟导出内容的完整的语句
export let a = 111
export function fn() {
console.log(222)
}
// 这一个顶上面两个
export {
a,
fn
}
// 报错,因为没有提供接口(取数据数据名)
//export 1
//export a
导入文件 02-导入
// import { 导出的值(名字不能变,导入的是什么名,导出的就是什么名,导入也要是什么名) } from '路径'
// 如果要给引入的内容起别名使用 as
// 语法:导出名 as 别名
import { a as a1, fn } from "./02-module.js"
console.log(a1)
console.log(fn)
import ‘./03-module.js’
示例
文件 03-module.js
for (let i = 0; i < 5; i++) {
console.log(i)
}
导入文件 03-直接导入.js
import './03-module.js'
解决问题:回调地狱
多个异步任务是无法保证执行顺序的,当我们想让多个异步任务按照固定的顺序执行,写出来的代码就是回调地狱
回调地狱 - 示例
import fs from 'fs'
fs.readFile('./a.txt', 'utf-8', function (err, data) {
if (err) return
console.log(data)
fs.readFile('./b.txt', 'utf-8', function (err, data) {
if (err) return
console.log(data)
fs.readFile('./c.txt', 'utf-8', function (err, data) {
if (err) return
console.log(data)
})
})
})
定义Promise对象
const p1 = new Promise((resolve,reject) => {
// 成功时执行resolve,比如成功获取服务端数据,读取文件内容成功。
// 失败时执行reject,因为参数错误(权限不够)导致业务执行失败
// resolve(想传给外面的数据,比如成果获取到服务数据或读取到文件内容)
// reject(失败信息)
})
使用
p1.then(
// 必填,调用resolve时执行,参数就是resolve中的参数
res => {},
// 可选,调用reject时执行,参数就是reject中的参数
err => {}
)
当达到最终的 fulfilled 或 rejected 时,promise的状态就不会再改变了。
当调用 resolve的时候,Promise 将到达最终的状态。 达到最终状态之后,Promise的状态就不会再改变了。
多次调用 resolve 函数,只有第一次有效,其他的调用都无效。
const fs = require('fs');
// 1. 创建 Promise 对象;(承诺)
let p = new Promise((resolve, reject) => {
resolve(123);
resolve(456); // 这次调用无效
});
// 2. 获取异步任务的结果
// p.then(函数1, [函数2]);
p.then(res => {
console.log(res); // 123
}, err => {
console.log(err);
});
Promise
构造函数,是同步的
then
里面的函数,是异步的
// 同步
console.log(1)
const p1 = new Promise(resolve => {
// 同步
console.log(2)
resolve()
console.log(3)
})
p1.then(() => {
// 异步
console.log(4)
})
// 同步
console.log(5)
// 结果:12354
前一个then里面返回的字符串,会被下一个then方法接收到。但是没有意义;
前一个then里面返回的Promise对象,并且调用resolve的时候传递了数据,数据会被下一个then接收到
前一个then里面如果没有调用resolve,则后续的then不会接收到任何值
ES6 — ES2015
async 和 await 是 ES2017 中提出来的。
异步操作是 JavaScript 编程的麻烦事,麻烦到一直有人提出各种各样的方案,试图解决这个问题。
从最早的回调函数,到 Promise 对象,再到 Generator 函数,每次都有所改进,但又让人觉得不彻底。它们都有额外的复杂性,都需要理解抽象的底层运行机制。
异步I/O不就是读取一个文件吗,干嘛要搞得这么复杂?异步编程的最高境界,就是根本不用关心它是不是异步。
async 函数就是隧道尽头的亮光,很多人认为它是异步操作的终极解决方案。
ES2017 提供了async和await关键字。await和async关键词能够将异步请求的结果以返回值的方式返回给我们。
.catch()
或 在promise对象后使用 .catch()
const fs = require('fs');
// 将异步读取文件的代码封装
function myReadFile (path) {
return new Promise((resolve, reject) => {
fs.readFile(path, 'utf-8', (err, data) => {
err ? reject(err) : resolve(data.length);
});
}).catch(err => {
console.log(err);
});
}
async function abc () {
let a = await myReadFile('./a.txt');
let b = await myReadFile('./b.txt');
let c = await myReadFile('./c.txt');
console.log(b);
console.log(a);
console.log(c);
}
abc();
前提是得到几个Promise对象,代码如下:
let fs = require('then-fs');
let p1 = fs.readFile('./files/a.txt', 'utf-8');
let p2 = fs.readFile('./files/bbb.txt', 'utf-8'); // 注意,这里故意写错路径
let p3 = fs.readFile('./files/c.txt', 'utf-8');
获取Promise的结果,可以通过 then 来获取。也可以通过 async 和 await 获取。
如果使用 then 获取结果,那么错误如何处理:在链式调用的尾端,加一个catch方法即可
// ---------------------- 通过 then 获取结果 ----------------------------
p1.then(res => {
console.log(res.length);
return p2;
}).then(res => {
console.log(res.length);
return p3;
}).then(res => {
console.log(res.length);
}).catch(err => {
console.log(err);
})
如果使用async和await获取结果,最好的错误处理方案,就是使用 try ... catch ...
// ---------------------- 通过 async/await 获取结果 ----------------------------
async function abc() {
try { // 尝试做一些事情
let r1 = await p1; // 正常得到结果
let r2 = await p2; // 这里出错了,就会抛出错误 throw err。
let r3 = await p3;
console.log(r1.length, r2.length, r3.length);
} catch (e) {
console.log(e); // catch这里,会抓住前面try里面抛出的错误
}
}
abc();
JavaScript是单线程的,也就是说,同一个时刻,JavaScript只能执行一个任务,其他任务只能等待。
js是运行于浏览器的脚本语言,因其经常涉及操作dom,如果是多线程的,也就意味着,同一个时刻,能够执行多个任务。
试想,如果一个线程修改dom,另一个线程删除dom,那么浏览器就不知道该先执行哪个操作。
所以js执行的时候会按照一个任务一个任务来执行。
试想一下,如果js的任务都是同步的,那么遇到定时器、网络请求等这类型需要延时执行的任务会发生什么?
页面可能会瘫痪,需要暂停下来等待这些需要很长时间才能执行完毕的代码
所以,又引入了异步任务。
事件循环的比较简单,它是一个在 “JavaScript 引擎等待任务”,"执行任务"和"进入休眠状态等待更多任务"这几个状态之间转换的无限循环。
引擎的一般算法:
根据规范,事件循环是通过任务队列的机制来进行协调的。一个 Event Loop 中,可以有一个或者多个任务队列(task queue),一个任务队列便是一系列有序任务(task)的集合;每个任务都有一个任务源(task source),源自同一个任务源的 task 必须放到同一个任务队列,从不同源来的则被添加到不同队列。setTimeout/Promise 等API便是任务源。
在事件循环中,每进行一次循环的关键步骤如下:
在上述循环的基础上需要了解几点:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BZFDf1R5-1653472547308)(F:\黑马程序员\前端就业班\07-node.js\02-案例\项目前置课-03\文档\其他.assets\bV31Xm)]
(macro)task,可以理解是每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)。
任务(代码) | 宏任务 | 环境 |
---|---|---|
script | 宏任务 | 浏览器 |
事件 | 宏任务 | 浏览器 |
网络请求(Ajax) | 宏任务 | 浏览器 |
setTimeout() 定时器 | 宏任务 | 浏览器 / Node |
fs.readFile() 读取文件 | 宏任务 | Node |
比如去银行排队办业务,每个人的业务就相当于是一个宏任务;
微任务(microtask)是宏任务中的一个部分,它的执行时机是在同步代码执行之后,下一个宏任务执行之前。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iOSCSokB-1653472547310)(F:\黑马程序员\前端就业班\07-node.js\02-案例\项目前置课-03\文档\其他.assets\image-20210418173900754.png)]
Promise.then
process.nextTick(Node.js 环境)
比如一个人,去银行存钱,存钱之后,又进行了一些了操作,比如买纪念币、买理财产品、办信用卡,这些就叫做微任务。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D1IICVgU-1653472547311)(F:\黑马程序员\前端就业班\07-node.js\02-案例\项目前置课-03\文档\其他.assets\image-20210326115124196.png)]
在事件循环中,每进行一次循环操作称为 tick,每一次 tick 的任务处理模型是比较复杂的,但关键步骤如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8S6A8DeZ-1653472547312)(F:\黑马程序员\前端就业班\07-node.js\02-案例\项目前置课-03\文档\其他.assets\image-20210623200912106.png)]
初级使用步骤
在项目根目录创建 webpack.config.js 文件
在这个文件内写一下代码
const path = require('path')
module.exports = {
// 打包方式 - development 开发环境(编写程序的时候使用), production 生产环境(项目完成上线的时候)
mode: 'development', // 决定了 main.js 编译的方式
// 修改入口文件
entry: './src/index1.js',
// 修改出口文件(打包后的文件路径和文件名)
output: {
// 指定打包好后文件的路径
path: path.join(__dirname, 'dist'),
// 指定打包好后文件的文件文件夹名称
filename: 'a.js'
}
}
在package.json中script内声明 "build": "webpack"
运行简化命令行 npm run build
在html中引入生成的main.js
注意
目标:
安装 webpack 相关的两个包: [email protected]
和 [email protected]
(前面已经统一安装过了)
① 在项目根目录中,创建名为 webpack.config.js
的 webpack 配置文件,并初始化如下的基本配置:
module.exports = {
// 打包模式
mode: 'development', // production:生成 development:开发
}
② 在 package.json 的 scripts 节点下,新增 dev 脚本如下:
"scripts": {
"dev": "webpack"
},
③ 在终端中运行 npm run dev
命令,启动 webpack 进行项目的打包构建
执行 npm run dev
命令后,会在项目根目录生成 dist
文件夹,并在 dist
文件夹中生成 main.js
main.js 就是 jquery.js 和 index.js 的结合体。
index.html 中引入 main.js ,再看效果。
目标:清楚每个 mode 值的作用,知道每个值的具体应用场景。
mode 节点的可选值有两个,分别是:
① development
② production
webpack.config.js是什么
作用
被读取的时机
在 webpack 4.x 和 5.x 的版本中,有如下的默认约定:
① 默认的打包入口文件为 src -> index.js
② 默认的输出文件路径为 dist -> main.js
注意:可以在 webpack.config.js 中修改打包的默认约定
在 webpack.config.js 配置文件中,通过 entry 节点指定打包的入口。通过 output 节点指定打包的出口。
示例代码如下:
// 引入path 并解构出 join方法
const { join } = require('path');
module.exports = {
// 打包模式
mode: 'development', // production:生成 development:开发
// 入口文件
entry: join(__dirname, 'src', 'index.js'),
// 出口文件
output: {
path: join(__dirname, 'dist'), // 要使用绝对路径,否则报错
filename: 'bundle.js',
}
}
重新运行 npm run dev
,即可得到新的打包结果 bundle.js
.
index.html 中引入新的打包结果 bundle.js。
最常用的 webpack 插件有如下3个:
① clean-webpack-plugin
② webpack-dev-server
③ html-webpack-plugin
作用:每次打包构建的时候,自动清理 dist 目录下的旧文件,保证 dist 目录的代码是最新的。
安装依赖包:[email protected] (前面已经统一安装过)
在 webpack.config.js 中增加配置:
// 1. 配置自动清理插件(在打包的时候,插件就会自动清理 dist 中没用的文件)
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const cleanPlugin = new CleanWebpackPlugin();
module.exports = {
mode: 'development',
// 其他项省略......
// 插件配置
plugins: [ cleanPlugin ]
}
重新运行 npm run dev
,即可将 dist
文件夹中没用的文件清理掉。
作用:可以让 webpack 监听项目源代码的变化,从而进行自动打包构建。
安装包 [email protected](前面已经统一安装过)
配置 webpack-dev-server
① 修改 package.json -> scripts 中的 dev 命令如下:
"scripts": {
"dev": "webpack serve" // 注意这里是 serve ,不是 server
},
② 在 webpack.config.js 配置文件中,增加 devServer 节点对 webpack-dev-server 插件进行更多的配置
devServer: {
port: 9000, // 实时打包所用的端口号
open: true // 初次打包完成后,自动打开浏览器
}
③ 再次运行 npm run dev 命令,重新进行项目的打包
④ 在浏览器中访问 http://localhost:8080 地址,查看自动打包效果
注意:凡是修改了 webpack.config.js 配置文件,或修改了 package.json 配置文件,必须重启实时打包的服务器,否则最新的配置文件无法生效!
① 不配置 webpack-dev-server 的情况下,webpack 打包生成的文件,会存放到实际的物理磁盘上
严格遵守开发者在 webpack.config.js 中指定配置
根据 output 节点指定路径进行存放
② 配置了 webpack-dev-server 之后,打包生成的文件存放到了内存中
所以,index.html 中应该这样引入js
html-webpack-plugin 是 webpack 中的 HTML 插件。
作用:自动把生成好的 bundle.js 注入到 HTML 页面中。
安装包 [email protected] (前面已经统一安装过)
在webpack.config.js中配置 html-webpack-plugin
const HtmlPlugin = require('html-webpack-plugin');
const htmlPlugin = new HtmlPlugin({
template: path.join(__dirname, 'public', 'index.html'), // public中,你的html叫什么
filename: 'index.html' // 打包后的html叫什么(这个文件会生成到dist文件夹)
});
module.exports = {
mode: 'development',
// 其他项省略......
// 插件配置
plugins: [ cleanPlugin, htmlPlugin ]
}
其他说明:
① 通过 HTML 插件复制到项目根目录中的 index.html 页面,也被放到了内存中,所以看不到
② HTML 插件在生成的 index.html 页面,自动注入了打包的 bundle.js 文件