Skip to content

Commit f061dc3

Browse files
authored
feat(commonjs): Do not use getters for module.exports (#1455)
1 parent 1bcd739 commit f061dc3

File tree

62 files changed

+746
-601
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+746
-601
lines changed

packages/commonjs/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
"@rollup/plugin-node-resolve": "^15.0.0",
7575
"locate-character": "^2.0.5",
7676
"require-relative": "^0.8.7",
77-
"rollup": "3.0.0-7",
77+
"rollup": "^3.19.0",
7878
"shx": "^0.3.4",
7979
"source-map": "^0.7.4",
8080
"source-map-support": "^0.5.21",

packages/commonjs/src/ast-utils.js

+8-3
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,16 @@ export function getKeypath(node) {
6060

6161
export const KEY_COMPILED_ESM = '__esModule';
6262

63-
export function isDefineCompiledEsm(node) {
63+
export function getDefineCompiledEsmType(node) {
64+
const definedPropertyWithExports = getDefinePropertyCallName(node, 'exports');
6465
const definedProperty =
65-
getDefinePropertyCallName(node, 'exports') || getDefinePropertyCallName(node, 'module.exports');
66+
definedPropertyWithExports || getDefinePropertyCallName(node, 'module.exports');
6667
if (definedProperty && definedProperty.key === KEY_COMPILED_ESM) {
67-
return isTruthy(definedProperty.value);
68+
return isTruthy(definedProperty.value)
69+
? definedPropertyWithExports
70+
? 'exports'
71+
: 'module'
72+
: false;
6873
}
6974
return false;
7075
}

packages/commonjs/src/generate-exports.js

+112-72
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,22 @@ export function wrapCode(magicString, uses, moduleName, exportsName, indentExclu
77
}
88
if (uses.exports) {
99
args.push('exports');
10-
passedArgs.push(exportsName);
10+
passedArgs.push(uses.module ? `${moduleName}.exports` : exportsName);
1111
}
1212
magicString
1313
.trim()
1414
.indent('\t', { exclude: indentExclusionRanges })
1515
.prepend(`(function (${args.join(', ')}) {\n`)
16-
.append(`\n} (${passedArgs.join(', ')}));`);
16+
// For some reason, this line is only indented correctly when using a
17+
// require-wrapper if we have this leading space
18+
.append(` \n} (${passedArgs.join(', ')}));`);
1719
}
1820

1921
export function rewriteExportsAndGetExportsBlock(
2022
magicString,
2123
moduleName,
2224
exportsName,
25+
exportedExportsName,
2326
wrapped,
2427
moduleExportsAssignments,
2528
firstTopLevelModuleExportsAssignment,
@@ -30,7 +33,6 @@ export function rewriteExportsAndGetExportsBlock(
3033
code,
3134
HELPERS_NAME,
3235
exportMode,
33-
detectWrappedDefault,
3436
defaultIsModuleExports,
3537
usesRequireWrapper,
3638
requireName
@@ -58,17 +60,20 @@ export function rewriteExportsAndGetExportsBlock(
5860
exportDeclarations,
5961
moduleExportsAssignments,
6062
firstTopLevelModuleExportsAssignment,
61-
exportsName
63+
exportsName,
64+
defaultIsModuleExports,
65+
HELPERS_NAME
6266
);
6367
} else {
64-
exports.push(`${exportsName} as __moduleExports`);
68+
if (exportMode === 'module') {
69+
exportDeclarations.push(`var ${exportedExportsName} = ${moduleName}.exports`);
70+
exports.push(`${exportedExportsName} as __moduleExports`);
71+
} else {
72+
exports.push(`${exportsName} as __moduleExports`);
73+
}
6574
if (wrapped) {
66-
getExportsWhenWrapping(
67-
exportDeclarations,
68-
exportsName,
69-
detectWrappedDefault,
70-
HELPERS_NAME,
71-
defaultIsModuleExports
75+
exportDeclarations.push(
76+
getDefaultExportDeclaration(exportedExportsName, defaultIsModuleExports, HELPERS_NAME)
7277
);
7378
} else {
7479
getExports(
@@ -81,17 +86,19 @@ export function rewriteExportsAndGetExportsBlock(
8186
topLevelAssignments,
8287
moduleName,
8388
exportsName,
89+
exportedExportsName,
8490
defineCompiledEsmExpressions,
8591
HELPERS_NAME,
86-
defaultIsModuleExports
92+
defaultIsModuleExports,
93+
exportMode
8794
);
8895
}
8996
}
9097
if (exports.length) {
91-
exportDeclarations.push(`export { ${exports.join(', ')} };`);
98+
exportDeclarations.push(`export { ${exports.join(', ')} }`);
9299
}
93100

94-
return `\n\n${exportDeclarations.join('\n')}`;
101+
return `\n\n${exportDeclarations.join(';\n')};`;
95102
}
96103

97104
function getExportsWhenUsingRequireWrapper(
@@ -106,35 +113,32 @@ function getExportsWhenUsingRequireWrapper(
106113
requireName,
107114
defineCompiledEsmExpressions
108115
) {
109-
if (!wrapped) {
110-
if (exportMode === 'replace') {
111-
for (const { left } of moduleExportsAssignments) {
112-
magicString.overwrite(left.start, left.end, exportsName);
113-
}
114-
} else {
115-
// Collect and rewrite module.exports assignments
116-
for (const { left } of moduleExportsAssignments) {
117-
magicString.overwrite(left.start, left.end, `${moduleName}.exports`);
118-
}
119-
// Collect and rewrite named exports
120-
for (const [exportName, { nodes }] of exportsAssignmentsByName) {
121-
for (const node of nodes) {
122-
magicString.overwrite(node.start, node.left.end, `${exportsName}.${exportName}`);
123-
}
124-
}
125-
// Collect and rewrite exports.__esModule assignments
126-
for (const expression of defineCompiledEsmExpressions) {
127-
const moduleExportsExpression =
128-
expression.type === 'CallExpression' ? expression.arguments[0] : expression.left.object;
116+
exports.push(`${requireName} as __require`);
117+
if (wrapped) return;
118+
if (exportMode === 'replace') {
119+
rewriteModuleExportsAssignments(magicString, moduleExportsAssignments, exportsName);
120+
} else {
121+
rewriteModuleExportsAssignments(magicString, moduleExportsAssignments, `${moduleName}.exports`);
122+
// Collect and rewrite named exports
123+
for (const [exportName, { nodes }] of exportsAssignmentsByName) {
124+
for (const { node, type } of nodes) {
129125
magicString.overwrite(
130-
moduleExportsExpression.start,
131-
moduleExportsExpression.end,
132-
exportsName
126+
node.start,
127+
node.left.end,
128+
`${
129+
exportMode === 'module' && type === 'module' ? `${moduleName}.exports` : exportsName
130+
}.${exportName}`
133131
);
134132
}
135133
}
134+
replaceDefineCompiledEsmExpressionsAndGetIfRestorable(
135+
defineCompiledEsmExpressions,
136+
magicString,
137+
exportMode,
138+
moduleName,
139+
exportsName
140+
);
136141
}
137-
exports.push(`${requireName} as __require`);
138142
}
139143

140144
function getExportsForReplacedModuleExports(
@@ -143,34 +147,30 @@ function getExportsForReplacedModuleExports(
143147
exportDeclarations,
144148
moduleExportsAssignments,
145149
firstTopLevelModuleExportsAssignment,
146-
exportsName
150+
exportsName,
151+
defaultIsModuleExports,
152+
HELPERS_NAME
147153
) {
148154
for (const { left } of moduleExportsAssignments) {
149155
magicString.overwrite(left.start, left.end, exportsName);
150156
}
151157
magicString.prependRight(firstTopLevelModuleExportsAssignment.left.start, 'var ');
152158
exports.push(`${exportsName} as __moduleExports`);
153-
exportDeclarations.push(`export default ${exportsName};`);
154-
}
155-
156-
function getExportsWhenWrapping(
157-
exportDeclarations,
158-
exportsName,
159-
detectWrappedDefault,
160-
HELPERS_NAME,
161-
defaultIsModuleExports
162-
) {
163159
exportDeclarations.push(
164-
`export default ${
165-
detectWrappedDefault && defaultIsModuleExports === 'auto'
166-
? `/*@__PURE__*/${HELPERS_NAME}.getDefaultExportFromCjs(${exportsName})`
167-
: defaultIsModuleExports === false
168-
? `${exportsName}.default`
169-
: exportsName
170-
};`
160+
getDefaultExportDeclaration(exportsName, defaultIsModuleExports, HELPERS_NAME)
171161
);
172162
}
173163

164+
function getDefaultExportDeclaration(exportedExportsName, defaultIsModuleExports, HELPERS_NAME) {
165+
return `export default ${
166+
defaultIsModuleExports === true
167+
? exportedExportsName
168+
: defaultIsModuleExports === false
169+
? `${exportedExportsName}.default`
170+
: `/*@__PURE__*/${HELPERS_NAME}.getDefaultExportFromCjs(${exportedExportsName})`
171+
}`;
172+
}
173+
174174
function getExports(
175175
magicString,
176176
exports,
@@ -181,9 +181,11 @@ function getExports(
181181
topLevelAssignments,
182182
moduleName,
183183
exportsName,
184+
exportedExportsName,
184185
defineCompiledEsmExpressions,
185186
HELPERS_NAME,
186-
defaultIsModuleExports
187+
defaultIsModuleExports,
188+
exportMode
187189
) {
188190
let deconflictedDefaultExportName;
189191
// Collect and rewrite module.exports assignments
@@ -195,8 +197,10 @@ function getExports(
195197
for (const [exportName, { nodes }] of exportsAssignmentsByName) {
196198
const deconflicted = deconflictedExportNames[exportName];
197199
let needsDeclaration = true;
198-
for (const node of nodes) {
199-
let replacement = `${deconflicted} = ${exportsName}.${exportName}`;
200+
for (const { node, type } of nodes) {
201+
let replacement = `${deconflicted} = ${
202+
exportMode === 'module' && type === 'module' ? `${moduleName}.exports` : exportsName
203+
}.${exportName}`;
200204
if (needsDeclaration && topLevelAssignments.has(node)) {
201205
replacement = `var ${replacement}`;
202206
needsDeclaration = false;
@@ -214,22 +218,58 @@ function getExports(
214218
}
215219
}
216220

217-
// Collect and rewrite exports.__esModule assignments
218-
let isRestorableCompiledEsm = false;
219-
for (const expression of defineCompiledEsmExpressions) {
220-
isRestorableCompiledEsm = true;
221-
const moduleExportsExpression =
222-
expression.type === 'CallExpression' ? expression.arguments[0] : expression.left.object;
223-
magicString.overwrite(moduleExportsExpression.start, moduleExportsExpression.end, exportsName);
224-
}
221+
const isRestorableCompiledEsm = replaceDefineCompiledEsmExpressionsAndGetIfRestorable(
222+
defineCompiledEsmExpressions,
223+
magicString,
224+
exportMode,
225+
moduleName,
226+
exportsName
227+
);
225228

226-
if (!isRestorableCompiledEsm || defaultIsModuleExports === true) {
227-
exports.push(`${exportsName} as default`);
228-
} else if (moduleExportsAssignments.length === 0 || defaultIsModuleExports === false) {
229-
exports.push(`${deconflictedDefaultExportName || exportsName} as default`);
229+
if (
230+
defaultIsModuleExports === false ||
231+
(defaultIsModuleExports === 'auto' &&
232+
isRestorableCompiledEsm &&
233+
moduleExportsAssignments.length === 0)
234+
) {
235+
// If there is no deconflictedDefaultExportName, then we use the namespace as
236+
// fallback because there can be no "default" property on the namespace
237+
exports.push(`${deconflictedDefaultExportName || exportedExportsName} as default`);
238+
} else if (
239+
defaultIsModuleExports === true ||
240+
(!isRestorableCompiledEsm && moduleExportsAssignments.length === 0)
241+
) {
242+
exports.push(`${exportedExportsName} as default`);
230243
} else {
231244
exportDeclarations.push(
232-
`export default /*@__PURE__*/${HELPERS_NAME}.getDefaultExportFromCjs(${exportsName});`
245+
getDefaultExportDeclaration(exportedExportsName, defaultIsModuleExports, HELPERS_NAME)
246+
);
247+
}
248+
}
249+
250+
function rewriteModuleExportsAssignments(magicString, moduleExportsAssignments, exportsName) {
251+
for (const { left } of moduleExportsAssignments) {
252+
magicString.overwrite(left.start, left.end, exportsName);
253+
}
254+
}
255+
256+
function replaceDefineCompiledEsmExpressionsAndGetIfRestorable(
257+
defineCompiledEsmExpressions,
258+
magicString,
259+
exportMode,
260+
moduleName,
261+
exportsName
262+
) {
263+
let isRestorableCompiledEsm = false;
264+
for (const { node, type } of defineCompiledEsmExpressions) {
265+
isRestorableCompiledEsm = true;
266+
const moduleExportsExpression =
267+
node.type === 'CallExpression' ? node.arguments[0] : node.left.object;
268+
magicString.overwrite(
269+
moduleExportsExpression.start,
270+
moduleExportsExpression.end,
271+
exportMode === 'module' && type === 'module' ? `${moduleName}.exports` : exportsName
233272
);
234273
}
274+
return isRestorableCompiledEsm;
235275
}

packages/commonjs/src/generate-imports.js

+7-8
Original file line numberDiff line numberDiff line change
@@ -98,19 +98,18 @@ export function getRequireHandlers() {
9898
commonjsMeta
9999
) {
100100
const imports = [];
101-
imports.push(`import * as ${helpersName} from "${HELPERS_ID}";`);
101+
imports.push(`import * as ${helpersName} from "${HELPERS_ID}"`);
102102
if (dynamicRequireName) {
103103
imports.push(
104104
`import { ${
105105
isDynamicRequireModulesEnabled ? CREATE_COMMONJS_REQUIRE_EXPORT : COMMONJS_REQUIRE_EXPORT
106-
} as ${dynamicRequireName} } from "${DYNAMIC_MODULES_ID}";`
106+
} as ${dynamicRequireName} } from "${DYNAMIC_MODULES_ID}"`
107107
);
108108
}
109109
if (exportMode === 'module') {
110110
imports.push(
111-
`import { __module as ${moduleName}, exports as ${exportsName} } from ${JSON.stringify(
112-
wrapId(id, MODULE_SUFFIX)
113-
)}`
111+
`import { __module as ${moduleName} } from ${JSON.stringify(wrapId(id, MODULE_SUFFIX))}`,
112+
`var ${exportsName} = ${moduleName}.exports`
114113
);
115114
} else if (exportMode === 'exports') {
116115
imports.push(
@@ -136,7 +135,7 @@ export function getRequireHandlers() {
136135
getIgnoreTryCatchRequireStatementMode,
137136
magicString
138137
);
139-
return imports.length ? `${imports.join('\n')}\n\n` : '';
138+
return imports.length ? `${imports.join(';\n')};\n\n` : '';
140139
}
141140

142141
return {
@@ -196,9 +195,9 @@ function processRequireExpressions(
196195
}
197196
if (needsImport) {
198197
if (isCommonJS === IS_WRAPPED_COMMONJS) {
199-
imports.push(`import { __require as ${name} } from ${JSON.stringify(resolvedId)};`);
198+
imports.push(`import { __require as ${name} } from ${JSON.stringify(resolvedId)}`);
200199
} else {
201-
imports.push(`import ${usesRequired ? `${name} from ` : ''}${JSON.stringify(resolvedId)};`);
200+
imports.push(`import ${usesRequired ? `${name} from ` : ''}${JSON.stringify(resolvedId)}`);
202201
}
203202
}
204203
}

packages/commonjs/src/index.js

+2-8
Original file line numberDiff line numberDiff line change
@@ -243,15 +243,9 @@ export default function commonjs(options = {}) {
243243
}
244244

245245
if (isWrappedId(id, MODULE_SUFFIX)) {
246-
const module = getName(unwrapId(id, MODULE_SUFFIX));
247-
const moduleExports = `${module}Exports`;
246+
const name = getName(unwrapId(id, MODULE_SUFFIX));
248247
return {
249-
code: `var ${moduleExports} = {};
250-
var ${module} = {
251-
get exports(){ return ${moduleExports}; },
252-
set exports(v){ ${moduleExports} = v; },
253-
};
254-
export {${module} as __module, ${moduleExports} as exports}`,
248+
code: `var ${name} = {exports: {}}; export {${name} as __module}`,
255249
meta: { commonjs: { isCommonJS: false } }
256250
};
257251
}

0 commit comments

Comments
 (0)