# 服务器启动前触发

通过源码中的注释: // overwrite listen to run optimizer before server start, 可以发现在服务器启动前, httpServer.listen启动前运行优化器。

调用 createServer 启动前,将会重写 listen 方法,调用优化器之后,再进行 listen 启动。

const listen = httpServer.listen.bind(httpServer)
httpServer.listen = (async (port: number, ...args: any[]) => {
  try {
    await runOptimize()
  }
  return listen(port, ...args)
}) as any

如果采用其它框架做为服务器时, 服务的器的启动是由开发者自行调用, 但在执行启动前 createServer 内部同样也会等到优化器执行完毕。

  if (!middlewareMode && httpServer) {
    ...
  } else {
    await runOptimize()
  }

# 浏览器导入资源时触发

在服务器启动前, 会对从 启动的html入口 和 自定义 optimizeDeps.entries 进行递归检查导入扫描, 收集构建依赖进行优化, 但是往往有些情况下, 优化扫描器并不能完全扫描收集到所有的构建依赖, 会有以下情况:

  1. import动态加载
const root = 'util'
import(/* @vite-ignore */ `./${root}/index.js`)
// util/index.js
import lodash from 'lodash'

lodash 对于 Vite 是需要进行构建的模块, 但在启动前虽然导入了 util/index.js 模块, 将不会深入文件内部扫描。

注意

动态 import 导入模块时, 路径存在 动态变量 时, 扫描器无法对 动态变量 的导入路径进行准确的扫描, 因为 动态变量 是不确定的因素, 在扫描期间并不会对动态变量 进行转换, 无法准确判断导入的路径。

  1. 通过插件 APItransform 方法转换源代码
// one.js
export default {}
// 插件方法
function myPlugin ()  {
  return {
    transform(src, id) {
      if (id.indexOf('one.js') >= 0) {
        return `
          import dayjs from 'dayjs'
          ${src}
        `
      }
    },
  }
}

dayjs 对于 Vite 是需要进行构建的模块, 在服务启动前并不会执行插件 transform 方法。

注意

插件 APItransform 是浏览器加载资源时, 服务器会经过此函数进行转换后再把内容发送到浏览器, 扫描器将无法提前识别转换后的文件内容。

  1. 通过插件 resolveIdload 插件 API 引入虚拟文件
// 引入的虚拟模块
import File from '@my-virtual-file'
// 插件内容
function myPlugin ()  {
  return {
    resolveId (id) {
      if (id === '@my-virtual-file') {
        return '@my-virtual-file'
      }
    },
    load(id) {
      if (id === '@my-virtual-file') {
        return `
          import moment from 'moment'
          export default {}
        `
      }
    },
  }
}

@my-virtual-file 虚拟模块在扫描依赖时, 解析导入模块 id 时会原封动返回, 会被扫描器当作虚拟模块进行过滤, 返回 true

// virtual id
if (resolvedId === rawId || resolvedId.includes('\0')) {
  return true
}

注意

load 同样和 transform 原理一样, 只有在浏览加载虚拟模块时, 服务器执行 load 向浏览器返回生成后的内容, 也无法在服务器启动前被扫描器收集到需要构建依赖。