Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
681cd8c
fix(commonjs): attach correct plugin meta-data to commonjs modules (#…
lukastaegert Sep 21, 2021
f55ba96
feat(commonjs): reimplement dynamic import handling (requires Node 12…
lukastaegert Oct 28, 2021
003845f
feat(commonjs): add strictRequires option to wrap modules (#1038)
lukastaegert Nov 6, 2021
771ef4a
feat(commonjs): automatically wrap cyclic modules (#1038)
lukastaegert Nov 9, 2021
aae44a2
feat(commonjs): Infer type for unidentified modules (#1038)
lukastaegert Nov 12, 2021
1054074
feat(commonjs): make namespace callable when requiring ESM with funct…
lukastaegert Nov 12, 2021
4424686
feat(commonjs): limit ignoreTryCatch to external requires (#1038)
lukastaegert Nov 19, 2021
a9ed479
feat(commonjs): auto-detect conditional requires (#1038)
lukastaegert Nov 20, 2021
42e7196
feat(commonjs): add dynamicRequireRoot option (#1038)
lukastaegert Nov 21, 2021
06a74ae
feat(commonjs): throw for dynamic requires from outside the configure…
lukastaegert Nov 22, 2021
3cdad21
refactor(commonjs): deconflict helpers only once globals are known (#…
lukastaegert Nov 22, 2021
3b28947
feat(commonjs): expose plugin version (#1038)
lukastaegert Nov 24, 2021
a66d253
fix(commonjs): do not transform "typeof exports" for mixed modules (#…
lukastaegert Dec 2, 2021
29074f4
fix(commonjs): inject module name into dynamic require function (#1038)
lukastaegert Dec 14, 2021
804eb8e
fix(commonjs): validate node-resolve peer version (#1038)
lukastaegert Dec 14, 2021
d01238f
fix(commonjs): use correct version and add package exports (#1038)
lukastaegert Dec 14, 2021
017ea90
fix(commonjs): proxy all entries to not break legacy polyfill plugins…
lukastaegert Jan 14, 2022
a521f47
fix(commonjs): add heuristic to deoptimize requires after calling imp…
lukastaegert Feb 7, 2022
368f9c8
fix(commonjs): handle external dependencies when using the cache (#1038)
lukastaegert Feb 24, 2022
e5f1abd
fix(commonjs): Do not change semantics when removing requires in if s…
lukastaegert Apr 3, 2022
e2f26a4
fix(commonjs): Warn when plugins do not pass options to resolveId (#1…
lukastaegert Apr 18, 2022
5b3bd05
fix(commonjs): support CJS modules re-exporting transpiled ESM module…
fwouts Apr 24, 2022
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
Next Next commit
fix(commonjs): attach correct plugin meta-data to commonjs modules (#…
  • Loading branch information
lukastaegert committed Apr 24, 2022
commit 681cd8c0f5fd1366aa5e5500fc3779d6824ae6ff
11 changes: 11 additions & 0 deletions packages/commonjs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,17 @@ Default: `false`

Instructs the plugin whether to enable mixed module transformations. This is useful in scenarios with modules that contain a mix of ES `import` statements and CommonJS `require` expressions. Set to `true` if `require` calls should be transformed to imports in mixed modules, or `false` if the `require` expressions should survive the transformation. The latter can be important if the code contains environment detection, or you are coding for an environment with special treatment for `require` calls such as [ElectronJS](https://www.electronjs.org/). See also the "ignore" option.

### `strictRequireSemantic`

Type: `boolean | string | string[]`<br>
Default: `false`

By default, this plugin will try to hoist all `require` statements as imports to the top of each file. While this works well for many code bases and allows for very efficient ESM output, it does not perfectly capture CommonJS semantics. This is especially problematic when there are circular `require` calls between CommonJS modules as those often rely on the lazy execution of nested `require` calls.

Setting this option to `true` will wrap all CommonJS files in functions which are executed when they are required for the first time, preserving NodeJS semantics. Note that this can have a small impact on the size and performance of the generated code.

You can also provide a [minimatch pattern](https://github.com/isaacs/minimatch), or array of patterns, to only specify a subset of files which should be wrapped in functions for proper `require` semantics.

### `ignore`

Type: `string[] | ((id: string) => boolean)`<br>
Expand Down
2 changes: 1 addition & 1 deletion packages/commonjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"require"
],
"peerDependencies": {
"rollup": "^2.38.3"
"rollup": "^2.61.1"
},
"dependencies": {
"@rollup/pluginutils": "^3.1.0",
Expand Down
14 changes: 2 additions & 12 deletions packages/commonjs/src/generate-imports.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,7 @@ import { dirname, resolve } from 'path';

import { sync as nodeResolveSync } from 'resolve';

import {
EXPORTS_SUFFIX,
HELPERS_ID,
MODULE_SUFFIX,
PROXY_SUFFIX,
REQUIRE_SUFFIX,
wrapId
} from './helpers';
import { EXPORTS_SUFFIX, HELPERS_ID, MODULE_SUFFIX, PROXY_SUFFIX, wrapId } from './helpers';
import { normalizePathSlashes } from './utils';

export function isRequireStatement(node, scope) {
Expand Down Expand Up @@ -153,12 +146,9 @@ export function getRequireHandlers() {
);
}
for (const source of dynamicRegisterSources) {
imports.push(`import ${JSON.stringify(wrapId(source, REQUIRE_SUFFIX))};`);
imports.push(`import ${JSON.stringify(source)};`);
}
for (const source of requiredSources) {
if (!source.startsWith('\0')) {
imports.push(`import ${JSON.stringify(wrapId(source, REQUIRE_SUFFIX))};`);
}
const { name, nodesUsingRequired } = requiredBySource[source];
imports.push(
`import ${nodesUsingRequired.length ? `${name} from ` : ''}${JSON.stringify(
Expand Down
1 change: 0 additions & 1 deletion packages/commonjs/src/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ export const wrapId = (id, suffix) => `\0${id}${suffix}`;
export const unwrapId = (wrappedId, suffix) => wrappedId.slice(1, -suffix.length);

export const PROXY_SUFFIX = '?commonjs-proxy';
export const REQUIRE_SUFFIX = '?commonjs-require';
export const EXTERNAL_SUFFIX = '?commonjs-external';
export const EXPORTS_SUFFIX = '?commonjs-exports';
export const MODULE_SUFFIX = '?commonjs-module';
Expand Down
18 changes: 7 additions & 11 deletions packages/commonjs/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import {
PROXY_SUFFIX,
unwrapId
} from './helpers';
import { setCommonJSMetaPromise } from './is-cjs';
import { hasCjsKeywords } from './parse';
import {
getDynamicJsonProxy,
Expand All @@ -43,6 +42,12 @@ import { getName, getVirtualPathForDynamicRequirePath, normalizePathSlashes } fr
export default function commonjs(options = {}) {
const extensions = options.extensions || ['.js'];
const filter = createFilter(options.include, options.exclude);
const strictRequireSemanticFilter =
options.strictRequireSemantic === true
? () => true
: !options.strictRequireSemantic
? () => false
: createFilter(options.strictRequireSemantic);
const {
ignoreGlobal,
ignoreDynamicRequires,
Expand Down Expand Up @@ -77,7 +82,6 @@ export default function commonjs(options = {}) {

const esModulesWithDefaultExport = new Set();
const esModulesWithNamedExports = new Set();
const commonJsMetaPromises = new Map();

const ignoreRequire =
typeof options.ignore === 'function'
Expand Down Expand Up @@ -248,7 +252,7 @@ export default function commonjs(options = {}) {
getRequireReturnsDefault(actualId),
esModulesWithDefaultExport,
esModulesWithNamedExports,
commonJsMetaPromises
this.load
);
}

Expand Down Expand Up @@ -277,14 +281,6 @@ export default function commonjs(options = {}) {
} catch (err) {
return this.error(err, err.loc);
}
},

moduleParsed({ id, meta: { commonjs: commonjsMeta } }) {
if (commonjsMeta && commonjsMeta.isCommonJS != null) {
setCommonJSMetaPromise(commonJsMetaPromises, id, commonjsMeta);
return;
}
setCommonJSMetaPromise(commonJsMetaPromises, id, null);
}
};
}
27 changes: 0 additions & 27 deletions packages/commonjs/src/is-cjs.js

This file was deleted.

15 changes: 8 additions & 7 deletions packages/commonjs/src/proxies.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { readFileSync } from 'fs';

import { DYNAMIC_JSON_PREFIX, HELPERS_ID } from './helpers';
import { getCommonJSMetaPromise } from './is-cjs';
import { getName, getVirtualPathForDynamicRequirePath, normalizePathSlashes } from './utils';

// e.g. id === "commonjsHelpers?commonjsRegister"
Expand All @@ -16,11 +15,11 @@ export function getUnknownRequireProxy(id, requireReturnsDefault) {
const name = getName(id);
const exported =
requireReturnsDefault === 'auto'
? `import {getDefaultExportFromNamespaceIfNotNamed} from "${HELPERS_ID}"; export default /*@__PURE__*/getDefaultExportFromNamespaceIfNotNamed(${name});`
? `import { getDefaultExportFromNamespaceIfNotNamed } from "${HELPERS_ID}"; export default /*@__PURE__*/getDefaultExportFromNamespaceIfNotNamed(${name});`
: requireReturnsDefault === 'preferred'
? `import {getDefaultExportFromNamespaceIfPresent} from "${HELPERS_ID}"; export default /*@__PURE__*/getDefaultExportFromNamespaceIfPresent(${name});`
? `import { getDefaultExportFromNamespaceIfPresent } from "${HELPERS_ID}"; export default /*@__PURE__*/getDefaultExportFromNamespaceIfPresent(${name});`
: !requireReturnsDefault
? `import {getAugmentedNamespace} from "${HELPERS_ID}"; export default /*@__PURE__*/getAugmentedNamespace(${name});`
? `import { getAugmentedNamespace } from "${HELPERS_ID}"; export default /*@__PURE__*/getAugmentedNamespace(${name});`
: `export default ${name};`;
return `import * as ${name} from ${JSON.stringify(id)}; ${exported}`;
}
Expand All @@ -47,13 +46,15 @@ export async function getStaticRequireProxy(
requireReturnsDefault,
esModulesWithDefaultExport,
esModulesWithNamedExports,
commonJsMetaPromises
loadModule
) {
const name = getName(id);
const commonjsMeta = await getCommonJSMetaPromise(commonJsMetaPromises, id);
const {
meta: { commonjs: commonjsMeta }
} = await loadModule({ id });
if (commonjsMeta && commonjsMeta.isCommonJS) {
return `export { __moduleExports as default } from ${JSON.stringify(id)};`;
} else if (commonjsMeta === null) {
} else if (!commonjsMeta) {
return getUnknownRequireProxy(id, requireReturnsDefault);
} else if (!requireReturnsDefault) {
return `import { getAugmentedNamespace } from "${HELPERS_ID}"; import * as ${name} from ${JSON.stringify(
Expand Down
31 changes: 18 additions & 13 deletions packages/commonjs/src/resolve-id.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
isWrappedId,
MODULE_SUFFIX,
PROXY_SUFFIX,
REQUIRE_SUFFIX,
unwrapId,
wrapId
} from './helpers';
Expand Down Expand Up @@ -66,14 +65,11 @@ export default function getResolveId(extensions) {
}

const isProxyModule = isWrappedId(importee, PROXY_SUFFIX);
const isRequiredModule = isWrappedId(importee, REQUIRE_SUFFIX);
let isModuleRegistration = false;

if (isProxyModule) {
importee = unwrapId(importee, PROXY_SUFFIX);
} else if (isRequiredModule) {
importee = unwrapId(importee, REQUIRE_SUFFIX);

} else {
isModuleRegistration = isWrappedId(importee, DYNAMIC_REGISTER_SUFFIX);
if (isModuleRegistration) {
importee = unwrapId(importee, DYNAMIC_REGISTER_SUFFIX);
Expand All @@ -98,20 +94,29 @@ export default function getResolveId(extensions) {
Object.assign({}, resolveOptions, {
skipSelf: true,
custom: Object.assign({}, resolveOptions.custom, {
'node-resolve': { isRequire: isProxyModule || isRequiredModule }
'node-resolve': { isRequire: isProxyModule || isModuleRegistration }
})
})
).then((resolved) => {
if (!resolved) {
resolved = resolveExtensions(importee, importer);
}
if (resolved && isProxyModule) {
resolved.id = wrapId(resolved.id, resolved.external ? EXTERNAL_SUFFIX : PROXY_SUFFIX);
resolved.external = false;
} else if (resolved && isModuleRegistration) {
resolved.id = wrapId(resolved.id, DYNAMIC_REGISTER_SUFFIX);
} else if (!resolved && (isProxyModule || isRequiredModule)) {
return { id: wrapId(importee, EXTERNAL_SUFFIX), external: false };
if (isProxyModule) {
if (!resolved || resolved.external) {
return {
id: wrapId(resolved ? resolved.id : importee, EXTERNAL_SUFFIX),
external: false
};
}
// This will make sure meta properties in "resolved" are correctly attached to the module
this.load(resolved);
return {
id: wrapId(resolved.id, PROXY_SUFFIX),
external: false
};
}
if (resolved && isModuleRegistration) {
return { id: wrapId(resolved.id, DYNAMIC_REGISTER_SUFFIX), external: false };
}
return resolved;
});
Expand Down
13 changes: 4 additions & 9 deletions packages/commonjs/src/transform-commonjs.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,8 @@ export default function transformCommonjs(
const dynamicRegisterSources = new Set();
let hasRemovedRequire = false;

const {
addRequireStatement,
requiredSources,
rewriteRequireExpressionsAndGetImportBlock
} = getRequireHandlers();
const { addRequireStatement, requiredSources, rewriteRequireExpressionsAndGetImportBlock } =
getRequireHandlers();

// See which names are assigned to. This is necessary to prevent
// illegally replacing `var foo = require('foo')` with `import foo from 'foo'`,
Expand Down Expand Up @@ -235,10 +232,8 @@ export default function transformCommonjs(
let shouldRemoveRequireStatement = false;

if (currentTryBlockEnd !== null) {
({
canConvertRequire,
shouldRemoveRequireStatement
} = getIgnoreTryCatchRequireStatementMode(node.arguments[0].value));
({ canConvertRequire, shouldRemoveRequireStatement } =
getIgnoreTryCatchRequireStatementMode(node.arguments[0].value));

if (shouldRemoveRequireStatement) {
hasRemovedRequire = true;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as commonjsHelpers from "_commonjsHelpers.js";
import { __exports as input } from "\u0000fixtures/form/constant-template-literal/input.js?commonjs-exports"
import "\u0000tape?commonjs-require";
import require$$0 from "\u0000tape?commonjs-proxy";

var foo = require$$0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ import * as commonjsHelpers from "_commonjsHelpers.js";
var input = { default: { foo: 'bar' }}

export default input;
export { input as __moduleExports };
export { input as __moduleExports };
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as commonjsHelpers from "_commonjsHelpers.js";
import { __exports as input } from "\u0000fixtures/form/ignore-ids-function/input.js?commonjs-exports"
import "\u0000bar?commonjs-require";
import require$$0 from "\u0000bar?commonjs-proxy";

var foo = require( 'foo' );
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as commonjsHelpers from "_commonjsHelpers.js";
import { __exports as input } from "\u0000fixtures/form/ignore-ids/input.js?commonjs-exports"
import "\u0000bar?commonjs-require";
import require$$0 from "\u0000bar?commonjs-proxy";

var foo = require( 'foo' );
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as commonjsHelpers from "_commonjsHelpers.js";
import "\u0000./input2.js?commonjs-require";
import require$$0 from "\u0000./input2.js?commonjs-proxy";

const t2 = require$$0;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as commonjsHelpers from "_commonjsHelpers.js";
import { __exports as input } from "\u0000fixtures/form/multiple-var-declarations-b/input.js?commonjs-exports"
import "\u0000./a?commonjs-require";
import require$$0 from "\u0000./a?commonjs-proxy";

var a = require$$0
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as commonjsHelpers from "_commonjsHelpers.js";
import { __exports as input } from "\u0000fixtures/form/multiple-var-declarations-c/input.js?commonjs-exports"
import "\u0000./b?commonjs-require";
import require$$0 from "\u0000./b?commonjs-proxy";

var a = 'a'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import * as commonjsHelpers from "_commonjsHelpers.js";
import { __exports as input } from "\u0000fixtures/form/multiple-var-declarations/input.js?commonjs-exports"
import "\u0000./a?commonjs-require";
import require$$0 from "\u0000./a?commonjs-proxy";
import "\u0000./b?commonjs-require";
import require$$1 from "\u0000./b?commonjs-proxy";

var a = require$$0()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as commonjsHelpers from "_commonjsHelpers.js";
import { __exports as input_1 } from "\u0000fixtures/form/no-exports-entry/input.js?commonjs-exports"
import "\u0000./dummy?commonjs-require";
import require$$0 from "\u0000./dummy?commonjs-proxy";

var dummy = require$$0;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as commonjsHelpers from "_commonjsHelpers.js";
import { __exports as input } from "\u0000fixtures/form/require-collision/input.js?commonjs-exports"
import "\u0000foo?commonjs-require";
import require$$1 from "\u0000foo?commonjs-proxy";

(function() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as commonjsHelpers from "_commonjsHelpers.js";
import { __exports as input } from "\u0000fixtures/form/unambiguous-with-default-export/input.js?commonjs-exports"
import "\u0000./foo.js?commonjs-require";
import "\u0000./foo.js?commonjs-proxy";

export default {};
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as commonjsHelpers from "_commonjsHelpers.js";
import { __exports as input } from "\u0000fixtures/form/unambiguous-with-import/input.js?commonjs-exports"
import "\u0000./foo.js?commonjs-require";
import "\u0000./foo.js?commonjs-proxy";

import './bar.js';
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as commonjsHelpers from "_commonjsHelpers.js";
import { __exports as input } from "\u0000fixtures/form/unambiguous-with-named-export/input.js?commonjs-exports"
import "\u0000./foo.js?commonjs-require";
import "\u0000./foo.js?commonjs-proxy";

export {};
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module.exports = {
description: 'preserves meta properties attached to modules by resolvers',
options: {
plugins: [
{
async resolveId(source, importer, options) {
if (source.endsWith('dep.js')) {
return {
...(await this.resolve(source, importer, { skipSelf: true, ...options })),
meta: { test: 'provided' }
};
}
return null;
},
moduleParsed({ id, meta: { test } }) {
if (id.endsWith('dep.js')) {
if (test !== 'provided') {
throw new Error(`Meta property missing for ${id}.`);
}
} else if (test === 'provided') {
throw new Error(`Meta property was unexpectedly added to ${id}.`);
}
}
}
]
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exports.foo = 'foo';
Loading