Skip to content

Commit

Permalink
Add option to configure if entry signatures are preserved (#3498)
Browse files Browse the repository at this point in the history
* Refactor some code

* Implement support for preserveEntrySignatures false and 'allow-extension'

* Throw an error if preserveEntrySignatures is set to false for preserveModules

* Add basic documentation

* Show a meaningful warning if an empty facade chunk is created for a user-defined chunk and preserveEntrySignatures has not been set

* Make config file watching more stable

* Add ability to override signature preservation for plugins

* Extend documentation

* Try to improve watch test stability

* Add option to control minification of internal exports
  • Loading branch information
lukastaegert committed Apr 21, 2020
1 parent c0c206e commit 9011204
Show file tree
Hide file tree
Showing 248 changed files with 2,081 additions and 743 deletions.
4 changes: 2 additions & 2 deletions LICENSE.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Repository: https://github.com/acornjs/acorn.git
## acorn-class-fields
License: MIT
By: Adrian Heine
Repository: https://github.com/acornjs/acorn-class-fields
Repository: git+https://github.com/acornjs/acorn-class-fields.git

> Copyright (C) 2017-2018 by Adrian Heine
>
Expand Down Expand Up @@ -166,7 +166,7 @@ Repository: https://github.com/acornjs/acorn-private-class-elements
## acorn-static-class-features
License: MIT
By: Adrian Heine
Repository: https://github.com/acornjs/acorn-static-class-features
Repository: git+https://github.com/acornjs/acorn-static-class-features.git

> Copyright (C) 2017-2018 by Adrian Heine
>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import MagicString from 'magic-string';

export default function addBinShebang() {
export default function addCliEntry() {
return {
name: 'add-bin-shebang',
name: 'add-cli-entry',
buildStart() {
this.emitFile({
type: 'chunk',
id: 'cli/cli.ts',
fileName: 'bin/rollup',
preserveSignature: false
});
},
renderChunk(code, chunkInfo) {
if (chunkInfo.fileName === 'bin/rollup') {
const magicString = new MagicString(code);
Expand Down
File renamed without changes.
9 changes: 7 additions & 2 deletions cli/help.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,27 @@ Basic options:
--no-interop Do not include interop block
--inlineDynamicImports Create single bundle when using dynamic imports
--intro <text> Code to insert at top of bundle (inside wrapper)
--minifyInternalExports Force or disable minification of internal exports
--namespaceToStringTag Create proper `.toString` methods for namespaces
--noConflict Generate a noConflict method for UMD globals
--no-strict Don't emit `"use strict";` in the generated modules
--outro <text> Code to insert at end of bundle (inside wrapper)
--preferConst Use `const` instead of `var` for exports
--no-preserveEntrySignatures Avoid facade chunks for entry points
--preserveModules Preserve module structure
--preserveSymlinks Do not follow symlinks when resolving files
--shimMissingExports Create shim variables for missing exports
--silent Don't print warnings
--sourcemapExcludeSources Do not include source code in source maps
--sourcemapFile <file> Specify bundle position for source maps
--no-stdin do not read "-" from stdin
--no-strict Don't emit `"use strict";` in the generated modules
--strictDeprecations Throw errors for deprecated features
--no-treeshake Disable tree-shaking optimisations
--no-treeshake.annotations Ignore pure call annotations
--no-treeshake.propertyReadSideEffects Ignore property access side-effects
--no-treeshake.no-moduleSideEffects Assume modules have no side-effects
--no-treeshake.no-propertyReadSideEffects Ignore property access side-effects
--no-treeshake.no-tryCatchDeoptimization Do not turn off try-catch-tree-shaking
--no-treeshake.no-unknownGlobalSideEffects Assume unknown globals do not throw

Examples:

Expand Down
6 changes: 4 additions & 2 deletions cli/run/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { MergedRollupOptions } from '../../src/rollup/types';
import { getAliasName } from '../../src/utils/relativeId';
import { loadFsEvents } from '../../src/watch/fsevents-importer';
import { handleError } from '../logging';
import { BatchWarnings } from './batchWarnings';
import build from './build';
import { getConfigPath } from './getConfigPath';
import loadAndParseConfigFile from './loadConfigFile';
import loadConfigFromCommand from './loadConfigFromCommand';
import watch from './watch';

export default async function runRollup(command: any) {
let inputSource;
if (command._.length > 0) {
if (command.input) {
handleError({
code: 'DUPLICATE_IMPORT_OPTIONS',
message: 'Either use --input, or pass input path as argument',
message: 'Either use --input, or pass input path as argument'
});
}
inputSource = command._;
Expand Down Expand Up @@ -57,6 +57,8 @@ export default async function runRollup(command: any) {
}

if (command.watch) {
await loadFsEvents();
const { watch } = await import('./watch-cli');
watch(command);
} else {
try {
Expand Down
12 changes: 5 additions & 7 deletions cli/run/watch.ts → cli/run/watch-cli.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import chokidar from 'chokidar';
import color from 'colorette';
import dateTime from 'date-time';
import fs from 'fs';
Expand All @@ -14,7 +15,7 @@ import loadConfigFromCommand from './loadConfigFromCommand';
import { getResetScreen } from './resetScreen';
import { printTimings } from './timings';

export default async function watch(command: any) {
export async function watch(command: any) {
process.env.ROLLUP_WATCH = 'true';
const isTTY = process.stderr.isTTY;
const silent = command.silent;
Expand All @@ -36,10 +37,7 @@ export default async function watch(command: any) {
let aborted = false;
let configFileData: string | null = null;

configWatcher = fs.watch(configFile, (event: string) => {
if (event === 'change') reloadConfigFile();
});

configWatcher = chokidar.watch(configFile).on('change', () => reloadConfigFile());
await reloadConfigFile();

async function reloadConfigFile() {
Expand Down Expand Up @@ -85,7 +83,7 @@ export default async function watch(command: any) {
function start(configs: MergedRollupOptions[]) {
watcher = rollup.watch(configs as any);

watcher.on('event', (event) => {
watcher.on('event', event => {
switch (event.code) {
case 'ERROR':
warnings.flush();
Expand All @@ -105,7 +103,7 @@ export default async function watch(command: any) {
input = Array.isArray(input)
? input.join(', ')
: Object.keys(input as Record<string, string>)
.map((key) => (input as Record<string, string>)[key])
.map(key => (input as Record<string, string>)[key])
.join(', ');
}
stderr(
Expand Down
2 changes: 1 addition & 1 deletion docs/00-introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Rollup is a module bundler for JavaScript which compiles small pieces of code in
npm install --global rollup
```

⚠️ If you are using TypeScript, we recommend you explicitly list the `@types` packages you want to use using the [`types` property in the "tsconfig.json" file](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html#types-typeroots-and-types), or set it to `[]`. Rollup has a dependency on `@types/node`, which means (without this change) these types will automatically be available in your app even when some of them should not be available based on the `target` you are using.
This will make Rollup available as a global command line tool. You can also install it locally, see [Installing Rollup locally](guide/en/#installing-rollup-locally).

### Quick start

Expand Down
12 changes: 9 additions & 3 deletions docs/01-command-line-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export default { // can be an array (for multiple inputs)
inlineDynamicImports,
manualChunks,
onwarn,
preserveEntrySignatures,
preserveModules,
strictDeprecations,

Expand Down Expand Up @@ -74,6 +75,7 @@ export default { // can be an array (for multiple inputs)
hoistTransitiveImports,
interop,
intro,
minifyInternalExports,
outro,
paths,
sourcemap,
Expand Down Expand Up @@ -292,23 +294,27 @@ Many options have command line equivalents. In those cases, any arguments passed
--no-interop Do not include interop block
--inlineDynamicImports Create single bundle when using dynamic imports
--intro <text> Code to insert at top of bundle (inside wrapper)
--minifyInternalExports Force or disable minification of internal exports
--namespaceToStringTag Create proper `.toString` methods for namespaces
--noConflict Generate a noConflict method for UMD globals
--no-strict Don't emit `"use strict";` in the generated modules
--outro <text> Code to insert at end of bundle (inside wrapper)
--preferConst Use `const` instead of `var` for exports
--no-preserveEntrySignatures Avoid facade chunks for entry points
--preserveModules Preserve module structure
--preserveSymlinks Do not follow symlinks when resolving files
--shimMissingExports Create shim variables for missing exports
--silent Don't print warnings
--sourcemapExcludeSources Do not include source code in source maps
--sourcemapFile <file> Specify bundle position for source maps
--no-stdin do not read "-" from stdin
--no-strict Don't emit `"use strict";` in the generated modules
--strictDeprecations Throw errors for deprecated features
--no-treeshake Disable tree-shaking optimisations
--no-treeshake.annotations Ignore pure call annotations
--no-treeshake.propertyReadSideEffects Ignore property access side-effects
--treeshake.pureExternalModules Assume side-effect free externals
--no-treeshake.no-moduleSideEffects Assume modules have no side-effects
--no-treeshake.no-propertyReadSideEffects Ignore property access side-effects
--no-treeshake.no-tryCatchDeoptimization Do not turn off try-catch-tree-shaking
--no-treeshake.no-unknownGlobalSideEffects Assume unknown globals do not throw
```

The flags listed below are only available via the command line interface. All other flags correspond to and override their config file equivalents, see the [big list of options](guide/en/#big-list-of-options) for details.
Expand Down
2 changes: 2 additions & 0 deletions docs/02-javascript-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ const inputOptions = {
inlineDynamicImports,
manualChunks,
onwarn,
preserveEntrySignatures,
preserveModules,
strictDeprecations,

Expand Down Expand Up @@ -130,6 +131,7 @@ const outputOptions = {
hoistTransitiveImports,
interop,
intro,
minifyInternalExports,
outro,
paths,
sourcemap,
Expand Down
5 changes: 3 additions & 2 deletions docs/05-plugin-development.md
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,7 @@ Emits a new file that is included in the build output and returns a `referenceId
type: 'chunk',
id: string,
importer?: string,
preserveSignature?: 'strict' | 'allow-extension' | false,
name?: string,
fileName?: string
}
Expand All @@ -520,7 +521,7 @@ You can reference the URL of an emitted file in any code returned by a [`load`](
The generated code that replaces `import.meta.ROLLUP_FILE_URL_referenceId` can be customized via the [`resolveFileUrl`](guide/en/#resolvefileurl) plugin hook. You can also use [`this.getFileName(referenceId)`](guide/en/#thisgetfilenamereferenceid-string--string) to determine the file name as soon as it is available
If the `type` is *`chunk`*, then this emits a new chunk with the given module `id` as entry point. To resolve it, the `id` will be passed through build hooks just like regular entry points, starting with [`resolveId`](guide/en/#resolveid). If an `importer` is provided, this acts as the second parameter of `resolveId` and is important to properly resolve relative paths. If it is not provided, paths will be resolved relative to the current working directory.
If the `type` is *`chunk`*, then this emits a new chunk with the given module `id` as entry point. To resolve it, the `id` will be passed through build hooks just like regular entry points, starting with [`resolveId`](guide/en/#resolveid). If an `importer` is provided, this acts as the second parameter of `resolveId` and is important to properly resolve relative paths. If it is not provided, paths will be resolved relative to the current working directory. If a value for `preserveSignature` is provided, this will override [`preserveEntrySignatures`](guide/en/#preserveentrysignatures) for this particular chunk.
This will not result in duplicate modules in the graph, instead if necessary, existing chunks will be split or a facade chunk with reexports will be created. Chunks with a specified `fileName` will always generate separate chunks while other emitted chunks may be deduplicated with existing chunks even if the `name` does not match. If such a chunk is not deduplicated, the [`output.chunkFileNames`](guide/en/#outputchunkfilenames) name pattern will be used.
Expand All @@ -536,7 +537,7 @@ Get the combined source maps of all previous plugins. This context function can
#### `this.getFileName(referenceId: string) => string`
Get the file name of a chunk or asset that has been emitted via [`this.emitFile`](guide/en/#thisemitfileemittedfile-emittedchunk--emittedasset--string) . The file name will be relative to `outputOptions.dir`.
Get the file name of a chunk or asset that has been emitted via [`this.emitFile`](guide/en/#thisemitfileemittedfile-emittedchunk--emittedasset--string). The file name will be relative to `outputOptions.dir`.
#### `this.getModuleInfo(moduleId: string) => ModuleInfo`
Expand Down
142 changes: 142 additions & 0 deletions docs/999-big-list-of-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,69 @@ export default {
};
```

#### output.minifyInternalExports
Type: `boolean`<br>
CLI: `--minifyInternalExports`/`--no-minifyInternalExports`<br>
Default: `true` for formats `es` and `system` or if `output.compact` is `true`, `false` otherwise

By default for formats `es` and `system` or if `output.compact` is `true`, Rollup will try to export internal variables as single letter variables to allow for better minification.

**Example**<br>
Input:

```js
// main.js
import './lib.js';

// lib.js
import('./dynamic.js');
export const value = 42;

// dynamic.js
import {value} from './lib.js';
console.log(value);
```

Output with `output.minifyInternalExports: true`:


```js
// main.js
import './main-5532def0.js';

// main-5532def0.js
import('./dynamic-402de2f0.js');
const importantValue = 42;

export { importantValue as i };

// dynamic-402de2f0.js
import { i as importantValue } from './main-5532def0.js';

console.log(importantValue);
```

Output with `output.minifyInternalExports: false`:


```js
// main.js
import './main-5532def0.js';

// main-5532def0.js
import('./dynamic-402de2f0.js');
const importantValue = 42;

export { importantValue };

// dynamic-402de2f0.js
import { importantValue } from './main-5532def0.js';

console.log(importantValue);
```

Even though it appears that setting this option to `true` makes the output larger, it actually makes it smaller if a minifier is used. In this case, `export { importantValue as i }` can become e.g. `export{a as i}` or even `export{i}`, while otherwise it would produce `export{ a as importantValue }` because a minifier usually will not change export signatures.

#### output.paths
Type: `{ [id: string]: string } | ((id: string) => string)`

Expand Down Expand Up @@ -575,6 +638,85 @@ export default ({
});
```

#### preserveEntrySignatures
Type: `"strict" | "allow-extension" | false`<br>
CLI: `--preserveEntrySignatures <strict|allow-extension>`/`--no-preserveEntrySignatures`<br>
Default: `"strict"`

Controls if Rollup tries to ensure that entry chunks have the same exports as the underlying entry module.

- If set to `"strict"`, Rollup will create exactly the same exports in the entry chunk as there are in the corresponding entry module. If this is not possible because additional internal exports need to be added to a chunk, Rollup will instead create a "facade" entry chunk that reexports just the necessary bindings from other chunks but contains no code otherwise. This is the recommended setting for libraries.
- `"allow-extension"` will create all exports of the entry module in the entry chunk but may also add additional exports if necessary, avoiding a "facade" entry chunk. This setting makes sense for libraries where a strict signature is not required.
- `false` will not add any exports of an entry module to the corresponding chunk and does not even include the corresponding code unless those exports are used elsewhere in the bundle. Internal exports may be added to entry chunks, though. This is the recommended setting for web apps where the entry chunks are to be placed in script tags as it may reduce both the number of chunks and possibly the bundle size.

**Example**<br>
Input:

```js
// main.js
import { shared } from './lib.js';
export const value = `value: ${shared}`;
import('./dynamic.js');

// lib.js
export const shared = 'shared';

// dynamic.js
import { shared } from './lib.js';
console.log(shared);
```

Output for `preserveEntrySignatures: "strict"`:

```js
// main.js
export { v as value } from './main-50a71bb6.js';

// main-50a71bb6.js
const shared = 'shared';

const value = `value: ${shared}`;
import('./dynamic-cd23645f.js');

export { shared as s, value as v };

// dynamic-cd23645f.js
import { s as shared } from './main-50a71bb6.js';

console.log(shared);
```

Output for `preserveEntrySignatures: "allow-extension"`:

```js
// main.js
const shared = 'shared';

const value = `value: ${shared}`;
import('./dynamic-298476ec.js');

export { shared as s, value };

// dynamic-298476ec.js
import { s as shared } from './main.js';

console.log(shared);
```

Output for `preserveEntrySignatures: false`:

```js
// main.js
import('./dynamic-39821cef.js');

// dynamic-39821cef.js
const shared = 'shared';

console.log(shared);
```

At the moment, the only way to override this setting for individual entry chunks is to use the plugin API and emit those chunks via [`this.emitFile`](guide/en/#thisemitfileemittedfile-emittedchunk--emittedasset--string) instead of using the [`input`](guide/en/#input) option.

#### preserveModules
Type: `boolean`<br>
CLI: `--preserveModules`/`--no-preserveModules`<br>
Expand Down
Loading

0 comments on commit 9011204

Please sign in to comment.