• 一级标题
  • 二级标题
  • 三级标题
  • 四级标题
  • 五级标题
  • 六级标题
  • 添加链接
  • 上传图片
  • 裁剪上传
  • 流程图
  • 时序图
  • 甘特图
  • 类图
  • 状态图
  • 饼图
  • 关系图
  • 旅程图
  • 行内公式
  • 块级公式
添加链接
//server 只在开发环境使用,默认只需关注development
const config = await resolveConfig(inlineConfig, 'serve', 'development')

源码位置:packages\vite\src\node\config.ts

核心代码如下:

export async function resolveConfig(
  inlineConfig: InlineConfig,
  command: 'build' | 'serve',
  defaultMode = 'development'
): Promise<ResolvedConfig> {
  let config = inlineConfig
  let configFileDependencies: string[] = []
  let mode = inlineConfig.mode || defaultMode


  let { configFile } = config

  //默认情况下,执行 vite dev,configFile 为 undefined
  //执行 vite dev --config vite.congfig.ts 时, configFile为vite.congfig.ts
  // configFile!==false 总是为true
  if (configFile !== false) {
    //加载本地的配置文件,可以是命令行或自动从根目录查找
    const loadResult = await loadConfigFromFile(
      configEnv,
      configFile,
      config.root,
      config.logLevel
    )
    if (loadResult) {
      config = mergeConfig(loadResult.config, config)
      configFile = loadResult.path
      configFileDependencies = loadResult.dependencies
    }
  }



  // user config may provide an alternative mode. But --mode has a higher priority
  mode = inlineConfig.mode || config.mode || mode
  configEnv.mode = mode

  // resolve plugins
  // 解析配置文件里面的插件
  const rawUserPlugins = (config.plugins || []).flat(Infinity).filter((p) => {
    if (!p) {
      return false
    } else if (!p.apply) {
      return true
    } else if (typeof p.apply === 'function') {
      return p.apply({ ...config, mode }, configEnv)
    } else {
      return p.apply === command
    }
  }) as Plugin[]
  const [prePlugins, normalPlugins, postPlugins] =
    sortUserPlugins(rawUserPlugins)

  // resolve worker
  const resolvedWorkerOptions: ResolveWorkerOptions = {
    format: config.worker?.format || 'iife',
    plugins: [],
    rollupOptions: config.worker?.rollupOptions || {}
  }

  // run config hooks
  const userPlugins = [...prePlugins, ...normalPlugins, ...postPlugins]
  for (const p of userPlugins) {
    if (p.config) {
      const res = await p.config(config, configEnv)
      if (res) {
        config = mergeConfig(config, res)
      }
    }
  }

  // resolve root
  const resolvedRoot = normalizePath(
    config.root ? path.resolve(config.root) : process.cwd()
  )

  const clientAlias = [
    { find: /^[\/]?@vite\/env/, replacement: () => ENV_ENTRY },
    { find: /^[\/]?@vite\/client/, replacement: () => CLIENT_ENTRY }
  ]

  // resolve alias with internal client alias
  const resolvedAlias = normalizeAlias(
    mergeAlias(
      // @ts-ignore because @rollup/plugin-alias' type doesn't allow function
      // replacement, but its implementation does work with function values.
      clientAlias,
      config.resolve?.alias || config.alias || []
    )
  )

  const resolveOptions: ResolvedConfig['resolve'] = {
    dedupe: config.dedupe,
    ...config.resolve,
    alias: resolvedAlias
  }

  // load .env files
  const envDir = config.envDir
    ? normalizePath(path.resolve(resolvedRoot, config.envDir))
    : resolvedRoot
  const userEnv =
    inlineConfig.envFile !== false &&
    loadEnv(mode, envDir, resolveEnvPrefix(config))

  // Note it is possible for user to have a custom mode, e.g. `staging` where
  // production-like behavior is expected. This is indicated by NODE_ENV=production
  // loaded from `.staging.env` and set by us as VITE_USER_NODE_ENV
  const isProduction = (process.env.VITE_USER_NODE_ENV || mode) === 'production'
  if (isProduction) {
    // in case default mode was not production and is overwritten
    process.env.NODE_ENV = 'production'
  }

  // resolve public base url
  const BASE_URL = resolveBaseUrl(config.base, command === 'build', logger)
  const resolvedBuildOptions = resolveBuildOptions(config.build)

  // resolve cache directory
  const pkgPath = lookupFile(resolvedRoot, [`package.json`], { pathOnly: true })
  const cacheDir = config.cacheDir
    ? path.resolve(resolvedRoot, config.cacheDir)
    : pkgPath
    ? path.join(path.dirname(pkgPath), `node_modules/.vite`)
    : path.join(resolvedRoot, `.vite`)

  const assetsFilter = config.assetsInclude
    ? createFilter(config.assetsInclude)
    : () => false

  const { publicDir } = config
  const resolvedPublicDir =
    publicDir !== false && publicDir !== ''
      ? path.resolve(
          resolvedRoot,
          typeof publicDir === 'string' ? publicDir : 'public'
        )
      : ''

  const server = resolveServerOptions(resolvedRoot, config.server, logger)

  const optimizeDeps = config.optimizeDeps || {}

  const resolved: ResolvedConfig = {
    ...config,
    configFile: configFile ? normalizePath(configFile) : undefined,
    configFileDependencies: configFileDependencies.map((name) =>
      normalizePath(path.resolve(name))
    ),
    inlineConfig,
    root: resolvedRoot,
    base: BASE_URL,
    resolve: resolveOptions,
    publicDir: resolvedPublicDir,
    cacheDir,
    command,
    mode,
    isWorker: false,
    isProduction,
    plugins: userPlugins,
    server,
    build: resolvedBuildOptions,
    preview: resolvePreviewOptions(config.preview, server),
    env: {
      ...userEnv,
      BASE_URL,
      MODE: mode,
      DEV: !isProduction,
      PROD: isProduction
    },
    assetsInclude(file: string) {
      return DEFAULT_ASSETS_RE.test(file) || assetsFilter(file)
    },
    logger,
    packageCache: new Map(),
    createResolver,
    optimizeDeps: {
      ...optimizeDeps,
      esbuildOptions: {
        keepNames: optimizeDeps.keepNames,
        preserveSymlinks: config.resolve?.preserveSymlinks,
        ...optimizeDeps.esbuildOptions
      }
    },
    worker: resolvedWorkerOptions
  }

  // flat config.worker.plugin
  const [workerPrePlugins, workerNormalPlugins, workerPostPlugins] =
    sortUserPlugins(config.worker?.plugins as Plugin[])
  const workerResolved: ResolvedConfig = { ...resolved, isWorker: true }
  resolved.worker.plugins = await resolvePlugins(
    workerResolved,
    workerPrePlugins,
    workerNormalPlugins,
    workerPostPlugins
  )
  // call configResolved worker plugins hooks
  await Promise.all(
    resolved.worker.plugins.map((p) => p.configResolved?.(workerResolved))
  )
  //resolvePlugins 位于 ./plugins 目录,下一章节分析
  ;(resolved.plugins as Plugin[]) = await resolvePlugins(
    resolved,
    prePlugins,
    normalPlugins,
    postPlugins
  )


  return resolved
}

