Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use rolldown for config loader #69

Merged
merged 2 commits into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading