Skip to content

Commit

Permalink
perf: cache esm file lookup
Browse files Browse the repository at this point in the history
  • Loading branch information
bluwy committed Oct 4, 2023
1 parent a396eed commit b868033
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 35 deletions.
18 changes: 5 additions & 13 deletions packages/vite/src/node/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1074,18 +1074,6 @@ async function bundleConfigFile(
false,
)?.id
}
const isESMFile = (id: string): boolean => {
if (id.endsWith('.mjs')) return true
if (id.endsWith('.cjs')) return false

const nearestPackageJson = findNearestPackageData(
path.dirname(id),
packageCache,
)
return (
!!nearestPackageJson && nearestPackageJson.data.type === 'module'
)
}

// externalize bare imports
build.onResolve(
Expand Down Expand Up @@ -1133,7 +1121,11 @@ async function bundleConfigFile(
if (idFsPath && isImport) {
idFsPath = pathToFileURL(idFsPath).href
}
if (idFsPath && !isImport && isESMFile(idFsPath)) {
if (
idFsPath &&
!isImport &&
isFilePathESM(idFsPath, packageCache)
) {
throw new Error(
`${JSON.stringify(
id,
Expand Down
10 changes: 2 additions & 8 deletions packages/vite/src/node/plugins/resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
isBuiltin,
isDataUrl,
isExternalUrl,
isFilePathESM,
isInNodeModules,
isNonDriveRelativeAbsolutePath,
isObject,
Expand Down Expand Up @@ -815,8 +816,6 @@ export function tryNodeResolve(
})
}

const ext = path.extname(resolved)

if (
!options.ssrOptimizeCheck &&
(!isInNodeModules(resolved) || // linked
Expand Down Expand Up @@ -852,12 +851,7 @@ export function tryNodeResolve(
(!options.ssrOptimizeCheck && !isBuild && ssr) ||
// Only optimize non-external CJS deps during SSR by default
(ssr &&
!(
ext === '.cjs' ||
(ext === '.js' &&
findNearestPackageData(path.dirname(resolved), options.packageCache)
?.data.type !== 'module')
) &&
isFilePathESM(resolved, options.packageCache) &&
!(include?.includes(pkgId) || include?.includes(id)))

if (options.ssrOptimizeCheck) {
Expand Down
20 changes: 13 additions & 7 deletions packages/vite/src/node/ssr/ssrModuleLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { transformRequest } from '../server/transformRequest'
import type { InternalResolveOptionsWithOverrideConditions } from '../plugins/resolve'
import { tryNodeResolve } from '../plugins/resolve'
import { genSourceMapUrl } from '../server/sourcemap'
import type { PackageCache } from '../packages'
import {
ssrDynamicImportKey,
ssrExportAllKey,
Expand All @@ -31,6 +32,7 @@ type SSRModule = Record<string, any>
interface NodeImportResolveOptions
extends InternalResolveOptionsWithOverrideConditions {
legacyProxySsrExternalModules?: boolean
packageCache?: PackageCache
}

interface SSRImportMetadata {
Expand Down Expand Up @@ -150,6 +152,7 @@ async function instantiateModule(
root,
legacyProxySsrExternalModules:
server.config.legacy?.proxySsrExternalModules,
packageCache: server.config.packageCache,
}

// Since dynamic imports can happen in parallel, we need to
Expand Down Expand Up @@ -318,9 +321,13 @@ async function nodeImport(
} else if (isRuntimeHandled) {
return mod
} else {
// NOTE: Bun is able to handle the interop, should we skip for Bun?
// Also, how does Deno work here?
analyzeImportedModDifference(mod, url, id, metadata)
analyzeImportedModDifference(
mod,
url,
id,
metadata,
resolveOptions.packageCache,
)
return proxyGuardOnlyEsm(mod, id)
}
}
Expand Down Expand Up @@ -361,19 +368,18 @@ function analyzeImportedModDifference(
filePath: string,
rawId: string,
metadata?: SSRImportMetadata,
packageCache?: PackageCache,
) {
// No normalization needed if the user already dynamic imports this module
if (metadata?.isDynamicImport) return
// If file path is ESM, everything should be fine
if (isFilePathESM(filePath)) return
if (isFilePathESM(filePath, packageCache)) return

// For non-ESM, named imports is done via static analysis with cjs-module-lexer in Node.js.
// If the user named imports a specifier that can't be analyzed, error.
const modExports = Object.keys(mod)

if (metadata?.namedImportSpecifiers?.length) {
const missingBindings = metadata.namedImportSpecifiers.filter(
(s) => !(s in modExports),
(s) => !(s in mod),
)
if (missingBindings.length) {
const lastBinding = missingBindings[missingBindings.length - 1]
Expand Down
19 changes: 12 additions & 7 deletions packages/vite/src/node/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ import {
import type { DepOptimizationConfig } from './optimizer'
import type { ResolvedConfig } from './config'
import type { ResolvedServerUrls, ViteDevServer } from './server'
import { resolvePackageData } from './packages'
import {
type PackageCache,
findNearestPackageData,
resolvePackageData,
} from './packages'
import type { CommonServerOptions } from '.'

/**
Expand Down Expand Up @@ -409,18 +413,19 @@ export function lookupFile(
}
}

export function isFilePathESM(filePath: string): boolean {
export function isFilePathESM(
filePath: string,
packageCache?: PackageCache,
): boolean {
if (/\.m[jt]s$/.test(filePath)) {
return true
} else if (/\.c[jt]s$/.test(filePath)) {
return false
} else {
// check package.json for type: "module" and set `isESM` to true
// check package.json for type: "module"
try {
const pkg = lookupFile(path.dirname(filePath), ['package.json'])
return (
!!pkg && JSON.parse(fs.readFileSync(pkg, 'utf-8')).type === 'module'
)
const pkg = findNearestPackageData(path.dirname(filePath), packageCache)
return pkg?.data.type === 'module'
} catch {
return false
}
Expand Down

0 comments on commit b868033

Please sign in to comment.