Skip to content

Commit 48f59ce

Browse files
authored
feat: use rolldown for config loader (#69)
1 parent 4753f60 commit 48f59ce

File tree

2 files changed

+108
-78
lines changed

2 files changed

+108
-78
lines changed

docs/_data/blog.data.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ interface Post {
1010
}
1111

1212
declare const data: Post[]
13-
export { data }
13+
export { type data }
1414

1515
export default createContentLoader('blog/*.md', {
1616
// excerpt: true,

packages/vite/src/node/config.ts

Lines changed: 107 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import { performance } from 'node:perf_hooks'
77
import { builtinModules, createRequire } from 'node:module'
88
import colors from 'picocolors'
99
import type { Alias, AliasOptions } from 'dep-types/alias'
10-
import { build } from 'esbuild'
11-
import type { RollupOptions } from 'rolldown'
10+
import { rolldown } from 'rolldown'
11+
import type { OutputChunk, RollupOptions } from 'rolldown'
1212
import picomatch from 'picomatch'
1313
import type { AnymatchFn } from '../types/anymatch'
1414
import { withTrailingSlash } from '../shared/utils'
@@ -1858,73 +1858,67 @@ async function bundleConfigFile(
18581858
const dirnameVarName = '__vite_injected_original_dirname'
18591859
const filenameVarName = '__vite_injected_original_filename'
18601860
const importMetaUrlVarName = '__vite_injected_original_import_meta_url'
1861-
const result = await build({
1862-
absWorkingDir: process.cwd(),
1863-
entryPoints: [fileName],
1864-
write: false,
1865-
target: [`node${process.versions.node}`],
1861+
1862+
const bundle = await rolldown({
1863+
input: fileName,
1864+
// target: [`node${process.versions.node}`],
18661865
platform: 'node',
1867-
bundle: true,
1868-
format: isESM ? 'esm' : 'cjs',
1869-
mainFields: ['main'],
1870-
sourcemap: 'inline',
1871-
metafile: true,
1866+
resolve: {
1867+
mainFields: ['main'],
1868+
},
18721869
define: {
18731870
__dirname: dirnameVarName,
18741871
__filename: filenameVarName,
18751872
'import.meta.url': importMetaUrlVarName,
18761873
'import.meta.dirname': dirnameVarName,
18771874
'import.meta.filename': filenameVarName,
18781875
},
1876+
// disable treeshake to include files that is not sideeffectful to `moduleIds`
1877+
treeshake: false,
18791878
plugins: [
1880-
{
1881-
name: 'externalize-deps',
1882-
setup(build) {
1883-
const packageCache = new Map()
1884-
const resolveByViteResolver = (
1885-
id: string,
1886-
importer: string,
1887-
isRequire: boolean,
1888-
) => {
1889-
return tryNodeResolve(id, importer, {
1890-
root: path.dirname(fileName),
1891-
isBuild: true,
1892-
isProduction: true,
1893-
preferRelative: false,
1894-
tryIndex: true,
1895-
mainFields: [],
1896-
conditions: [
1897-
'node',
1898-
...(isModuleSyncConditionEnabled ? ['module-sync'] : []),
1899-
],
1900-
externalConditions: [],
1901-
external: [],
1902-
noExternal: [],
1903-
dedupe: [],
1904-
extensions: configDefaults.resolve.extensions,
1905-
preserveSymlinks: false,
1906-
packageCache,
1907-
isRequire,
1908-
})?.id
1909-
}
1910-
1911-
// externalize bare imports
1912-
build.onResolve(
1913-
{ filter: /^[^.].*/ },
1914-
async ({ path: id, importer, kind }) => {
1915-
if (
1916-
kind === 'entry-point' ||
1917-
path.isAbsolute(id) ||
1918-
isNodeBuiltin(id)
1919-
) {
1879+
(() => {
1880+
const packageCache = new Map()
1881+
const resolveByViteResolver = (
1882+
id: string,
1883+
importer: string,
1884+
isRequire: boolean,
1885+
) => {
1886+
return tryNodeResolve(id, importer, {
1887+
root: path.dirname(fileName),
1888+
isBuild: true,
1889+
isProduction: true,
1890+
preferRelative: false,
1891+
tryIndex: true,
1892+
mainFields: [],
1893+
conditions: [
1894+
'node',
1895+
...(isModuleSyncConditionEnabled ? ['module-sync'] : []),
1896+
],
1897+
externalConditions: [],
1898+
external: [],
1899+
noExternal: [],
1900+
dedupe: [],
1901+
extensions: configDefaults.resolve.extensions,
1902+
preserveSymlinks: false,
1903+
packageCache,
1904+
isRequire,
1905+
})?.id
1906+
}
1907+
1908+
return {
1909+
name: 'externalize-deps',
1910+
resolveId: {
1911+
filter: { id: /^[^.].*/ },
1912+
async handler(id, importer, { kind }) {
1913+
if (!importer || path.isAbsolute(id) || isNodeBuiltin(id)) {
19201914
return
19211915
}
19221916

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

19301924
const isImport = isESM || kind === 'dynamic-import'
@@ -1951,44 +1945,80 @@ async function bundleConfigFile(
19511945
}
19521946
throw e
19531947
}
1948+
if (!idFsPath) return
1949+
// always no-externalize json files as rolldown does not support import attributes
1950+
if (idFsPath.endsWith('.json')) {
1951+
return idFsPath
1952+
}
1953+
19541954
if (idFsPath && isImport) {
19551955
idFsPath = pathToFileURL(idFsPath).href
19561956
}
1957-
return {
1958-
path: idFsPath,
1959-
external: true,
1960-
}
1957+
return { id: idFsPath, external: true }
19611958
},
1962-
)
1963-
},
1964-
},
1959+
},
1960+
}
1961+
})(),
19651962
{
19661963
name: 'inject-file-scope-variables',
1967-
setup(build) {
1968-
build.onLoad({ filter: /\.[cm]?[jt]s$/ }, async (args) => {
1969-
const contents = await fsp.readFile(args.path, 'utf-8')
1964+
transform: {
1965+
filter: { id: /\.[cm]?[jt]s$/ },
1966+
async handler(code, id) {
19701967
const injectValues =
1971-
`const ${dirnameVarName} = ${JSON.stringify(
1972-
path.dirname(args.path),
1973-
)};` +
1974-
`const ${filenameVarName} = ${JSON.stringify(args.path)};` +
1968+
`const ${dirnameVarName} = ${JSON.stringify(path.dirname(id))};` +
1969+
`const ${filenameVarName} = ${JSON.stringify(id)};` +
19751970
`const ${importMetaUrlVarName} = ${JSON.stringify(
1976-
pathToFileURL(args.path).href,
1971+
pathToFileURL(id).href,
19771972
)};`
1978-
1979-
return {
1980-
loader: args.path.endsWith('ts') ? 'ts' : 'js',
1981-
contents: injectValues + contents,
1982-
}
1983-
})
1973+
return { code: injectValues + code, map: null }
1974+
},
19841975
},
19851976
},
19861977
],
19871978
})
1988-
const { text } = result.outputFiles[0]
1979+
const result = await bundle.generate({
1980+
format: isESM ? 'esm' : 'cjs',
1981+
sourcemap: 'inline',
1982+
})
1983+
await bundle.close()
1984+
1985+
const entryChunk = result.output.find(
1986+
(chunk): chunk is OutputChunk => chunk.type === 'chunk' && chunk.isEntry,
1987+
)!
1988+
const bundleChunks = Object.fromEntries(
1989+
result.output.flatMap((c) => (c.type === 'chunk' ? [[c.fileName, c]] : [])),
1990+
)
1991+
1992+
const allModules = new Set<string>()
1993+
collectAllModules(bundleChunks, entryChunk.fileName, allModules)
1994+
allModules.delete(fileName)
1995+
19891996
return {
1990-
code: text,
1991-
dependencies: result.metafile ? Object.keys(result.metafile.inputs) : [],
1997+
code: entryChunk.code,
1998+
dependencies: [...allModules],
1999+
}
2000+
}
2001+
2002+
function collectAllModules(
2003+
bundle: Record<string, OutputChunk>,
2004+
fileName: string,
2005+
allModules: Set<string>,
2006+
analyzedModules = new Set<string>(),
2007+
) {
2008+
if (analyzedModules.has(fileName)) return
2009+
analyzedModules.add(fileName)
2010+
2011+
const chunk = bundle[fileName]!
2012+
for (const mod of chunk.moduleIds) {
2013+
allModules.add(mod)
2014+
}
2015+
for (const i of chunk.imports) {
2016+
analyzedModules.add(i)
2017+
collectAllModules(bundle, i, allModules, analyzedModules)
2018+
}
2019+
for (const i of chunk.dynamicImports) {
2020+
analyzedModules.add(i)
2021+
collectAllModules(bundle, i, allModules, analyzedModules)
19922022
}
19932023
}
19942024

0 commit comments

Comments
 (0)