Skip to content
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
128 changes: 32 additions & 96 deletions packages/vite/src/node/__tests__/plugins/import.spec.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,39 @@
import { beforeEach, describe, expect, test, vi } from 'vitest'
import { transformCjsImport } from '../../plugins/importAnalysis'

describe('transformCjsImport', () => {
const url = './node_modules/.vite/deps/react.js'
const rawUrl = 'react'
describe('runTransform', () => {
const config: any = {
command: 'serve',
logger: {
warn: vi.fn(),
},
}

function runTransformCjsImport(importExp: string) {
const result = transformCjsImport(
importExp,
'./node_modules/.vite/deps/react.js',
'react',
0,
'modA',
config,
)
if (result !== undefined) {
expect(result.split('\n').length, 'result line count').toBe(
importExp.split('\n').length,
)
}
Comment on lines +21 to +25
Copy link
Member Author

@sapphi-red sapphi-red Jul 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main change in this file is this part.

return result
}

beforeEach(() => {
config.logger.warn.mockClear()
})

test('import specifier', () => {
expect(
transformCjsImport(
runTransformCjsImport(
'import { useState, Component, "👋" as fake } from "react"',
url,
rawUrl,
0,
'',
config,
),
).toBe(
'import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"; ' +
Expand All @@ -34,90 +44,44 @@ describe('transformCjsImport', () => {
})

test('import default specifier', () => {
expect(
transformCjsImport(
'import React from "react"',
url,
rawUrl,
0,
'',
config,
),
).toBe(
expect(runTransformCjsImport('import React from "react"')).toBe(
'import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"; ' +
'const React = __vite__cjsImport0_react.__esModule ? __vite__cjsImport0_react.default : __vite__cjsImport0_react',
)

expect(
transformCjsImport(
'import { default as React } from "react"',
url,
rawUrl,
0,
'',
config,
),
runTransformCjsImport('import { default as React } from "react"'),
).toBe(
'import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"; ' +
'const React = __vite__cjsImport0_react.__esModule ? __vite__cjsImport0_react.default : __vite__cjsImport0_react',
)
})

test('import all specifier', () => {
expect(
transformCjsImport(
'import * as react from "react"',
url,
rawUrl,
0,
'',
config,
),
).toBe(
expect(runTransformCjsImport('import * as react from "react"')).toBe(
'import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"; ' +
`const react = ((m) => m?.__esModule ? m : { ...typeof m === "object" && !Array.isArray(m) || typeof m === "function" ? m : {}, default: m })(__vite__cjsImport0_react)`,
`const react = ((m) => m?.__esModule ? m : { ...typeof m === "object" && !Array.isArray(m) || typeof m === "function" ? m : {}, default: m})(__vite__cjsImport0_react)`,
)
})

test('export all specifier', () => {
expect(
transformCjsImport(
'export * from "react"',
url,
rawUrl,
0,
'modA',
config,
),
).toBe(undefined)
expect(runTransformCjsImport('export * from "react"')).toBe(undefined)

expect(config.logger.warn).toBeCalledWith(
expect.stringContaining(`export * from "react"\` in modA`),
)

expect(
transformCjsImport(
'export * as react from "react"',
url,
rawUrl,
0,
'',
config,
),
).toBe(undefined)
expect(runTransformCjsImport('export * as react from "react"')).toBe(
undefined,
)

expect(config.logger.warn).toBeCalledTimes(1)
})

test('export name specifier', () => {
expect(
transformCjsImport(
runTransformCjsImport(
'export { useState, Component, "👋" } from "react"',
url,
rawUrl,
0,
'',
config,
),
).toBe(
'import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"; ' +
Expand All @@ -128,13 +92,8 @@ describe('transformCjsImport', () => {
)

expect(
transformCjsImport(
runTransformCjsImport(
'export { useState as useStateAlias, Component as ComponentAlias, "👋" as "👍" } from "react"',
url,
rawUrl,
0,
'',
config,
),
).toBe(
'import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"; ' +
Expand All @@ -146,45 +105,22 @@ describe('transformCjsImport', () => {
})

test('export default specifier', () => {
expect(
transformCjsImport(
'export { default } from "react"',
url,
rawUrl,
0,
'',
config,
),
).toBe(
expect(runTransformCjsImport('export { default } from "react"')).toBe(
'import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"; ' +
'const __vite__cjsExportDefault_0 = __vite__cjsImport0_react.__esModule ? __vite__cjsImport0_react.default : __vite__cjsImport0_react; ' +
'export default __vite__cjsExportDefault_0',
)

expect(
transformCjsImport(
'export { default as React} from "react"',
url,
rawUrl,
0,
'',
config,
),
runTransformCjsImport('export { default as React} from "react"'),
).toBe(
'import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"; ' +
'const __vite__cjsExportI_React = __vite__cjsImport0_react.__esModule ? __vite__cjsImport0_react.default : __vite__cjsImport0_react; ' +
'export { __vite__cjsExportI_React as React }',
)

expect(
transformCjsImport(
'export { Component as default } from "react"',
url,
rawUrl,
0,
'',
config,
),
runTransformCjsImport('export { Component as default } from "react"'),
).toBe(
'import __vite__cjsImport0_react from "./node_modules/.vite/deps/react.js"; ' +
'const __vite__cjsExportDefault_0 = __vite__cjsImport0_react["Component"]; ' +
Expand Down
18 changes: 14 additions & 4 deletions packages/vite/src/node/plugins/importAnalysis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -897,8 +897,18 @@ export function createParseErrorInfo(
showCodeFrame: !probablyBinary,
}
}
// prettier-ignore
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ignore comment is not needed as Rolldown does not keep this function in a single line anyway.

const interopHelper = (m: any) => m?.__esModule ? m : { ...(typeof m === 'object' && !Array.isArray(m) || typeof m === 'function' ? m : {}), default: m }

const interopHelper = (m: any) =>
m?.__esModule
? m
: {
...((typeof m === 'object' && !Array.isArray(m)) ||
typeof m === 'function'
? m
: {}),
default: m,
}
const interopHelperStr = interopHelper.toString().replaceAll('\n', '')

export function interopNamedImports(
str: MagicString,
Expand All @@ -922,7 +932,7 @@ export function interopNamedImports(
str.overwrite(
expStart,
expEnd,
`import('${rewrittenUrl}').then(m => (${interopHelper.toString()})(m.default))` +
`import('${rewrittenUrl}').then(m => (${interopHelperStr})(m.default))` +
getLineBreaks(exp),
{ contentOnly: true },
)
Expand Down Expand Up @@ -1058,7 +1068,7 @@ export function transformCjsImport(
importNames.forEach(({ importedName, localName }) => {
if (importedName === '*') {
lines.push(
`const ${localName} = (${interopHelper.toString()})(${cjsModuleName})`,
`const ${localName} = (${interopHelperStr})(${cjsModuleName})`,
)
} else if (importedName === 'default') {
lines.push(
Expand Down
Loading