diff --git a/README.md b/README.md index e142d4f..3e3856f 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,10 @@ const foo = require('foo').bar // ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ import * as __CJS_import__0__ from 'foo'; const { bar: foo } = __CJS_import__0__ +require('foo') +// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ +import 'foo' + // Non top-level scope const foo = [{ bar: require('foo').bar }] ↓ diff --git a/README.zh-CN.md b/README.zh-CN.md index 1039892..16e64a3 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -90,6 +90,10 @@ const foo = require('foo').bar // ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ import * as __CJS_import__0__ from 'foo'; const { bar: foo } = __CJS_import__0__ +require('foo') +// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ +import 'foo' + // 非顶级作用域 const foo = [{ bar: require('foo').bar }] ↓ diff --git a/src/analyze.ts b/src/analyze.ts index bf54472..2197e5d 100644 --- a/src/analyze.ts +++ b/src/analyze.ts @@ -13,6 +13,7 @@ export interface RequireStatement { /** CallExpression */ node: AcornNode ancestors: AcornNode[] + sideEffect: boolean /** * If require statement located top-level scope ant it is convertible, this will have a value(🎯-①) * 如果 require 在顶级作用于,并且是可转换 import 的,那么 topScopeNode 将会被赋值 @@ -66,6 +67,7 @@ export function analyzer(ast: AcornNode, code: string, id: string): Analyzed { analyzed.require.push({ node, ancestors, + sideEffect: ancestors.at(-2)?.type === 'ExpressionStatement', topScopeNode: dynamic === 'dynamic' ? undefined : findTopLevelScope(ancestors) as RequireStatement['topScopeNode'], diff --git a/src/generate-import.ts b/src/generate-import.ts index 59894a6..0993f46 100644 --- a/src/generate-import.ts +++ b/src/generate-import.ts @@ -12,7 +12,7 @@ export function generateImport(analyzed: Analyzed, id: string, options: Commonjs const imports: ImportRecord[] = [] let count = 0 - for (const { node, dynamic } of analyzed.require) { + for (const { node, dynamic, sideEffect, ancestors } of analyzed.require) { // Handled in `dynamic-require.ts` if (dynamic === 'dynamic') continue @@ -35,6 +35,13 @@ export function generateImport(analyzed: Analyzed, id: string, options: Commonjs -> ${codeSnippets} ${'^'.repeat(codeSnippets.length)}`) } + + if (sideEffect) { + impt.node = ancestors.at(-2)! // Replace the whole ExpressionStatement + impt.importExpression = `import "${requireId}"` + imports.push(impt) + continue + } // This is probably less accurate, but is much cheaper than a full AST parse. let importInterop: ImportInteropType | string = 'defaultFirst' diff --git a/src/index.ts b/src/index.ts index 5a4d4c1..45d071c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -168,11 +168,11 @@ async function transformCommonjs({ importExpression, importInterop, } = impt - if (importExpression != null && importInterop != null) { + if (importExpression != null) { // TODO: Merge duplicated require id hoistImports.push(importExpression + ';') // `importInterop` with brackets see #54 - ms.overwrite(node.start, node.end, `(${importInterop})`) + ms.overwrite(node.start, node.end, importInterop != null ? `(${importInterop})` : '') } } diff --git a/test/fixtures/__snapshots__/main.ts b/test/fixtures/__snapshots__/main.ts index 09504e3..00e4b66 100644 --- a/test/fixtures/__snapshots__/main.ts +++ b/test/fixtures/__snapshots__/main.ts @@ -1,4 +1,5 @@ -/* [vite-plugin-commonjs] import-hoist-S */ import * as __CJS__import__0__ from "./exports"; /* [vite-plugin-commonjs] import-hoist-E */const { msg: message } = (__CJS__import__0__.default || __CJS__import__0__); +/* [vite-plugin-commonjs] import-hoist-S */ import * as __CJS__import__0__ from "./exports"; import "./side-effect.cjs"; /* [vite-plugin-commonjs] import-hoist-E */const { msg: message } = (__CJS__import__0__.default || __CJS__import__0__); + import cjs from "./cjs"; document.querySelector("#app").innerHTML = `
diff --git a/test/fixtures/__snapshots__/side-effect.cjs b/test/fixtures/__snapshots__/side-effect.cjs
new file mode 100644
index 0000000..0060935
--- /dev/null
+++ b/test/fixtures/__snapshots__/side-effect.cjs
@@ -0,0 +1 @@
+globalThis.baz = 1
\ No newline at end of file
diff --git a/test/fixtures/src/main.ts b/test/fixtures/src/main.ts
index b9e2f33..800672b 100644
--- a/test/fixtures/src/main.ts
+++ b/test/fixtures/src/main.ts
@@ -1,8 +1,8 @@
const { msg: message } = require('./exports')
+require('./side-effect.cjs')
// import { cjs } from './cjs'
import cjs from './cjs'
-
document.querySelector('#app')!.innerHTML = `
${message}
diff --git a/test/fixtures/src/side-effect.cjs b/test/fixtures/src/side-effect.cjs
new file mode 100644
index 0000000..0060935
--- /dev/null
+++ b/test/fixtures/src/side-effect.cjs
@@ -0,0 +1 @@
+globalThis.baz = 1
\ No newline at end of file