Skip to content

Commit 97eddef

Browse files
committed
fix(commonjs): Always sort node-resolve plugin after commonjs if necessary
1 parent 8d56097 commit 97eddef

File tree

8 files changed

+80
-129
lines changed

8 files changed

+80
-129
lines changed

packages/commonjs/README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ export default {
4242

4343
Then call `rollup` either via the [CLI](https://www.rollupjs.org/guide/en/#command-line-reference) or the [API](https://www.rollupjs.org/guide/en/#javascript-api).
4444

45+
When used together with the node-resolve plugin
46+
4547
## Options
4648

4749
### `strictRequires`
@@ -378,10 +380,12 @@ export default {
378380
format: 'iife',
379381
name: 'MyModule'
380382
},
381-
plugins: [resolve(), commonjs()]
383+
plugins: [commonjs(), resolve()]
382384
};
383385
```
384386

387+
Note that this plugin needs to be placed _before_ the node-resolve plugin. If that is not the case, it will automatically fix this by adjusting the plugins array and moving the node-resolve plugin directly behind the commonjs plugin during startup.
388+
385389
## Usage with symlinks
386390

387391
Symlinks are common in monorepos and are also created by the `npm link` command. Rollup with `@rollup/plugin-node-resolve` resolves modules to their real paths by default. So `include` and `exclude` paths should handle real paths rather than symlinked paths (e.g. `../common/node_modules/**` instead of `node_modules/**`). You may also use a regular expression for `include` that works regardless of base path. Try this:

packages/commonjs/src/dynamic-modules.js

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,63 @@
1+
import { existsSync, readFileSync, statSync } from 'fs';
2+
import { join, resolve } from 'path';
3+
4+
import glob from 'glob';
5+
16
import { getVirtualPathForDynamicRequirePath, normalizePathSlashes } from './utils';
27

8+
function getPackageEntryPoint(dirPath) {
9+
let entryPoint = 'index.js';
10+
11+
try {
12+
if (existsSync(join(dirPath, 'package.json'))) {
13+
entryPoint =
14+
JSON.parse(readFileSync(join(dirPath, 'package.json'), { encoding: 'utf8' })).main ||
15+
entryPoint;
16+
}
17+
} catch (ignored) {
18+
// ignored
19+
}
20+
21+
return entryPoint;
22+
}
23+
24+
function isDirectory(path) {
25+
try {
26+
if (statSync(path).isDirectory()) return true;
27+
} catch (ignored) {
28+
// Nothing to do here
29+
}
30+
return false;
31+
}
32+
33+
export function getDynamicRequireModules(patterns) {
34+
const dynamicRequireModules = new Map();
35+
for (const pattern of !patterns || Array.isArray(patterns) ? patterns || [] : [patterns]) {
36+
const isNegated = pattern.startsWith('!');
37+
const modifyMap = (targetPath, resolvedPath) =>
38+
isNegated
39+
? dynamicRequireModules.delete(targetPath)
40+
: dynamicRequireModules.set(targetPath, resolvedPath);
41+
for (const path of glob.sync(isNegated ? pattern.substr(1) : pattern)) {
42+
const resolvedPath = resolve(path);
43+
const requirePath = normalizePathSlashes(resolvedPath);
44+
if (isDirectory(resolvedPath)) {
45+
const modulePath = normalizePathSlashes(resolve(join(path, getPackageEntryPoint(path))));
46+
modifyMap(requirePath, modulePath);
47+
modifyMap(modulePath, modulePath);
48+
} else {
49+
modifyMap(requirePath, requirePath);
50+
}
51+
}
52+
}
53+
return dynamicRequireModules;
54+
}
55+
356
const FAILED_REQUIRE_ERROR = `throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.');`;
457

5-
export function getDynamicRequireModules(
58+
export function getDynamicModuleRegistry(
659
isDynamicRequireModulesEnabled,
7-
dynamicRequireModuleSet,
60+
dynamicRequireModules,
861
commonDir,
962
ignoreDynamicRequires
1063
) {
@@ -13,16 +66,15 @@ export function getDynamicRequireModules(
1366
${FAILED_REQUIRE_ERROR}
1467
}`;
1568
}
16-
const dynamicModuleIds = [...dynamicRequireModuleSet];
17-
const dynamicModuleImports = dynamicModuleIds
69+
const dynamicModuleImports = [...dynamicRequireModules.values()]
1870
.map(
1971
(id, index) =>
2072
`import ${
2173
id.endsWith('.json') ? `json${index}` : `{ __require as require${index} }`
2274
} from ${JSON.stringify(id)};`
2375
)
2476
.join('\n');
25-
const dynamicModuleProps = dynamicModuleIds
77+
const dynamicModuleProps = [...dynamicRequireModules.keys()]
2678
.map(
2779
(id, index) =>
2880
`\t\t${JSON.stringify(

packages/commonjs/src/dynamic-require-paths.js

Lines changed: 0 additions & 46 deletions
This file was deleted.

packages/commonjs/src/generate-imports.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,11 @@ export function getRequireStringArg(node) {
6868
: node.arguments[0].quasis[0].value.cooked;
6969
}
7070

71-
export function hasDynamicModuleForPath(source, id, dynamicRequireModuleSet) {
71+
export function hasDynamicModuleForPath(source, id, dynamicRequireModules) {
7272
if (!/^(?:\.{0,2}[/\\]|[A-Za-z]:[/\\])/.test(source)) {
7373
try {
7474
const resolvedPath = normalizePathSlashes(nodeResolveSync(source, { basedir: dirname(id) }));
75-
if (dynamicRequireModuleSet.has(resolvedPath)) {
75+
if (dynamicRequireModules.has(resolvedPath)) {
7676
return true;
7777
}
7878
} catch (ex) {
@@ -85,7 +85,7 @@ export function hasDynamicModuleForPath(source, id, dynamicRequireModuleSet) {
8585

8686
for (const attemptExt of ['', '.js', '.json']) {
8787
const resolvedPath = normalizePathSlashes(resolve(dirname(id), source + attemptExt));
88-
if (dynamicRequireModuleSet.has(resolvedPath)) {
88+
if (dynamicRequireModules.has(resolvedPath)) {
8989
return true;
9090
}
9191
}

packages/commonjs/src/index.js

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ import getCommonDir from 'commondir';
66
import { peerDependencies } from '../package.json';
77

88
import analyzeTopLevelStatements from './analyze-top-level-statements';
9-
import { getDynamicRequireModules } from './dynamic-modules';
9+
import { getDynamicModuleRegistry, getDynamicRequireModules } from './dynamic-modules';
1010

11-
import getDynamicRequireModuleSet from './dynamic-require-paths';
1211
import {
1312
DYNAMIC_MODULES_ID,
1413
ES_IMPORT_SUFFIX,
@@ -61,10 +60,11 @@ export default function commonjs(options = {}) {
6160
getWrappedIds,
6261
isRequiredId
6362
} = getResolveRequireSourcesAndGetMeta(extensions, detectCycles);
64-
const dynamicRequireModuleSet = getDynamicRequireModuleSet(options.dynamicRequireTargets);
65-
const isDynamicRequireModulesEnabled = dynamicRequireModuleSet.size > 0;
63+
const dynamicRequireModules = getDynamicRequireModules(options.dynamicRequireTargets);
64+
const isDynamicRequireModulesEnabled = dynamicRequireModules.size > 0;
65+
// TODO Lukas do we need the CWD?
6666
const commonDir = isDynamicRequireModulesEnabled
67-
? getCommonDir(null, Array.from(dynamicRequireModuleSet).concat(process.cwd()))
67+
? getCommonDir(null, Array.from(dynamicRequireModules.keys()).concat(process.cwd()))
6868
: null;
6969

7070
const esModulesWithDefaultExport = new Set();
@@ -111,7 +111,7 @@ export default function commonjs(options = {}) {
111111
}
112112

113113
if (
114-
!dynamicRequireModuleSet.has(normalizePathSlashes(id)) &&
114+
!dynamicRequireModules.has(normalizePathSlashes(id)) &&
115115
(!(hasCjsKeywords(code, ignoreGlobal) || isRequiredId(id)) ||
116116
(isEsModule && !options.transformMixedEsModules))
117117
) {
@@ -120,7 +120,7 @@ export default function commonjs(options = {}) {
120120

121121
const needsRequireWrapper =
122122
!isEsModule &&
123-
(dynamicRequireModuleSet.has(normalizePathSlashes(id)) || strictRequiresFilter(id));
123+
(dynamicRequireModules.has(normalizePathSlashes(id)) || strictRequiresFilter(id));
124124

125125
return transformCommonjs(
126126
this.parse,
@@ -133,7 +133,7 @@ export default function commonjs(options = {}) {
133133
getIgnoreTryCatchRequireStatementMode,
134134
sourceMap,
135135
isDynamicRequireModulesEnabled,
136-
dynamicRequireModuleSet,
136+
dynamicRequireModules,
137137
commonDir,
138138
ast,
139139
defaultIsModuleExports,
@@ -146,10 +146,9 @@ export default function commonjs(options = {}) {
146146
return {
147147
name: 'commonjs',
148148

149-
options(options) {
149+
options({ plugins }) {
150150
// Always sort the node-resolve plugin after the commonjs plugin as otherwise CommonJS entries
151151
// will not work with strictRequires: true
152-
const { plugins } = options;
153152
if (Array.isArray(plugins)) {
154153
const cjsIndex = plugins.findIndex((plugin) => plugin.name === 'commonjs');
155154
const nodeResolveIndex = plugins.findIndex((plugin) => plugin.name === 'node-resolve');
@@ -228,9 +227,9 @@ export default function commonjs(options = {}) {
228227
}
229228

230229
if (id === DYNAMIC_MODULES_ID) {
231-
return getDynamicRequireModules(
230+
return getDynamicModuleRegistry(
232231
isDynamicRequireModulesEnabled,
233-
dynamicRequireModuleSet,
232+
dynamicRequireModules,
234233
commonDir,
235234
ignoreDynamicRequires
236235
);

packages/commonjs/src/transform-commonjs.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export default async function transformCommonjs(
4646
getIgnoreTryCatchRequireStatementMode,
4747
sourceMap,
4848
isDynamicRequireModulesEnabled,
49-
dynamicRequireModuleSet,
49+
dynamicRequireModules,
5050
commonDir,
5151
astCache,
5252
defaultIsModuleExports,
@@ -195,7 +195,7 @@ export default async function transformCommonjs(
195195
node.callee.object &&
196196
node.callee.object.name === 'require' &&
197197
node.callee.property.name === 'resolve' &&
198-
hasDynamicModuleForPath(id, '/', dynamicRequireModuleSet)
198+
hasDynamicModuleForPath(id, '/', dynamicRequireModules)
199199
) {
200200
// TODO Lukas reimplement?
201201
uses.require = true;
@@ -288,7 +288,7 @@ export default async function transformCommonjs(
288288
uses.require = true;
289289
if (isNodeRequirePropertyAccess(parent)) {
290290
// TODO Lukas reimplement?
291-
if (hasDynamicModuleForPath(id, '/', dynamicRequireModuleSet)) {
291+
if (hasDynamicModuleForPath(id, '/', dynamicRequireModules)) {
292292
if (parent.property.name === 'cache') {
293293
magicString.overwrite(node.start, node.end, dynamicRequireName, {
294294
storeName: true

packages/commonjs/test/snapshots/function.js.md

Lines changed: 1 addition & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -5624,7 +5624,7 @@ Generated by [AVA](https://avajs.dev).
56245624
`,
56255625
}
56265626

5627-
## strict-requires-entry
5627+
## strict-requires-entry-node-resolve
56285628

56295629
> Snapshot 1
56305630
@@ -5883,40 +5883,6 @@ Generated by [AVA](https://avajs.dev).
58835883
`,
58845884
}
58855885

5886-
## strict-requires-magic-string
5887-
5888-
> Snapshot 1
5889-
5890-
{
5891-
'main.js': `'use strict';␊
5892-
5893-
Object.defineProperty(exports, '__esModule', { value: true });␊
5894-
5895-
var main = {};␊
5896-
5897-
var hasRequiredMain;␊
5898-
5899-
function requireMain () {␊
5900-
if (hasRequiredMain) return main;␊
5901-
hasRequiredMain = 1;␊
5902-
console.log('hey');␊
5903-
5904-
const m = new MagicString('0123456789');␊
5905-
console.log(␊
5906-
m.prependRight(0, 'W').prependLeft(3, 'AB').appendRight(9, 'XY').remove(6, 8).toString()␊
5907-
);␊
5908-
const bundle = new MagicString.Bundle();␊
5909-
bundle.addSource({ filename: 'foo.txt', content: m });␊
5910-
const map = bundle.generateMap({ file: 'bundle.txt', includeContent: true, hires: true });␊
5911-
console.log(JSON.stringify(map));␊
5912-
main.foo = 'foo';␊
5913-
return main;␊
5914-
}␊
5915-
5916-
exports.__require = requireMain;␊
5917-
`,
5918-
}
5919-
59205886
## strict-requires-multiple-entry
59215887

59225888
> Snapshot 1
@@ -6807,27 +6773,3 @@ Generated by [AVA](https://avajs.dev).
68076773
module.exports = main;␊
68086774
`,
68096775
}
6810-
6811-
## strict-requires-entry-node-resolve
6812-
6813-
> Snapshot 1
6814-
6815-
{
6816-
'main.js': `'use strict';␊
6817-
6818-
var main = {};␊
6819-
6820-
var hasRequiredMain;␊
6821-
6822-
function requireMain () {␊
6823-
if (hasRequiredMain) return main;␊
6824-
hasRequiredMain = 1;␊
6825-
main.foo = 'foo';␊
6826-
return main;␊
6827-
}␊
6828-
6829-
var mainExports = requireMain();␊
6830-
6831-
module.exports = mainExports;␊
6832-
`,
6833-
}
-322 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)