Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use export mode "auto" by default when preserving modules #3265

Merged
merged 5 commits into from Nov 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion LICENSE.md
Expand Up @@ -382,7 +382,7 @@ Repository: sindresorhus/pretty-bytes
## pretty-ms
License: MIT
By: Sindre Sorhus
Repository: git+https://github.com/sindresorhus/pretty-ms.git
Repository: sindresorhus/pretty-ms

---------------------------------------

Expand Down
151 changes: 81 additions & 70 deletions cli/run/batchWarnings.ts
Expand Up @@ -82,13 +82,6 @@ const immediateHandlers: {
stderr(
`Creating a browser bundle that depends on ${detail}. You might need to include https://www.npmjs.com/package/rollup-plugin-node-builtins`
);
},

MIXED_EXPORTS: () => {
title('Mixing named and default exports');
stderr(
`Consumers of your bundle will have to use bundle['default'] to access the default export, which may not be what you want. Use \`output.exports: 'named'\` to disable this warning`
);
}
};

Expand All @@ -106,27 +99,19 @@ const deferredHandlers: {
}
},

UNUSED_EXTERNAL_IMPORT(warnings) {
title('Unused external imports');
for (const warning of warnings) {
stderr(`${warning.names} imported from external module '${warning.source}' but never used`);
}
EMPTY_BUNDLE(warnings) {
title(
`Generated${warnings.length === 1 ? ' an' : ''} empty ${
warnings.length > 1 ? 'chunks' : 'chunk'
}`
);
stderr(warnings.map(warning => warning.chunkName!).join(', '));
},

UNRESOLVED_IMPORT(warnings) {
title('Unresolved dependencies');
info('https://rollupjs.org/guide/en/#warning-treating-module-as-external-dependency');

const dependencies = new Map();
for (const warning of warnings) {
if (!dependencies.has(warning.source)) dependencies.set(warning.source, []);
dependencies.get(warning.source).push(warning.importer);
}

for (const dependency of dependencies.keys()) {
const importers = dependencies.get(dependency);
stderr(`${tc.bold(dependency)} (imported by ${importers.join(', ')})`);
}
EVAL(warnings) {
title('Use of eval is strongly discouraged');
info('https://rollupjs.org/guide/en/#avoiding-eval');
showTruncatedWarnings(warnings);
},

MISSING_EXPORT(warnings) {
Expand All @@ -140,21 +125,32 @@ const deferredHandlers: {
}
},

THIS_IS_UNDEFINED(warnings) {
title('`this` has been rewritten to `undefined`');
info('https://rollupjs.org/guide/en/#error-this-is-undefined');
showTruncatedWarnings(warnings);
},

EVAL(warnings) {
title('Use of eval is strongly discouraged');
info('https://rollupjs.org/guide/en/#avoiding-eval');
showTruncatedWarnings(warnings);
MISSING_GLOBAL_NAME(warnings) {
title(`Missing global variable ${warnings.length > 1 ? 'names' : 'name'}`);
stderr(
`Use output.globals to specify browser global variable names corresponding to external modules`
);
for (const warning of warnings) {
stderr(`${tc.bold(warning.source!)} (guessing '${warning.guess}')`);
}
},

NON_EXISTENT_EXPORT(warnings) {
title(`Import of non-existent ${warnings.length > 1 ? 'exports' : 'export'}`);
showTruncatedWarnings(warnings);
MIXED_EXPORTS: (warnings) => {
title('Mixing named and default exports');
info(`https://rollupjs.org/guide/en/#output-exports`);
stderr(
tc.bold('The following entry modules are using named and default exports together:')
);
const displayedWarnings = warnings.length > 5 ? warnings.slice(0, 3) : warnings;
for (const warning of displayedWarnings) {
stderr(relativeId(warning.id!));
}
if (displayedWarnings.length < warnings.length) {
stderr(`...and ${warnings.length - displayedWarnings.length} other entry modules`);
}
stderr(
`\nConsumers of your bundle will have to use chunk['default'] to access their default export, which may not be what you want. Use \`output.exports: 'named'\` to disable this warning`
);
},

NAMESPACE_CONFLICT(warnings) {
Expand All @@ -170,30 +166,9 @@ const deferredHandlers: {
}
},

MISSING_GLOBAL_NAME(warnings) {
title(`Missing global variable ${warnings.length > 1 ? 'names' : 'name'}`);
stderr(
`Use output.globals to specify browser global variable names corresponding to external modules`
);
for (const warning of warnings) {
stderr(`${tc.bold(warning.source!)} (guessing '${warning.guess}')`);
}
},

SOURCEMAP_BROKEN(warnings) {
title(`Broken sourcemap`);
info('https://rollupjs.org/guide/en/#warning-sourcemap-is-likely-to-be-incorrect');

const plugins = Array.from(new Set(warnings.map(w => w.plugin).filter(Boolean)));
const detail =
plugins.length > 1
? ` (such as ${plugins
.slice(0, -1)
.map(p => `'${p}'`)
.join(', ')} and '${plugins.slice(-1)}')`
: ` (such as '${plugins[0]}')`;

stderr(`Plugins that transform code${detail} should generate accompanying sourcemaps`);
NON_EXISTENT_EXPORT(warnings) {
title(`Import of non-existent ${warnings.length > 1 ? 'exports' : 'export'}`);
showTruncatedWarnings(warnings);
},

PLUGIN_WARNING(warnings) {
Expand Down Expand Up @@ -222,13 +197,49 @@ const deferredHandlers: {
}
},

EMPTY_BUNDLE(warnings) {
title(
`Generated${warnings.length === 1 ? ' an' : ''} empty ${
warnings.length > 1 ? 'chunks' : 'chunk'
}`
);
stderr(warnings.map(warning => warning.chunkName!).join(', '));
SOURCEMAP_BROKEN(warnings) {
title(`Broken sourcemap`);
info('https://rollupjs.org/guide/en/#warning-sourcemap-is-likely-to-be-incorrect');

const plugins = Array.from(new Set(warnings.map(w => w.plugin).filter(Boolean)));
const detail =
plugins.length > 1
? ` (such as ${plugins
.slice(0, -1)
.map(p => `'${p}'`)
.join(', ')} and '${plugins.slice(-1)}')`
: ` (such as '${plugins[0]}')`;

stderr(`Plugins that transform code${detail} should generate accompanying sourcemaps`);
},

THIS_IS_UNDEFINED(warnings) {
title('`this` has been rewritten to `undefined`');
info('https://rollupjs.org/guide/en/#error-this-is-undefined');
showTruncatedWarnings(warnings);
},

UNRESOLVED_IMPORT(warnings) {
title('Unresolved dependencies');
info('https://rollupjs.org/guide/en/#warning-treating-module-as-external-dependency');

const dependencies = new Map();
for (const warning of warnings) {
if (!dependencies.has(warning.source)) dependencies.set(warning.source, []);
dependencies.get(warning.source).push(warning.importer);
}

for (const dependency of dependencies.keys()) {
const importers = dependencies.get(dependency);
stderr(`${tc.bold(dependency)} (imported by ${importers.join(', ')})`);
}
},

UNUSED_EXTERNAL_IMPORT(warnings) {
title('Unused external imports');
for (const warning of warnings) {
stderr(`${warning.names} imported from external module '${warning.source}' but never used`);
}
}
};

Expand Down
16 changes: 16 additions & 0 deletions docs/01-command-line-reference.md
Expand Up @@ -187,6 +187,22 @@ export default commandLineArgs => {

If you now run `rollup --config --configDebug`, the debug configuration will be used.

By default, command line arguments will always override the respective values exported from a config file. If you want to change this behaviour, you can make Rollup ignore command line arguments by deleting them from the `commandLineArgs` object:

```javascript
// rollup.config.js
export default commandLineArgs => {
const inputBase = commandLineArgs.input || 'main.js';

// this will make Rollup ignore the CLI argument
delete commandLineArgs.input;
return {
input: 'src/entries/' + inputBase,
output: {...}
}
}
```


### Command line flags

Expand Down
42 changes: 42 additions & 0 deletions docs/999-big-list-of-options.md
Expand Up @@ -572,6 +572,48 @@ Default: `false`

Instead of creating as few chunks as possible, this mode will create separate chunks for all modules using the original module names as file names. Requires the [`output.dir`](guide/en/#outputdir) option. Tree-shaking will still be applied, suppressing files that are not used by the provided entry points or do not have side-effects when executed. This mode can be used to transform a file structure to a different module format.

Note that when transforming to `cjs` or `amd` format, each file will by default be treated as an entry point with [`output.exports`](guide/en/#outputexports) set to `auto`. This means that e.g. for `cjs`, a file that only contains a default export will be rendered as

```js
// input main.js
export default 42;

// output main.js
'use strict';

var main = 42;

module.exports = main;
```

assigning the value directly to `module.exports`. If someone imports this file, they will get access to the default export via

```js
const main = require('./main.js');
console.log(main); // 42
```

As with regular entry points, files that mix default and named exports will produce warnings. You can avoid the warnings by forcing all files to use named export mode via `output.exports: "named"`. In that case, the default export needs to be accessed via the `.default` property of the export:

```js
// input main.js
export default 42;

// output main.js
'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var main = 42;

exports.default = main;

// consuming file
const main = require('./main.js');
console.log(main.default); // 42
```


#### strictDeprecations
Type: `boolean`<br>
CLI: `--strictDeprecations`/`--no-strictDeprecations`<br>
Expand Down
6 changes: 4 additions & 2 deletions src/Chunk.ts
Expand Up @@ -619,7 +619,7 @@ export default class Chunk {
this.renderedSourceLength = undefined as any;
this.renderedHash = undefined as any;

if (this.getExportNames().length === 0 && this.getImportIds().length === 0 && this.isEmpty) {
if (this.isEmpty && this.getExportNames().length === 0 && this.dependencies.length === 0) {
const chunkName = this.getChunkName();
this.graph.warn({
chunkName,
Expand Down Expand Up @@ -708,7 +708,9 @@ export default class Chunk {
hasExports,
indentString: this.indentString,
intro: addons.intro as string,
isEntryModuleFacade: this.facadeModule !== null && this.facadeModule.isEntryPoint,
isEntryModuleFacade:
this.graph.preserveModules ||
(this.facadeModule !== null && this.facadeModule.isEntryPoint),
namedExportsMode: this.exportMode !== 'default',
outro: addons.outro as string,
usesTopLevelAwait,
Expand Down
1 change: 1 addition & 0 deletions src/finalisers/shared/getExportBlock.ts
Expand Up @@ -23,6 +23,7 @@ export default function getExportBlock(
dep.namedExportsMode && expt.imported !== '*' && expt.imported !== 'default'
? `${dep.name}.${expt.imported}`
: dep.name;
break;
}
}
}
Expand Down
18 changes: 14 additions & 4 deletions src/rollup/index.ts
Expand Up @@ -5,7 +5,12 @@ import Graph from '../Graph';
import { createAddons } from '../utils/addons';
import { assignChunkIds } from '../utils/assignChunkIds';
import commondir from '../utils/commondir';
import { errCannotEmitFromOptionsHook, errDeprecation, error } from '../utils/error';
import {
errCannotEmitFromOptionsHook,
errDeprecation,
errInvalidExportOptionValue,
error
} from '../utils/error';
import { writeFile } from '../utils/fs';
import getExportMode from '../utils/getExportMode';
import mergeOptions, { GenericConfigObject } from '../utils/mergeOptions';
Expand Down Expand Up @@ -45,6 +50,10 @@ function checkOutputOptions(options: OutputOptions) {
url: `https://rollupjs.org/guide/en/#output-format`
});
}

if (options.exports && !['default', 'named', 'none', 'auto'].includes(options.exports)) {
error(errInvalidExportOptionValue(options.exports));
}
}

function getAbsoluteEntryModulePaths(chunks: Chunk[]): string[] {
Expand Down Expand Up @@ -259,8 +268,8 @@ export default async function rollup(rawInputOptions: GenericConfigObject): Prom
const addons = await createAddons(outputOptions, outputPluginDriver);
for (const chunk of chunks) {
if (!inputOptions.preserveModules) chunk.generateInternalExports(outputOptions);
if (chunk.facadeModule && chunk.facadeModule.isEntryPoint)
chunk.exportMode = getExportMode(chunk, outputOptions);
if (inputOptions.preserveModules || (chunk.facadeModule && chunk.facadeModule.isEntryPoint))
chunk.exportMode = getExportMode(chunk, outputOptions, chunk.facadeModule!.id);
}
for (const chunk of chunks) {
chunk.preRender(outputOptions, inputBase);
Expand Down Expand Up @@ -403,7 +412,8 @@ function createOutput(outputBundle: Record<string, OutputChunk | OutputAsset | {
.map(fileName => outputBundle[fileName])
.filter(outputFile => Object.keys(outputFile).length > 0) as (
| OutputChunk
| OutputAsset)[]).sort((outputFileA, outputFileB) => {
| OutputAsset
)[]).sort((outputFileA, outputFileB) => {
const fileTypeA = getSortingFileType(outputFileA);
const fileTypeB = getSortingFileType(outputFileB);
if (fileTypeA === fileTypeB) return 0;
Expand Down