# 利用依赖信息更新 browser hash
在预构建启动前已经生成了 main hash, 同时 browser hash 也等于 main hash, 如果不进行预构建的情况下 main hash 与 browser hash 相同。
# main hash
main hash 的生成是用来重新启动时,比对当前生成的 main hash 与上次构建参照的 main hash 是否需要进行重新执行构建。
# browser hash
browser hash 在浏览加载资源的时候, 告诉浏览器是否需要向服务端重新加载资源, 在预构建扫描入口的情况下并不会总是把所有文件扫描干净,收集到应该收集的所有依赖。等到浏览器启动加载资源时, 如果此资源是需要进行预构建,在构建元信息内容中找到构建内容,将会再次进行与原有依赖内容合并后再次构建后,自动重新刷新浏览器, 重新预构建的内容将需要重服务端重新获取。因为构建内容将会重新改变, 不能再次利用 304 缓存, 需要向服务器再次重新请求最新资源。
// update browser hash
data.browserHash = createHash('sha256')
.update(data.hash + JSON.stringify(deps))
.digest('hex')
.substr(0, 8)
生成方式与 main hash 一样,调用 node 模块 crypto 的 createHash 方法对进行 hash 加密,截取8位,加密的内容是由 main hash + 所收集的所有依赖。这样就可以确保在开发中, 自动重新预构建时候,保证加载的是最新的资源。
提示
这里需要一张理解图 尽请期待....
# 报错提示缺失的依赖
在项目中,如果缺少任务一个导入模块包(NPM包), 这必定是一个无法正常运行的项目, 在收集依赖时,如果发现缺少对应依赖的文件内容时,Vite 将会中断赖个构建过种, 通过报错提示告诉开发者。
const missingIds = Object.keys(missing)
if (missingIds.length) {
throw new Error(
`The following dependencies are imported but could not be resolved:\n\n ${missingIds
.map(
(id) =>
`${chalk.cyan(id)} ${chalk.white.dim(
`(imported by ${missing[id]})`
)}`
)
.join(`\n `)}\n\nAre they installed?`
)
}
missing 的数据结构是由导模块名称作为 key, 所有导入模块的文件路径作为 value。
// /user/admin/project/src/main.js 文件
import dayjs from 'dayjs'
// 返回的数据格式
{
"dayjs" : "/user/admin/project/src/main.js"
}
提取 missing 中的 key 通过抛错进行通知。
TIP
这里需要加一个报错图 尽请期待....
# 添加 optimizeDeps.include 依赖
之前是通过文件入口进行扫描, 某些情况下入口扫描无法完全扫描, 需要在加载资源的时候会进行重新预构建, pre-bundle 是队列的形式,队列一旦比较多,会影响启动速度,不断重新构建,重新刷新页面。
入口扫描加入依赖的内容只会存在 bare Import, 表示从 node_modules 包导入的模块
同时还可以解决业务模块同时导入一个模块后, 进行再进行导出的方式会影响加载性能,会占用大量connect连接线程进行阻塞加载, 可以通过 include 加入依赖, 进行合并构建。
const include = config.optimizeDeps?.include
if (include) {
const resolve = config.createResolver({ asSrc: false })
for (const id of include) {
if (!deps[id]) {
const entry = await resolve(id)
if (entry) {
deps[id] = entry
} else {
throw new Error(
`Failed to resolve force included dependency: ${chalk.cyan(id)}`
)
}
}
}
}
通过 config 的配置获取 include 数组,如果存在 include 依赖,通过 for of 循环, 如果模块已经被收集依赖则过滤,否则对模块进行解析文件路径,无法解析到预期的文件路径则提示报错,错误内容为 include 中的依赖收集 id。 路径解析成功,则加入构建依赖收集项中。
不符合构建文件类型
如果 include 中导入解析的文件非 .js 或者 .mjs 被 es-module-lexer 后续词法分析进行抛错。
# 未收集到依赖
在服务启动前是否收集到构建依赖分为两点:
- 入口扫描是否收集到依赖。
optimizeDeps.include中是否包含依赖。
const qualifiedIds = Object.keys(deps)
if (!qualifiedIds.length) {
writeFile(dataPath, JSON.stringify(data, null, 2))
log(`No dependencies to bundle. Skipping.\n\n\n`)
return data
}
声明 qualifiedIds 变量, 通过 Object.keys 进行收集构建依赖的模块名称, 如果不存在任何需要构建的依赖,把 data 元数据数进行返回赋值到 server._optimizeDepsMetadata属性上。同时向缓存文件进行写入优化元信息内容。
提示
此时元信息中只会包含 hash、 browserHash, optimized 构建内容元信息并是一个空的对象, 因为没有进行依赖构建。
// _metadata.json文件
{
hash: XXXXXXXX,
browserHash: XXXXXXXX,
optimized: {}
}
# 构建依赖前的提示
依赖已经收集完毕了, 马上就要临近构建了, 在构建前需要提示开发者, 当前构建了那些依赖。 预构建的执行会在三处。这三处理的执行预构建方法给开发者的提示都不一样。
通过控制台命令行进行指令调用
logger.info(chalk.greenBright(`Optimizing dependencies:\n ${depsString}`))
只通知优化内容
调用vite createServer启动前调用
logger.info(
chalk.greenBright(`Pre-bundling dependencies:\n ${depsString}`)
)
logger.info(
`(this will be run only when your dependencies or config have changed)`
)
不但通知优化内容,还进行提示: 通过配置进行改动,将重新进行预构建
启动后加载资源时进行调用
if (!asCommand) {
if (!newDeps) {
// This is auto run on server start - let the user know that we are
// pre-optimizing deps
logger.info(
chalk.greenBright(`Pre-bundling dependencies:\n ${depsString}`)
)
logger.info(
`(this will be run only when your dependencies or config have changed)`
)
}
} else {
logger.info(chalk.greenBright(`Optimizing dependencies:\n ${depsString}`))
}
asCommand表示是否是命令行启动。newDeps表示是否是加载时执行的优化。
不进行任何提示, 在进行加载资源时优化的执行逻辑时内部分进行提示。
depsString 生成方法
const total = qualifiedIds.length
const maxListed = 5
const listed = Math.min(total, maxListed)
const extra = Math.max(0, total - maxListed)
const depsString = chalk.yellow(
qualifiedIds.slice(0, listed).join(`\n `) +
(extra > 0 ? `\n (...and ${extra} more)` : ``)
)
变量 total 是需要构建依赖的总数。
变量 maxListed 表示最大只展示 5 条构建依赖模块名称。
变量 listed 表示得到最小的截取数量, 如果依赖总数小于 maxListed,则用 total,否则用 maxListed。
变量 extra 表示大于 5 条构建依赖条目时,还有多少省略展示。
展示的构建提示内容
Pre-bundling dependencies:
vue
ant-design-vue
@ant-design/icons-vue
vue-router
vuex
(...and 9 more)
(this will be run only when your dependencies or config have changed)
总共有 14 条需要构建的依赖, 只展示了前 5 个,9 个将被省略展示。