最终解析出的 resolved 大概如下:

{
  base:'/',
  // 项目的根目录, 一般是项目目录
  root:'……',
  // 构建缓存的文件夹, 默认情况下是项目目录中 node_modules 下的.vite文件
  cacheDir:'……/node_modules/.vite',
  // 命令模式是 serve 还是 build
  command:'serve',
  // 环境 development、 production,与 process.env.NODE_ENV 一致
  mode:'development',  
  // vite 配置文件位置
  configFile:'……/vite.config.js',
  // server 需要运行的 public 文件夹
  publicDir:'……/public',
  configFileDependencies:['vite.config.js'],
  // 这个就是用户自定义使用 vue 插件设置的配置属性,在 vue 插件中被使用
  define:{
    __VUE_OPTIONS_API__: true, 
    __VUE_PROD_DEVTOOLS__: false
  },
  env:{
    BASE_URL: '/', 
    MODE: 'development', 
    DEV: true, 
    PROD: false
  },
  esbuild:{include: /\\.ts$/},
  // createServer 中传入命令行参数, 都为 undefined
  inlineConfig:{root: undefined, base: undefined, mode: undefined, configFile: undefined, logLevel: undefined, …},
  isProduction: false,
  optimizeDeps:{esbuildOptions: {…}}
  // 插件集合,结果为上面介绍的插件列表
  plugins:[],
  ……
}
<pre data-line="0"><code class="language-typescript" language=typescript><span class="code-block">//server 只在开发环境使用,默认只需关注development const config = await resolveConfig(inlineConfig, 'serve', 'development')</span></code></pre> <p data-line="4">源码位置:<code>packages\vite\src\node\config.ts</code></p> <p data-line="6">核心代码如下:</p> <pre data-line="7"><code class="language-typescript" language=typescript><span class="code-block">export async function resolveConfig( inlineConfig: InlineConfig, command: 'build' | 'serve', defaultMode = 'development' ): Promise&lt;ResolvedConfig&gt; { let config = inlineConfig let configFileDependencies: string[] = [] let mode = inlineConfig.mode || defaultMode let { configFile } = config //默认情况下,执行 vite dev,configFile 为 undefined //执行 vite dev --config vite.congfig.ts 时, configFile为vite.congfig.ts // configFile!==false 总是为true if (configFile !== false) { //加载本地的配置文件,可以是命令行或自动从根目录查找 const loadResult = await loadConfigFromFile( configEnv, configFile, config.root, config.logLevel ) if (loadResult) { config = mergeConfig(loadResult.config, config) configFile = loadResult.path configFileDependencies = loadResult.dependencies } } // user config may provide an alternative mode. But --mode has a higher priority mode = inlineConfig.mode || config.mode || mode configEnv.mode = mode // resolve plugins // 解析配置文件里面的插件 const rawUserPlugins = (config.plugins || []).flat(Infinity).filter((p) =&gt; { if (!p) { return false } else if (!p.apply) { return true } else if (typeof p.apply === 'function') { return p.apply({ ...config, mode }, configEnv) } else { return p.apply === command } }) as Plugin[] const [prePlugins, normalPlugins, postPlugins] = sortUserPlugins(rawUserPlugins) // resolve worker const resolvedWorkerOptions: ResolveWorkerOptions = { format: config.worker?.format || 'iife', plugins: [], rollupOptions: config.worker?.rollupOptions || {} } // run config hooks const userPlugins = [...prePlugins, ...normalPlugins, ...postPlugins] for (const p of userPlugins) { if (p.config) { const res = await p.config(config, configEnv) if (res) { config = mergeConfig(config, res) } } } // resolve root const resolvedRoot = normalizePath( config.root ? path.resolve(config.root) : process.cwd() ) const clientAlias = [ { find: /^[\/]?@vite\/env/, replacement: () =&gt; ENV_ENTRY }, { find: /^[\/]?@vite\/client/, replacement: () =&gt; CLIENT_ENTRY } ] // resolve alias with internal client alias const resolvedAlias = normalizeAlias( mergeAlias( // @ts-ignore because @rollup/plugin-alias' type doesn't allow function // replacement, but its implementation does work with function values. clientAlias, config.resolve?.alias || config.alias || [] ) ) const resolveOptions: ResolvedConfig['resolve'] = { dedupe: config.dedupe, ...config.resolve, alias: resolvedAlias } // load .env files const envDir = config.envDir ? normalizePath(path.resolve(resolvedRoot, config.envDir)) : resolvedRoot const userEnv = inlineConfig.envFile !== false &amp;&amp; loadEnv(mode, envDir, resolveEnvPrefix(config)) // Note it is possible for user to have a custom mode, e.g. `staging` where // production-like behavior is expected. This is indicated by NODE_ENV=production // loaded from `.staging.env` and set by us as VITE_USER_NODE_ENV const isProduction = (process.env.VITE_USER_NODE_ENV || mode) === 'production' if (isProduction) { // in case default mode was not production and is overwritten process.env.NODE_ENV = 'production' } // resolve public base url const BASE_URL = resolveBaseUrl(config.base, command === 'build', logger) const resolvedBuildOptions = resolveBuildOptions(config.build) // resolve cache directory const pkgPath = lookupFile(resolvedRoot, [`package.json`], { pathOnly: true }) const cacheDir = config.cacheDir ? path.resolve(resolvedRoot, config.cacheDir) : pkgPath ? path.join(path.dirname(pkgPath), `node_modules/.vite`) : path.join(resolvedRoot, `.vite`) const assetsFilter = config.assetsInclude ? createFilter(config.assetsInclude) : () =&gt; false const { publicDir } = config const resolvedPublicDir = publicDir !== false &amp;&amp; publicDir !== '' ? path.resolve( resolvedRoot, typeof publicDir === 'string' ? publicDir : 'public' ) : '' const server = resolveServerOptions(resolvedRoot, config.server, logger) const optimizeDeps = config.optimizeDeps || {} const resolved: ResolvedConfig = { ...config, configFile: configFile ? normalizePath(configFile) : undefined, configFileDependencies: configFileDependencies.map((name) =&gt; normalizePath(path.resolve(name)) ), inlineConfig, root: resolvedRoot, base: BASE_URL, resolve: resolveOptions, publicDir: resolvedPublicDir, cacheDir, command, mode, isWorker: false, isProduction, plugins: userPlugins, server, build: resolvedBuildOptions, preview: resolvePreviewOptions(config.preview, server), env: { ...userEnv, BASE_URL, MODE: mode, DEV: !isProduction, PROD: isProduction }, assetsInclude(file: string) { return DEFAULT_ASSETS_RE.test(file) || assetsFilter(file) }, logger, packageCache: new Map(), createResolver, optimizeDeps: { ...optimizeDeps, esbuildOptions: { keepNames: optimizeDeps.keepNames, preserveSymlinks: config.resolve?.preserveSymlinks, ...optimizeDeps.esbuildOptions } }, worker: resolvedWorkerOptions } // flat config.worker.plugin const [workerPrePlugins, workerNormalPlugins, workerPostPlugins] = sortUserPlugins(config.worker?.plugins as Plugin[]) const workerResolved: ResolvedConfig = { ...resolved, isWorker: true } resolved.worker.plugins = await resolvePlugins( workerResolved, workerPrePlugins, workerNormalPlugins, workerPostPlugins ) // call configResolved worker plugins hooks await Promise.all( resolved.worker.plugins.map((p) =&gt; p.configResolved?.(workerResolved)) ) //resolvePlugins 位于 ./plugins 目录,下一章节分析 ;(resolved.plugins as Plugin[]) = await resolvePlugins( resolved, prePlugins, normalPlugins, postPlugins ) return resolved }</span></code></pre> <p data-line="222">最终解析出的 resolved 大概如下:</p> <pre data-line="223"><code class="language-typescript" language=typescript><span class="code-block">{ base:'/', // 项目的根目录, 一般是项目目录 root:'……', // 构建缓存的文件夹, 默认情况下是项目目录中 node_modules 下的.vite文件 cacheDir:'……/node_modules/.vite', // 命令模式是 serve 还是 build command:'serve', // 环境 development、 production,与 process.env.NODE_ENV 一致 mode:'development', // vite 配置文件位置 configFile:'……/vite.config.js', // server 需要运行的 public 文件夹 publicDir:'……/public', configFileDependencies:['vite.config.js'], // 这个就是用户自定义使用 vue 插件设置的配置属性,在 vue 插件中被使用 define:{ __VUE_OPTIONS_API__: true, __VUE_PROD_DEVTOOLS__: false }, env:{ BASE_URL: '/', MODE: 'development', DEV: true, PROD: false }, esbuild:{include: /\\.ts$/}, // createServer 中传入命令行参数, 都为 undefined inlineConfig:{root: undefined, base: undefined, mode: undefined, configFile: undefined, logLevel: undefined, …}, isProduction: false, optimizeDeps:{esbuildOptions: {…}} // 插件集合,结果为上面介绍的插件列表 plugins:[], …… }</span></code></pre>