Skip to content

Commit 72d6bcf

Browse files
committed
feat: use rolldown to bundle config
1 parent ee0b21a commit 72d6bcf

File tree

2 files changed

+111
-81
lines changed

2 files changed

+111
-81
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: 110 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ import colors from 'picocolors'
1010
import type { Alias, AliasOptions } from 'dep-types/alias'
1111
import type { RollupOptions } from 'rollup'
1212
import picomatch from 'picomatch'
13-
import { build } from 'esbuild'
14-
import type { RolldownOptions } from 'rolldown'
13+
import { type OutputChunk, type RolldownOptions, rolldown } from 'rolldown'
1514
import type { AnymatchFn } from '../types/anymatch'
1615
import { withTrailingSlash } from '../shared/utils'
1716
import {
@@ -1970,76 +1969,68 @@ async function bundleConfigFile(
19701969
const dirnameVarName = '__vite_injected_original_dirname'
19711970
const filenameVarName = '__vite_injected_original_filename'
19721971
const importMetaUrlVarName = '__vite_injected_original_import_meta_url'
1973-
const result = await build({
1974-
absWorkingDir: process.cwd(),
1975-
entryPoints: [fileName],
1976-
write: false,
1977-
target: [`node${process.versions.node}`],
1972+
1973+
const bundle = await rolldown({
1974+
input: fileName,
1975+
// target: [`node${process.versions.node}`],
19781976
platform: 'node',
1979-
bundle: true,
1980-
format: isESM ? 'esm' : 'cjs',
1981-
mainFields: ['main'],
1982-
sourcemap: 'inline',
1983-
// the last slash is needed to make the path correct
1984-
sourceRoot: path.dirname(fileName) + path.sep,
1985-
metafile: true,
1977+
resolve: {
1978+
mainFields: ['main'],
1979+
},
19861980
define: {
19871981
__dirname: dirnameVarName,
19881982
__filename: filenameVarName,
19891983
'import.meta.url': importMetaUrlVarName,
19901984
'import.meta.dirname': dirnameVarName,
19911985
'import.meta.filename': filenameVarName,
19921986
},
1987+
// disable treeshake to include files that is not sideeffectful to `moduleIds`
1988+
treeshake: false,
19931989
plugins: [
1994-
{
1995-
name: 'externalize-deps',
1996-
setup(build) {
1997-
const packageCache = new Map()
1998-
const resolveByViteResolver = (
1999-
id: string,
2000-
importer: string,
2001-
isRequire: boolean,
2002-
) => {
2003-
return tryNodeResolve(id, importer, {
2004-
root: path.dirname(fileName),
2005-
isBuild: true,
2006-
isProduction: true,
2007-
preferRelative: false,
2008-
tryIndex: true,
2009-
mainFields: [],
2010-
conditions: [
2011-
'node',
2012-
...(isModuleSyncConditionEnabled ? ['module-sync'] : []),
2013-
],
2014-
externalConditions: [],
2015-
external: [],
2016-
noExternal: [],
2017-
dedupe: [],
2018-
extensions: configDefaults.resolve.extensions,
2019-
preserveSymlinks: false,
2020-
packageCache,
2021-
isRequire,
2022-
builtins: nodeLikeBuiltins,
2023-
})?.id
2024-
}
2025-
2026-
// externalize bare imports
2027-
build.onResolve(
2028-
{ filter: /^[^.#].*/ },
2029-
async ({ path: id, importer, kind }) => {
2030-
if (
2031-
kind === 'entry-point' ||
2032-
path.isAbsolute(id) ||
2033-
isNodeBuiltin(id)
2034-
) {
1990+
(() => {
1991+
const packageCache = new Map()
1992+
const resolveByViteResolver = (
1993+
id: string,
1994+
importer: string,
1995+
isRequire: boolean,
1996+
) => {
1997+
return tryNodeResolve(id, importer, {
1998+
root: path.dirname(fileName),
1999+
isBuild: true,
2000+
isProduction: true,
2001+
preferRelative: false,
2002+
tryIndex: true,
2003+
mainFields: [],
2004+
conditions: [
2005+
'node',
2006+
...(isModuleSyncConditionEnabled ? ['module-sync'] : []),
2007+
],
2008+
externalConditions: [],
2009+
external: [],
2010+
noExternal: [],
2011+
dedupe: [],
2012+
extensions: configDefaults.resolve.extensions,
2013+
preserveSymlinks: false,
2014+
packageCache,
2015+
isRequire,
2016+
builtins: nodeLikeBuiltins,
2017+
})?.id
2018+
}
2019+
2020+
return {
2021+
name: 'externalize-deps',
2022+
resolveId: {
2023+
filter: { id: /^[^.#].*/ },
2024+
async handler(id, importer, { kind }) {
2025+
if (!importer || path.isAbsolute(id) || isNodeBuiltin(id)) {
20352026
return
20362027
}
20372028

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

20452036
const isImport = isESM || kind === 'dynamic-import'
@@ -2066,44 +2057,83 @@ async function bundleConfigFile(
20662057
}
20672058
throw e
20682059
}
2060+
if (!idFsPath) return
2061+
// always no-externalize json files as rolldown does not support import attributes
2062+
if (idFsPath.endsWith('.json')) {
2063+
return idFsPath
2064+
}
2065+
20692066
if (idFsPath && isImport) {
20702067
idFsPath = pathToFileURL(idFsPath).href
20712068
}
2072-
return {
2073-
path: idFsPath,
2074-
external: true,
2075-
}
2069+
return { id: idFsPath, external: true }
20762070
},
2077-
)
2078-
},
2079-
},
2071+
},
2072+
}
2073+
})(),
20802074
{
20812075
name: 'inject-file-scope-variables',
2082-
setup(build) {
2083-
build.onLoad({ filter: /\.[cm]?[jt]s$/ }, async (args) => {
2084-
const contents = await fsp.readFile(args.path, 'utf-8')
2076+
transform: {
2077+
filter: { id: /\.[cm]?[jt]s$/ },
2078+
async handler(code, id) {
20852079
const injectValues =
2086-
`const ${dirnameVarName} = ${JSON.stringify(
2087-
path.dirname(args.path),
2088-
)};` +
2089-
`const ${filenameVarName} = ${JSON.stringify(args.path)};` +
2080+
`const ${dirnameVarName} = ${JSON.stringify(path.dirname(id))};` +
2081+
`const ${filenameVarName} = ${JSON.stringify(id)};` +
20902082
`const ${importMetaUrlVarName} = ${JSON.stringify(
2091-
pathToFileURL(args.path).href,
2083+
pathToFileURL(id).href,
20922084
)};`
2093-
2094-
return {
2095-
loader: args.path.endsWith('ts') ? 'ts' : 'js',
2096-
contents: injectValues + contents,
2097-
}
2098-
})
2085+
return { code: injectValues + code, map: null }
2086+
},
20992087
},
21002088
},
21012089
],
21022090
})
2103-
const { text } = result.outputFiles[0]
2091+
const result = await bundle.generate({
2092+
format: isESM ? 'esm' : 'cjs',
2093+
sourcemap: 'inline',
2094+
sourcemapPathTransform(relative) {
2095+
return path.resolve(fileName, relative)
2096+
},
2097+
})
2098+
await bundle.close()
2099+
2100+
const entryChunk = result.output.find(
2101+
(chunk): chunk is OutputChunk => chunk.type === 'chunk' && chunk.isEntry,
2102+
)!
2103+
const bundleChunks = Object.fromEntries(
2104+
result.output.flatMap((c) => (c.type === 'chunk' ? [[c.fileName, c]] : [])),
2105+
)
2106+
2107+
const allModules = new Set<string>()
2108+
collectAllModules(bundleChunks, entryChunk.fileName, allModules)
2109+
allModules.delete(fileName)
2110+
21042111
return {
2105-
code: text,
2106-
dependencies: Object.keys(result.metafile.inputs),
2112+
code: entryChunk.code,
2113+
dependencies: [...allModules],
2114+
}
2115+
}
2116+
2117+
function collectAllModules(
2118+
bundle: Record<string, OutputChunk>,
2119+
fileName: string,
2120+
allModules: Set<string>,
2121+
analyzedModules = new Set<string>(),
2122+
) {
2123+
if (analyzedModules.has(fileName)) return
2124+
analyzedModules.add(fileName)
2125+
2126+
const chunk = bundle[fileName]!
2127+
for (const mod of chunk.moduleIds) {
2128+
allModules.add(mod)
2129+
}
2130+
for (const i of chunk.imports) {
2131+
analyzedModules.add(i)
2132+
collectAllModules(bundle, i, allModules, analyzedModules)
2133+
}
2134+
for (const i of chunk.dynamicImports) {
2135+
analyzedModules.add(i)
2136+
collectAllModules(bundle, i, allModules, analyzedModules)
21072137
}
21082138
}
21092139

0 commit comments

Comments
 (0)