2024-07-08 02:35:47 +08:00

90 lines
2.6 KiB
TypeScript

import { promises as fsp } from 'node:fs'
import path from 'node:path'
import process from 'node:process'
import { pathToFileURL } from 'node:url'
import { build } from 'esbuild'
import { importFileDefault } from 'vuepress/utils'
import type { ThemeConfig } from '../../shared/theme-data.js'
import { hash } from '../utils/index.js'
export async function compiler(configPath?: string,
): Promise<{
config: ThemeConfig
dependencies: string[]
}> {
if (!configPath) {
return { config: {}, dependencies: [] }
}
const dirnameVarName = '__vite_injected_original_dirname'
const filenameVarName = '__vite_injected_original_filename'
const importMetaUrlVarName = '__vite_injected_original_import_meta_url'
const result = await build({
absWorkingDir: process.cwd(),
entryPoints: [configPath],
outfile: 'out.js',
write: false,
target: ['node18'],
platform: 'node',
bundle: true,
format: 'esm',
sourcemap: 'inline',
metafile: true,
define: {
'__dirname': dirnameVarName,
'__filename': filenameVarName,
'import.meta.url': importMetaUrlVarName,
},
plugins: [
{
name: 'externalize-deps',
setup(build) {
build.onResolve({ filter: /.*/ }, ({ path: id }) => {
// externalize bare imports
if (id[0] !== '.' && !path.isAbsolute(id)) {
return { external: true }
}
return null
})
},
},
{
name: 'inject-file-scope-variables',
setup(build) {
build.onLoad({ filter: /\.[cm]?[jt]s$/ }, async (args) => {
const contents = await fsp.readFile(args.path, 'utf8')
const injectValues
= `const ${dirnameVarName} = ${JSON.stringify(
path.dirname(args.path),
)};`
+ `const ${filenameVarName} = ${JSON.stringify(args.path)};`
+ `const ${importMetaUrlVarName} = ${JSON.stringify(
pathToFileURL(args.path).href,
)};`
return {
loader: args.path.endsWith('ts') ? 'ts' : 'js',
contents: injectValues + contents,
}
})
},
},
],
})
const { text } = result.outputFiles[0]
const tempFilePath = `${configPath}.${hash(text)}.mjs`
let config: ThemeConfig
try {
await fsp.writeFile(tempFilePath, text)
config = await importFileDefault(tempFilePath)
}
finally {
await fsp.rm(tempFilePath)
}
return {
config,
dependencies: Object.keys(result.metafile?.inputs ?? {}),
}
}