likes
comments
collection
share

vite源码之配置文件

作者站长头像
站长
· 阅读数 13

前言

配置文件在前端是非常常见的,如 webpack/rollup 等打包工具,又或者是 babel/postcss/ts 等编译工具都有自己的配置文件。它们有的是js文件、有的是json文件。而vite作为新一代的前端工具,打包的效率与开发环境的体验自不必说,它在配置文件这个领域也与之前的工具有所区别的。

vite配置文件的优点

  1. 可以使用ts编写

    vite的配置文件兼容了多种格式,如:js mjs cjs ts mts cts等,比较常用的就是 jsts了,并且即使你的项目并没有安装 typescript,vite配置文件依旧是可以使用ts文件,那这是如何做到的呢?我们后面再做分析。

  2. 使用 defineConfig 来得到类型提示

    当配置非常多,同时配置属性名比较长时,能够得到类型提示的优势就非常大了。类型提示能够使你不必每次都去查阅官方文档,同时也避免了你在书写过程中把配置写错的尴尬。

vite对ts配置文件的处理

对于配置文件的读取其实很简单了,使用 await import 或者 require 即可。但是如何处理ts配置文件呢?await import 或者 require都是仅支持js文件的。我读了一下vite的源码,是通过esbuild将ts代码编译成功js后再输出到一个临时文件中,最后通过 dynamicImport 去读取的,代码大概如下:

async function resolveConfigFiles(configFiles: string[]) {
  // 获取配置文件的完整路径
  const configFilePath = await getConfigFilePath(configFiles)
  
  if (!configFilePath) {
    render.noConfigurationProvide()
    return
  }
    
  const buildResult = await build({
    entryPoints: [configFilePath],
    bundle: true,
    platform: 'node',
    target: ['node14', 'node16'],
    format: await getModuleFormat(configFilePath), // 获取文件是 esm 还是 cjs
    outfile: 'out.js',
    write: false, // 设置为false时buildResult才会有outputFiles
    loader: {
      '.ts': 'ts' // 处理ts文件
    }
  })
  
  const code = buildResult.outputFiles?.[0]?.text || ''

  try {
    await access(TMP_PATH)
  } catch(e) {
    await mkdir(TMP_PATH)
  }
  
  // 将编译成功js的配置文件写入到临时的文件中
  await writeFile(
    join(TMP_PATH, TMP_CONFIG_FILE),
    code,
    'utf8'
  )
  
  // 通过dynamicImport去解析配置,最后得到具体配置对象
  const mod = await import(`file://${join(TMP_PATH, TMP_CONFIG_FILE)}`)
  
  return mod.default.default
}

以上代码并非vite源码,而是我读了vite源码之后用在了自己写的工具中,vite的大致核心逻辑其实也是这样的。

如何获得类型提示

获得类型提示的关键就是 defineConfig 函数,而该函数本身是没有逻辑的,只是将输入的配置再return出去。代码如下:

export function defineConfig(config: UserConfiguration): UserConfiguration {
  return config;
}

主要是利用了函数来得到类型提示,而通过 dynamicImport 之后的结果其实是函数的运行结果,也就是传入的配置。

结语

vite作为新一代的前端工具,虽然现在还不如 webpack/rollup 这些工具成熟。但其优势也非常明显,打包速度有了esbuild的加持就不必多说了,它在很多细节的处理上也让人焕然一新,期待它慢慢的成长吧!