Skip to content

Commit

Permalink
feat: use rolldown for config loader (#69)
Browse files Browse the repository at this point in the history
  • Loading branch information
sapphi-red authored Nov 29, 2024
1 parent 4753f60 commit 48f59ce
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 78 deletions.
2 changes: 1 addition & 1 deletion docs/_data/blog.data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface Post {
}

declare const data: Post[]
export { data }
export { type data }

export default createContentLoader('blog/*.md', {
// excerpt: true,
Expand Down
184 changes: 107 additions & 77 deletions packages/vite/src/node/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { performance } from 'node:perf_hooks'
import { builtinModules, createRequire } from 'node:module'
import colors from 'picocolors'
import type { Alias, AliasOptions } from 'dep-types/alias'
import { build } from 'esbuild'
import type { RollupOptions } from 'rolldown'
import { rolldown } from 'rolldown'
import type { OutputChunk, RollupOptions } from 'rolldown'
import picomatch from 'picomatch'
import type { AnymatchFn } from '../types/anymatch'
import { withTrailingSlash } from '../shared/utils'
Expand Down Expand Up @@ -1858,73 +1858,67 @@ async function bundleConfigFile(
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: [fileName],
write: false,
target: [`node${process.versions.node}`],

const bundle = await rolldown({
input: fileName,
// target: [`node${process.versions.node}`],
platform: 'node',
bundle: true,
format: isESM ? 'esm' : 'cjs',
mainFields: ['main'],
sourcemap: 'inline',
metafile: true,
resolve: {
mainFields: ['main'],
},
define: {
__dirname: dirnameVarName,
__filename: filenameVarName,
'import.meta.url': importMetaUrlVarName,
'import.meta.dirname': dirnameVarName,
'import.meta.filename': filenameVarName,
},
// disable treeshake to include files that is not sideeffectful to `moduleIds`
treeshake: false,
plugins: [
{
name: 'externalize-deps',
setup(build) {
const packageCache = new Map()
const resolveByViteResolver = (
id: string,
importer: string,
isRequire: boolean,
) => {
return tryNodeResolve(id, importer, {
root: path.dirname(fileName),
isBuild: true,
isProduction: true,
preferRelative: false,
tryIndex: true,
mainFields: [],
conditions: [
'node',
...(isModuleSyncConditionEnabled ? ['module-sync'] : []),
],
externalConditions: [],
external: [],
noExternal: [],
dedupe: [],
extensions: configDefaults.resolve.extensions,
preserveSymlinks: false,
packageCache,
isRequire,
})?.id
}

// externalize bare imports
build.onResolve(
{ filter: /^[^.].*/ },
async ({ path: id, importer, kind }) => {
if (
kind === 'entry-point' ||
path.isAbsolute(id) ||
isNodeBuiltin(id)
) {
(() => {
const packageCache = new Map()
const resolveByViteResolver = (
id: string,
importer: string,
isRequire: boolean,
) => {
return tryNodeResolve(id, importer, {
root: path.dirname(fileName),
isBuild: true,
isProduction: true,
preferRelative: false,
tryIndex: true,
mainFields: [],
conditions: [
'node',
...(isModuleSyncConditionEnabled ? ['module-sync'] : []),
],
externalConditions: [],
external: [],
noExternal: [],
dedupe: [],
extensions: configDefaults.resolve.extensions,
preserveSymlinks: false,
packageCache,
isRequire,
})?.id
}

return {
name: 'externalize-deps',
resolveId: {
filter: { id: /^[^.].*/ },
async handler(id, importer, { kind }) {
if (!importer || path.isAbsolute(id) || isNodeBuiltin(id)) {
return
}

// With the `isNodeBuiltin` check above, this check captures if the builtin is a
// non-node built-in, which esbuild doesn't know how to handle. In that case, we
// externalize it so the non-node runtime handles it instead.
if (isBuiltin(id)) {
return { external: true }
return { id, external: true }
}

const isImport = isESM || kind === 'dynamic-import'
Expand All @@ -1951,44 +1945,80 @@ async function bundleConfigFile(
}
throw e
}
if (!idFsPath) return
// always no-externalize json files as rolldown does not support import attributes
if (idFsPath.endsWith('.json')) {
return idFsPath
}

if (idFsPath && isImport) {
idFsPath = pathToFileURL(idFsPath).href
}
return {
path: idFsPath,
external: true,
}
return { id: idFsPath, external: true }
},
)
},
},
},
}
})(),
{
name: 'inject-file-scope-variables',
setup(build) {
build.onLoad({ filter: /\.[cm]?[jt]s$/ }, async (args) => {
const contents = await fsp.readFile(args.path, 'utf-8')
transform: {
filter: { id: /\.[cm]?[jt]s$/ },
async handler(code, id) {
const injectValues =
`const ${dirnameVarName} = ${JSON.stringify(
path.dirname(args.path),
)};` +
`const ${filenameVarName} = ${JSON.stringify(args.path)};` +
`const ${dirnameVarName} = ${JSON.stringify(path.dirname(id))};` +
`const ${filenameVarName} = ${JSON.stringify(id)};` +
`const ${importMetaUrlVarName} = ${JSON.stringify(
pathToFileURL(args.path).href,
pathToFileURL(id).href,
)};`

return {
loader: args.path.endsWith('ts') ? 'ts' : 'js',
contents: injectValues + contents,
}
})
return { code: injectValues + code, map: null }
},
},
},
],
})
const { text } = result.outputFiles[0]
const result = await bundle.generate({
format: isESM ? 'esm' : 'cjs',
sourcemap: 'inline',
})
await bundle.close()

const entryChunk = result.output.find(
(chunk): chunk is OutputChunk => chunk.type === 'chunk' && chunk.isEntry,
)!
const bundleChunks = Object.fromEntries(
result.output.flatMap((c) => (c.type === 'chunk' ? [[c.fileName, c]] : [])),
)

const allModules = new Set<string>()
collectAllModules(bundleChunks, entryChunk.fileName, allModules)
allModules.delete(fileName)

return {
code: text,
dependencies: result.metafile ? Object.keys(result.metafile.inputs) : [],
code: entryChunk.code,
dependencies: [...allModules],
}
}

function collectAllModules(
bundle: Record<string, OutputChunk>,
fileName: string,
allModules: Set<string>,
analyzedModules = new Set<string>(),
) {
if (analyzedModules.has(fileName)) return
analyzedModules.add(fileName)

const chunk = bundle[fileName]!
for (const mod of chunk.moduleIds) {
allModules.add(mod)
}
for (const i of chunk.imports) {
analyzedModules.add(i)
collectAllModules(bundle, i, allModules, analyzedModules)
}
for (const i of chunk.dynamicImports) {
analyzedModules.add(i)
collectAllModules(bundle, i, allModules, analyzedModules)
}
}

Expand Down

0 comments on commit 48f59ce

Please sign in to comment.