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

refactor: ExportData.imports to ExportData.hasImports #8355

Merged
merged 1 commit into from May 27, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 0 additions & 2 deletions packages/vite/src/node/index.ts
Expand Up @@ -37,8 +37,6 @@ export type {
DepOptimizationProcessing,
OptimizedDepInfo,
DepsOptimizer,
EsModuleLexerImportSpecifier,
EsModuleLexerParseReturnType,
ExportsData
} from './optimizer'
export type { Plugin } from './plugin'
Expand Down
11 changes: 3 additions & 8 deletions packages/vite/src/node/optimizer/esbuildDepPlugin.ts
Expand Up @@ -171,20 +171,15 @@ export function esbuildDepPlugin(
}

let contents = ''
const data = exportsData[id]
const [imports, exports] = data
if (!imports.length && !exports.length) {
const { hasImports, exports, hasReExports } = exportsData[id]
if (!hasImports && !exports.length) {
// cjs
contents += `export default require("${relativePath}");`
} else {
if (exports.includes('default')) {
contents += `import d from "${relativePath}";export default d;`
}
if (
data.hasReExports ||
exports.length > 1 ||
exports[0] !== 'default'
) {
if (hasReExports || exports.length > 1 || exports[0] !== 'default') {
contents += `\nexport * from "${relativePath}"`
}
}
Expand Down
85 changes: 47 additions & 38 deletions packages/vite/src/node/optimizer/index.ts
Expand Up @@ -6,7 +6,6 @@ import colors from 'picocolors'
import type { BuildOptions as EsbuildBuildOptions } from 'esbuild'
import { build } from 'esbuild'
import { init, parse } from 'es-module-lexer'
import type { ImportSpecifier as EsModuleLexerImportSpecifier } from 'types/es-module-lexer'
import type { ResolvedConfig } from '../config'
import {
createDebugger,
Expand All @@ -32,18 +31,15 @@ const isDebugEnabled = _debug('vite:deps').enabled
const jsExtensionRE = /\.js$/i
const jsMapExtensionRE = /\.js\.map$/i

export type { EsModuleLexerImportSpecifier }
export type EsModuleLexerParseReturnType = readonly [
imports: ReadonlyArray<EsModuleLexerImportSpecifier>,
exports: ReadonlyArray<string>,
export type ExportsData = {
hasImports: boolean
exports: readonly string[]
facade: boolean
]
export type ExportsData = EsModuleLexerParseReturnType & {
// es-module-lexer has a facade detection but isn't always accurate for our
// use case when the module has default export
hasReExports?: true
hasReExports?: boolean
// hint if the dep requires loading as jsx
jsxLoader?: true
jsxLoader?: boolean
}

export interface DepsOptimizer {
Expand Down Expand Up @@ -754,7 +750,6 @@ export async function extractExportsData(
config: ResolvedConfig
): Promise<ExportsData> {
await init
let exportsData: ExportsData

const esbuildOptions = config.optimizeDeps?.esbuildOptions ?? {}
if (config.optimizeDeps.extensions?.some((ext) => filePath.endsWith(ext))) {
Expand All @@ -767,34 +762,48 @@ export async function extractExportsData(
write: false,
format: 'esm'
})
exportsData = parse(result.outputFiles[0].text) as ExportsData
} else {
const entryContent = fs.readFileSync(filePath, 'utf-8')
try {
exportsData = parse(entryContent) as ExportsData
} catch {
const loader = esbuildOptions.loader?.[path.extname(filePath)] || 'jsx'
debug(
`Unable to parse: ${filePath}.\n Trying again with a ${loader} transform.`
)
const transformed = await transformWithEsbuild(entryContent, filePath, {
loader
})
// Ensure that optimization won't fail by defaulting '.js' to the JSX parser.
// This is useful for packages such as Gatsby.
esbuildOptions.loader = {
'.js': 'jsx',
...esbuildOptions.loader
}
exportsData = parse(transformed.code) as ExportsData
exportsData.jsxLoader = true
const [imports, exports, facade] = parse(result.outputFiles[0].text)
return {
hasImports: imports.length > 0,
exports,
facade
}
for (const { ss, se } of exportsData[0]) {
const exp = entryContent.slice(ss, se)
if (/export\s+\*\s+from/.test(exp)) {
exportsData.hasReExports = true
}
}

let parseResult: ReturnType<typeof parse>
let usedJsxLoader = false

const entryContent = fs.readFileSync(filePath, 'utf-8')
try {
parseResult = parse(entryContent)
} catch {
const loader = esbuildOptions.loader?.[path.extname(filePath)] || 'jsx'
debug(
`Unable to parse: ${filePath}.\n Trying again with a ${loader} transform.`
)
const transformed = await transformWithEsbuild(entryContent, filePath, {
loader
})
// Ensure that optimization won't fail by defaulting '.js' to the JSX parser.
// This is useful for packages such as Gatsby.
esbuildOptions.loader = {
'.js': 'jsx',
...esbuildOptions.loader
}
parseResult = parse(transformed.code)
usedJsxLoader = true
}

const [imports, exports, facade] = parseResult
const exportsData: ExportsData = {
hasImports: imports.length > 0,
exports,
facade,
hasReExports: imports.some(({ ss, se }) => {
const exp = entryContent.slice(ss, se)
return /export\s+\*\s+from/.test(exp)
}),
jsxLoader: usedJsxLoader
}
return exportsData
}
Expand All @@ -816,9 +825,9 @@ function needsInterop(
) {
return true
}
const [imports, exports] = exportsData
const { hasImports, exports } = exportsData
// entry has no ESM syntax - likely CJS or UMD
if (!exports.length && !imports.length) {
if (!exports.length && !hasImports) {
return true
}

Expand Down
90 changes: 0 additions & 90 deletions packages/vite/types/es-module-lexer.d.ts

This file was deleted.