# nginx 怎么设置前端项目的缓存
html
。协商缓存
location ~* \.html$ {
expires -1; # 禁用强缓存,浏览器每次请求都要和服务器协商
add_header Cache-Control "no-cache";
add_header ETag $upstream_http_etag;
add_header Last-Modified $date_gmt;
}
其他静态资源
。文件名有 hash 值,所以强缓存
location ~* \.(css|js|jpg|jpeg|png|gif|svg|woff|woff2|ttf|eot|ico)$ {
expires 30d; # 缓存30天
add_header Cache-Control "public, max-age=2592000, immutable";
}
# webpack 打包流程
初始化阶段
解析配置。读取
webpack.config.js
文件配置初始化编译器对象 compiler。根据配置文件创建 compiler 对象,是整个打包过程的控制器
确定入口 entry。根据配置文件读入入口文件,作为构建依赖图的起点
编译阶段
从入口文件开始构建依赖图
递归解析依赖。根据依赖关系,如 import 或 require 引入的模块,将这些依赖加入到依赖图
加载模块并转化。通过 loader 对模块进行转化:比如 babel-lader 将 es6 代码转成 es5、通过 style-loader 和 css-loader 将 css 文件转成模块
生成抽象语法树 ast。webpack 对模块代码生成一个抽象语法树,用于后续的代码分析和转换
将模块代码编译成浏览器可执行的代码。经过解析和转化,最后得到 js 代码
输出
生成代码块 chunk。根据依赖图,webpack 可以将模块分割为多个 chunk,chunk 通常是一个多个打包后的文件
优化和处理代码。webpack 可以根据 plugin 进一步处理代码,比如 ugly 化(UglifyJsPlugin)、提取 css 文件(MinCssExtractPlugin)、自动生成 html 文件(HtmlWebpackPlugin)
文件写入磁盘。根据 outpath 配置,输入文件到指定路径
# npi i 和 mpm ci 的区别
安装依据
npm install
依赖与package.json
package-lock.json
npm ci
严格根据package-lock.json
安装
是否删除 node_moudles
npm install
不会,增量安装npm ci
会,重新安装
安装速度
npm install
较慢,因为它会重新解析依赖npm ci
快一点,严格根据package-lock.json
安装指定版本
适用场景
npm install
适合本地开发npm ci
适合 ci/cd 流程,需要一致性的场景
新增依赖
npm install
可以执行npm install <package>
,进而修改package.json
package-lock.json
文件npm ci
不能执行新增依赖命令
# npm cache 是什么
- npm install 字后会计算每个包的 sha1 值,然后将这个包和和 sha1 值的关联保存到
package-lock.json
文件里面,下次 npm install 的时候,会根据 sha1 值去找对应的包,找到了就不需要重新下载安装了
# webpack 的热更新实现
文件更改的监控, 通过 webpack-dev-server 开发服务器 监听文件变化
- 生成模块依赖树和对用的
moudle id
,这个 id 在构建过程中跟踪和标记模块
- 生成模块依赖树和对用的
重新编译发生变化的模块, webpack
增量编译
,只编译发生变化的模块和依赖模块,生成一个新的模块更新块监控文件变化:webpack 服务器和 webpack 通过 watch 机制,监听到文件变更就会重新编译该文件和其依赖,监听机制实际是监听文件内容对应的 hash 值是否变更
生成新的更新块 chunk,记录了原本的 module id 和 新的内容,注意这里的新的 chunk 是增量编译出来的,同样为了确定 chunk 是否有变更,也有对应的 chunkhash
webpack 服务器向浏览器发送信息,告知哪个模块变更,并且提供新的模块
浏览器根据 module id 进行代码替换
模块替换和更新。 不刷新页面,只是动态替换变更的模块
css 模块,生成新的 style 标签进行替换
js 模块,直接替换旧的代码模块,并调用模块的 dispose 钩子来清理之前的状态
# webpack 的热更新实现 描述
文件变更,webpack 的 watch 机制检测到文件变更
增量编译, Webpack 只会重新编译发生变化的模块及其依赖模块。增量编译的结果会生成一个更新块(Update Chunk),其中包含变更的模块代码和对应的 Module ID(这是每个模块的唯一标识)。
生成更新块 ,更新块会包含新编译的模块内容;每个模块依然有唯一的 Module ID,Webpack 会用这个 Module ID 来跟踪和标识模块;chunkhash 或者 hash 用于标识模块的内容变化,但在 HMR 中,真正起到核心作用的是 Module ID。
通知客户端: Webpack Dev Server 通过 WebSocket 通信,将更新块的内容发送给客户端(浏览器)。
客户端接收更新块, 客户端通过 Module ID 来确定发生变化的模块,直接替换掉缓存中已加载的模块代码。
# vite 的热更新
vite 监听文件变化
更新模块缓存
通过 websocket,通知浏览器 hmr runtime
浏览器基于 esm 的模块机制 用新的模块代码进行替换
# tree shaking 原理
webpack 依赖 babel 和其他 loader,将代码转变成 esm 形式的代码
基于 es6 模块的 import 和 export 的静态分析,可以在打包的时候移除未使用的方法
标记可用代码,移除未使用的代码
# preload、prefetch 怎么理解
preload 提前加载关键资源、优先级高、和页面其他必要资源 CSS JS 一起加载
- 比如汉字语言包,提前加载,从而实现加快首屏渲染
prefetch 提前加载可能需要用到的资源、优先级低、浏览器空闲时间加载
- 比如英文语言包,预先加载,如果用户切换语言将不会再去临时加载英文语言包
# http2 相比较 http1.1 的改进
多路复用, 多个请求/相应可以共用一个 tcp 连接并行传输
头部压缩
二进制分帧
支持服务器推送
单一持久化连接, 单一持久连接,减少连接数
流量控制
减少延迟
# 对于已经 import 的模块,但是没有实际使用,webpack 会打包进去吗
取决于 webpack 配置的优化手段
tree-shaking
,专门用于消除死代码(dead code),基于 es6 的静态分析能力移除未使用的导出,所以 commanjs 的导入导出就没法移除了uglifyJsPlugin
,压缩 js 代码的插件,也会进行死代码消除,会删除没有使用的代码sideEffect属性
,可以在 package.json 里面标识指定文件,告诉 webpack 可以安全的被移除
# 打包过程中代码分割 code splitting 的原理是什么
按需加载
,基于**动态导入 import()**的语法实现,它会返回一个 Promise,从而实现调用的时候才去加载指定的模块依赖关系分析
,基于 webpack 的 dp-graph 依赖图,webpack 会决定模块的打包和分割多入口打包
,这种多页面应用,有不同的入口文件共享代码块
,不同代码块共享相同的依赖的时候,webpack 可以将这些共享以来分离出来,打包成独立的’共享代码块‘proload和prefetch
,预加载 和 预取,也会生成代码分割,webpack 支持魔法注释来设置预加载和预取// 使用预取 import(/* webpackPrefetch: true */ './moduleA.js'); // 使用预加载 import(/* webpackPreload: true */ './moduleB.js');