Skip to content

Commit

Permalink
chore(commonjs): add documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
lukastaegert committed Jul 26, 2020
1 parent 71cc82b commit 61c1fc7
Show file tree
Hide file tree
Showing 14 changed files with 175 additions and 48 deletions.
112 changes: 104 additions & 8 deletions packages/commonjs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Then call `rollup` either via the [CLI](https://www.rollupjs.org/guide/en/#comma

### `dynamicRequireTargets`

Type: `String|Array[String]`<br>
Type: `string | string[]`<br>
Default: `[]`

Some modules contain dynamic `require` calls, or require modules that contain circular dependencies, which are not handled well by static imports.
Expand All @@ -73,53 +73,149 @@ commonjs({

### `exclude`

Type: `String` | `Array[...String]`<br>
Type: `string | string[]`<br>
Default: `null`

A [minimatch pattern](https://github.com/isaacs/minimatch), or array of patterns, which specifies the files in the build the plugin should _ignore_. By default non-CommonJS modules are ignored.

### `include`

Type: `String` | `Array[...String]`<br>
Type: `string | string[]`<br>
Default: `null`

A [minimatch pattern](https://github.com/isaacs/minimatch), or array of patterns, which specifies the files in the build the plugin should operate on. By default CommonJS modules are targeted.

### `extensions`

Type: `Array[...String]`<br>
Type: `string[]`<br>
Default: `['.js']`

Search for extensions other than .js in the order specified.

### `ignoreGlobal`

Type: `Boolean`<br>
Type: `boolean`<br>
Default: `false`

If true, uses of `global` won't be dealt with by this plugin.

### `sourceMap`

Type: `Boolean`<br>
Type: `boolean`<br>
Default: `true`

If false, skips source map generation for CommonJS modules.

### `transformMixedEsModules`

Type: `Boolean`<br>
Type: `boolean`<br>
Default: `false`

Instructs the plugin whether or not to enable mixed module transformations. This is useful in scenarios with mixed ES and CommonJS modules. Set to `true` if it's known that `require` calls should be transformed, or `false` if the code contains env detection and the `require` should survive a transformation.

### `ignore`

Type: `Array[...String | (String) => Boolean]`<br>
Type: `string[] | (id: string) => boolean`<br>
Default: `[]`

Sometimes you have to leave require statements unconverted. Pass an array containing the IDs or an `id => boolean` function. Only use this option if you know what you're doing!

### `requireReturnsDefault`

Type: `boolean | "auto" | "preferred" | ((id: string) => boolean | "auto" | "preferred")`<br>
Default: `false`

Controls what is returned when requiring an ES module or external dependency from a CommonJS file. By default, this plugin will render it as a namespace import, i.e.

```js
// input
const foo = require('foo');

// output
import * as foo from 'foo';
```

This is in line with how other bundlers handle this situation and is also the most likely behaviour in case Node should ever support this. However there are some situations where this may not be desired:

- There is code in an external dependency that cannot be changed where a `require` statement expects the default export to be returned.
- You want to import an external dependency that is actually CommonJS and want your generated code to be able to run natively in NodeJS 14+. Node can only import a default export from a CommonJS file so rendering a namespace import would not work.
- If the imported module is in the same bundle, Rollup will generate a namespace object for the imported module which can increase bundle size unnecessarily:

```js
// input: main.js
const dep = require('./dep.js');
console.log(dep.default);

// input: dep.js
export default 'foo';

// output
var dep = 'foo';

var dep$1 = /*#__PURE__*/Object.freeze({
__proto__: null,
'default': dep
});

console.log(dep$1.default);
```

For these situations, you can change Rollup's behaviour either globally or per module. To change it globally, set the `requireReturnsDefault` option to one of the following values:

- `false`: This is the default, requiring an ES module returns its namespace. For external dependencies, no additional interop code is generated:

```js
// input
const dep = require('dep');
console.log(dep);

// output
import * as dep from 'dep';

console.log(dep);
```

- `"auto"`: This is complementary to how [`output.exports`](https://rollupjs.org/guide/en/#outputexports): `"auto"` works in Rollup: If a module has a default export and no named exports, requiring that module returns the default export. In all other cases, the namespace is returned. For external dependencies, a corresponding interop helper is added:

```js
// output
import * as dep$1 from 'dep';

function getDefaultExportFromNamespaceIfNotNamed (n) {
return n && Object.prototype.hasOwnProperty.call(n, 'default') && Object.keys(n).length === 1 ? n['default'] : n;
}

var dep = getDefaultExportFromNamespaceIfNotNamed(dep$1);

console.log(dep);
```

- `"preferred"`: If a module has a default export, requiring that module always returns the default export, no matter whether additional named exports exist. This is similar to how previous versions of this plugin worked. Again for external dependencies, an interop helper is added:

```js
// output
import * as dep$1 from 'dep';

function getDefaultExportFromNamespaceIfPresent (n) {
return n && Object.prototype.hasOwnProperty.call(n, 'default') ? n['default'] : n;
}

var dep = getDefaultExportFromNamespaceIfPresent(dep$1);

console.log(dep);
```

- `true`: This will always try to return the default export on require without checking if it actually exists. This can throw at build time if there is no default export. The advantage over the other options is that, like `false`, this does not add an interop helper for external dependencies, keeping the code lean:

```js
// output
import dep from 'dep';

console.log(dep);
```

To change this for individual modules, you can supply a function for `requireReturnsDefault` instead. This function will then be called once for each required ES module or external dependency with the corresponding id and allows you to return different values for different modules.

## Using with @rollup/plugin-node-resolve

Since most CommonJS packages you are importing are probably dependencies in `node_modules`, you may need to use [@rollup/plugin-node-resolve](https://github.com/rollup/plugins/tree/master/packages/node-resolve):
Expand Down
4 changes: 2 additions & 2 deletions packages/commonjs/src/proxies.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ export function getUnknownRequireProxy(id, requireReturnsDefault) {
const name = getName(id);
const exported =
requireReturnsDefault === 'auto'
? `import {getDefaultExportFromNamespaceIfNotNamed} from "${HELPERS_ID}"; export default getDefaultExportFromNamespaceIfNotNamed(${name})`
? `import {getDefaultExportFromNamespaceIfNotNamed} from "${HELPERS_ID}"; export default /*@__PURE__*/getDefaultExportFromNamespaceIfNotNamed(${name})`
: requireReturnsDefault === 'preferred'
? `import {getDefaultExportFromNamespaceIfPresent} from "${HELPERS_ID}"; export default getDefaultExportFromNamespaceIfPresent(${name})`
? `import {getDefaultExportFromNamespaceIfPresent} from "${HELPERS_ID}"; export default /*@__PURE__*/getDefaultExportFromNamespaceIfPresent(${name})`
: `export default ${name}`;
return `import * as ${name} from ${JSON.stringify(id)}; ${exported}`;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
const externalNamed = require('external-esm-named');
const externalMixed = require('external-esm-mixed');
const externalDefault = require('external-esm-default');

const namedExports = require('./named.js');
const mixedExports = require('./mixed.js');
const defaultExport = require('./default.js');
const noExports = require('./none.js');

t.deepEqual(namedExports, { foo: 'foo' }, 'named exports');
t.deepEqual(mixedExports, { foo: 'foo', default: 'bar' }, 'mixed exports');
t.deepEqual(defaultExport, 'bar', 'default export');
t.deepEqual(noExports, {}, 'no exports');
t.deepEqual(externalNamed, { foo: 'foo' }, 'external named');
t.deepEqual(externalMixed, { foo: 'foo', default: 'bar' }, 'external mixed');
t.deepEqual(externalDefault, 'bar', 'external default');
Empty file.
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
const externalNamed = require('external-esm-named');
const externalMixed = require('external-esm-mixed');
const externalDefault = require('external-esm-default');

const namedExports = require('./named.js');
const mixedExports = require('./mixed.js');
const defaultExport = require('./default.js');
const noExports = require('./none.js');

t.deepEqual(namedExports, { foo: 'foo' }, 'named exports');
t.deepEqual(mixedExports, { foo: 'foo', default: 'bar' }, 'mixed exports');
t.deepEqual(defaultExport, { default: 'bar' }, 'default export');
t.deepEqual(noExports, {}, 'no exports');
t.deepEqual(externalNamed, { foo: 'foo' }, 'external named');
t.deepEqual(externalMixed, { foo: 'foo', default: 'bar' }, 'external mixed');
t.deepEqual(externalDefault, { default: 'bar' }, 'external default');
Empty file.
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// TODO Lukas do the same with externals
module.exports = {
description: 'allows configuring requireReturnsDefault for externals with a function',
options: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
const externalNamed = require('external-esm-named');
const externalMixed = require('external-esm-mixed');
const externalDefault = require('external-esm-default');

const namedExports = require('./named.js');
const mixedExports = require('./mixed.js');
const defaultExport = require('./default.js');
const noExports = require('./none.js');

t.deepEqual(namedExports, { foo: 'foo' }, 'named exports');
t.deepEqual(mixedExports, 'bar', 'mixed exports');
t.deepEqual(defaultExport, 'bar', 'default export');
t.deepEqual(noExports, {}, 'no exports');
t.deepEqual(externalNamed, { foo: 'foo' }, 'external named');
t.deepEqual(externalMixed, 'bar', 'external mixed');
t.deepEqual(externalDefault, 'bar', 'external default');
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
const externalNamed = require('external-esm-named');
const externalMixed = require('external-esm-mixed');
const externalDefault = require('external-esm-default');

const namedExports = require('./named.js');
const mixedExports = require('./mixed.js');
const defaultExport = require('./default.js');
const noExports = require('./none.js');

t.deepEqual(namedExports, { foo: 'foo' }, 'named exports');
t.deepEqual(mixedExports, { foo: 'foo', default: 'bar' }, 'mixed exports');
t.deepEqual(defaultExport, { default: 'bar' }, 'default export');
t.deepEqual(noExports, {}, 'no exports');
t.deepEqual(externalNamed, { foo: 'foo' }, 'external named');
t.deepEqual(externalMixed, { foo: 'foo', default: 'bar' }, 'external mixed');
t.deepEqual(externalDefault, { default: 'bar' }, 'external default');

0 comments on commit 61c1fc7

Please sign in to comment.