Skip to content
Open
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
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 }]
Expand Down
4 changes: 4 additions & 0 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 }]
Expand Down
2 changes: 2 additions & 0 deletions src/analyze.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 将会被赋值
Expand Down Expand Up @@ -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'],
Expand Down
9 changes: 8 additions & 1 deletion src/generate-import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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'
Expand Down
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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})` : '')
}
}

Expand Down
3 changes: 2 additions & 1 deletion test/fixtures/__snapshots__/main.ts
Original file line number Diff line number Diff line change
@@ -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 = `
<pre>
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/__snapshots__/side-effect.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
globalThis.baz = 1
2 changes: 1 addition & 1 deletion test/fixtures/src/main.ts
Original file line number Diff line number Diff line change
@@ -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 = `
<pre>
${message}
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/src/side-effect.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
globalThis.baz = 1