From 61e29b3e55e8b7e295f9ea3754c7d9e2c140d737 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sun, 11 Nov 2018 16:12:58 +0100 Subject: [PATCH 01/23] Split up misc tests --- test/misc/acorn-plugins.js | 124 +++++++ test/misc/deprecations.js | 93 +++++ test/misc/in-memory-sourcemaps.js | 33 ++ test/misc/index.js | 589 +----------------------------- test/misc/misc.js | 73 ++++ test/misc/sanity-checks.js | 159 ++++++++ test/misc/write-bundle.js | 116 ++++++ 7 files changed, 604 insertions(+), 583 deletions(-) create mode 100644 test/misc/acorn-plugins.js create mode 100644 test/misc/deprecations.js create mode 100644 test/misc/in-memory-sourcemaps.js create mode 100644 test/misc/misc.js create mode 100644 test/misc/sanity-checks.js create mode 100644 test/misc/write-bundle.js diff --git a/test/misc/acorn-plugins.js b/test/misc/acorn-plugins.js new file mode 100644 index 00000000000..1cb8a9f7d9c --- /dev/null +++ b/test/misc/acorn-plugins.js @@ -0,0 +1,124 @@ +const assert = require('assert'); +const rollup = require('../../dist/rollup'); +const { executeBundle, loader } = require('../utils.js'); + +describe('acorn plugins', () => { + // Acorn registers plugins globally per process. The tests in this suite + // use unique plugin names to make sure each plugin is registered in its + // proper test rather than in a test that ran earlier. + + it('injects plugins passed in acornInjectPlugins', () => { + let pluginAInjected = false; + let pluginBInjected = false; + + return rollup + .rollup({ + input: 'x.js', + plugins: [loader({ 'x.js': `export default 42` })], + acornInjectPlugins: [ + function pluginA(acorn) { + pluginAInjected = true; + return acorn; + }, + function pluginB(acorn) { + pluginBInjected = true; + return acorn; + } + ] + }) + .then(executeBundle) + .then(result => { + assert.equal(result, 42); + assert( + pluginAInjected, + 'A plugin passed via acornInjectPlugins should inject itself into Acorn.' + ); + assert( + pluginBInjected, + 'A plugin passed via acornInjectPlugins should inject itself into Acorn.' + ); + }); + }); + + it('injected plugins are registered with Acorn only if acorn.plugins is set', () => { + let pluginCRegistered = false; + let pluginDRegistered = false; + + function pluginC(acorn) { + acorn.plugins.pluginC = () => (pluginCRegistered = true); + return acorn; + } + + function pluginD(acorn) { + acorn.plugins.pluginD = () => (pluginDRegistered = true); + return acorn; + } + + return rollup + .rollup({ + input: 'x.js', + plugins: [loader({ 'x.js': `export default 42` })], + acorn: { + plugins: { + pluginC: true + } + }, + acornInjectPlugins: [pluginC, pluginD] + }) + .then(executeBundle) + .then(result => { + assert.equal(result, 42); + assert.equal( + pluginCRegistered, + true, + 'A plugin enabled in acorn.plugins should register with Acorn.' + ); + assert.equal( + pluginDRegistered, + false, + 'A plugin not enabled in acorn.plugins should not register with Acorn.' + ); + }); + }); + + it('throws if acorn.plugins is set and acornInjectPlugins is missing', () => { + return rollup + .rollup({ + input: 'x.js', + plugins: [loader({ 'x.js': `export default 42` })], + acorn: { + plugins: { + pluginE: true + } + } + }) + .then(executeBundle) + .then(() => { + throw new Error('Missing expected error'); + }) + .catch(error => { + assert.equal(error.message, "Plugin 'pluginE' not found"); + }); + }); + + it('throws if acorn.plugins is set and acornInjectPlugins is empty', () => { + return rollup + .rollup({ + input: 'x.js', + plugins: [loader({ 'x.js': `export default 42` })], + acorn: { + plugins: { + pluginF: true + } + }, + acornInjectPlugins: [] + }) + .then(executeBundle) + .then(() => { + throw new Error('Missing expected error'); + }) + .catch(error => { + assert.equal(error.message, "Plugin 'pluginF' not found"); + }); + }); +}); diff --git a/test/misc/deprecations.js b/test/misc/deprecations.js new file mode 100644 index 00000000000..0740aef7084 --- /dev/null +++ b/test/misc/deprecations.js @@ -0,0 +1,93 @@ +const assert = require('assert'); +const rollup = require('../../dist/rollup'); +const { executeBundle, loader } = require('../utils.js'); + +describe('deprecations', () => { + it('warns on options.entry, but handles', () => { + const warnings = []; + return rollup + .rollup({ + entry: 'x', + plugins: [loader({ x: `export default 42` })], + onwarn: warning => { + warnings.push(warning); + } + }) + .then(executeBundle) + .then(result => { + assert.equal(result, 42); + assert.deepEqual(warnings, [ + { + code: 'DEPRECATED_OPTIONS', + deprecations: [ + { + new: 'input', + old: 'entry' + } + ], + message: `The following options have been renamed — please update your config: entry -> input` + } + ]); + }); + }); + + it('adds deprecations correctly for rollup', () => { + const warnings = []; + return rollup + .rollup({ + entry: 'x', + format: 'cjs', + indent: true, + sourceMap: true, + plugins: [loader({ x: `export default 42` })], + onwarn: warning => { + warnings.push(warning); + } + }) + .then(executeBundle) + .then(result => { + assert.equal(result, 42); + const deprecations = warnings[0].deprecations; + assert.equal(deprecations.length, 4); + assert.deepEqual(deprecations, [ + { new: 'input', old: 'entry' }, + { new: 'output.indent', old: 'indent' }, + { new: 'output.sourcemap', old: 'sourceMap' }, + { new: 'output.format', old: 'format' } + ]); + }); + }); + + it('throws a useful error on accessing code/map properties of bundle.generate promise', () => { + return rollup + .rollup({ + input: 'x', + plugins: [loader({ x: `console.log( 42 );` })] + }) + .then(bundle => { + let errored = false; + + try { + const { code, map } = bundle.generate({ format: 'es' }); + console.log(code, map); + } catch (err) { + assert.equal( + err.message, + `bundle.generate(...) now returns a Promise instead of a { code, map } object` + ); + errored = true; + } + + assert.ok(errored); + }); + }); + + it('supports esm format alias', () => { + return rollup + .rollup({ input: 'x', plugins: [loader({ x: 'export const x = function () {}' })] }) + .then(bundle => bundle.generate({ format: 'esm' })) + .then(({ code }) => { + assert.equal(code, 'const x = function () {};\n\nexport { x };\n'); + }); + }); +}); diff --git a/test/misc/in-memory-sourcemaps.js b/test/misc/in-memory-sourcemaps.js new file mode 100644 index 00000000000..2fb9308494a --- /dev/null +++ b/test/misc/in-memory-sourcemaps.js @@ -0,0 +1,33 @@ +const assert = require('assert'); +const path = require('path'); +const rollup = require('../../dist/rollup'); +const { loader } = require('../utils.js'); +const { SourceMapConsumer } = require('source-map'); +const { getLocator } = require('locate-character'); + +describe('in-memory sourcemaps', () => { + it('generates an in-memory sourcemap', () => { + return rollup + .rollup({ + input: 'main', + plugins: [loader({ main: `console.log( 42 );` })] + }) + .then(bundle => { + return bundle.generate({ + format: 'cjs', + sourcemap: true, + sourcemapFile: path.resolve('bundle.js') + }); + }) + .then(generated => { + const smc = new SourceMapConsumer(generated.map); + const locator = getLocator(generated.code, { offsetLine: 1 }); + + const generatedLoc = locator('42'); + const loc = smc.originalPositionFor(generatedLoc); // 42 + assert.equal(loc.source, 'main'); + assert.equal(loc.line, 1); + assert.equal(loc.column, 13); + }); + }); +}); diff --git a/test/misc/index.js b/test/misc/index.js index 447e667e1b8..3479a3643b9 100644 --- a/test/misc/index.js +++ b/test/misc/index.js @@ -1,583 +1,6 @@ -const assert = require('assert'); -const path = require('path'); -const rollup = require('../../dist/rollup'); -const { executeBundle, loader } = require('../utils.js'); -const { SourceMapConsumer } = require('source-map'); -const { getLocator } = require('locate-character'); - -describe('sanity checks', () => { - it('exists', () => { - assert.ok(!!rollup); - }); - - it('has a rollup method', () => { - assert.equal(typeof rollup.rollup, 'function'); - }); - - it('fails without options', () => { - return rollup - .rollup() - .then(() => { - throw new Error('Missing expected error'); - }) - .catch(err => { - assert.equal(err.message, 'You must supply an options object to rollup'); - }); - }); - - it('node API passes warning and default handler to custom onwarn function', () => { - let args = []; - return rollup - .rollup({ - entry: 'x', - plugins: [loader({ x: `console.log( 42 );` })], - onwarn(warning, onwarn) { - args = [warning, onwarn]; - } - }) - .then(() => { - assert.deepEqual(args[0], { - code: 'DEPRECATED_OPTIONS', - deprecations: [ - { - new: 'input', - old: 'entry' - } - ], - message: `The following options have been renamed — please update your config: entry -> input` - }); - assert.equal(typeof args[1], 'function'); - }); - }); - - it('fails without options.input', () => { - return rollup - .rollup({}) - .then(() => { - throw new Error('Missing expected error'); - }) - .catch(err => { - assert.equal(err.message, 'You must supply options.input to rollup'); - }); - }); - - it('fails with invalid keys', () => { - const warnings = []; - const onwarn = warning => warnings.push(warning); - return rollup - .rollup({ input: 'x', onwarn, plUgins: [], plugins: [loader({ x: `console.log( 42 );` })] }) - .then(() => { - assert.deepEqual(warnings, [ - { - code: 'UNKNOWN_OPTION', - message: - 'Unknown input option: plUgins. Allowed options: ' + require('./optionList').input - } - ]); - }); - }); - - it('treats Literals as leaf nodes, even if first literal encountered is null', () => { - // this test has to be up here, otherwise the bug doesn't have - // an opportunity to present itself - return rollup.rollup({ - input: 'x', - plugins: [loader({ x: `var a = null; a = 'a string';` })] - }); - }); - - it('includes a newline at the end of the bundle', () => { - return rollup - .rollup({ - input: 'x', - plugins: [loader({ x: `console.log( 42 );` })] - }) - .then(bundle => { - return bundle.generate({ format: 'iife' }); - }) - .then(({ code }) => { - assert.ok(code[code.length - 1] === '\n'); - }); - }); - - it('throws on missing output options', () => { - const warnings = []; - - return rollup - .rollup({ - input: 'x', - plugins: [loader({ x: `console.log( 42 );` })], - onwarn: warning => warnings.push(warning) - }) - .then(bundle => { - assert.throws(() => { - bundle.generate(); - }, /You must supply an options object/); - }); - }); - - it('throws on missing format option', () => { - const warnings = []; - - return rollup - .rollup({ - input: 'x', - plugins: [loader({ x: `console.log( 42 );` })], - onwarn: warning => warnings.push(warning) - }) - .then(bundle => { - assert.throws(() => { - bundle.generate({ file: 'x' }); - }, /You must specify output\.format, which can be one of 'amd', 'cjs', 'system', 'esm', 'iife' or 'umd'/); - }); - }); - - it('reuses existing error object', () => { - let error; - - class CustomError extends Error { - constructor(message, x) { - super(message); - this.prop = x.toUpperCase(); - } - } - - return rollup - .rollup({ - input: 'x', - plugins: [ - loader({ x: `console.log( 42 );` }), - { - transform(code) { - error = new CustomError('foo', 'bar'); - this.error(error); - } - } - ] - }) - .catch(e => { - assert.equal(e, error); - }); - }); -}); - -describe('in-memory sourcemaps', () => { - it('generates an in-memory sourcemap', () => { - return rollup - .rollup({ - input: 'main', - plugins: [loader({ main: `console.log( 42 );` })] - }) - .then(bundle => { - return bundle.generate({ - format: 'cjs', - sourcemap: true, - sourcemapFile: path.resolve('bundle.js') - }); - }) - .then(generated => { - const smc = new SourceMapConsumer(generated.map); - const locator = getLocator(generated.code, { offsetLine: 1 }); - - const generatedLoc = locator('42'); - const loc = smc.originalPositionFor(generatedLoc); // 42 - assert.equal(loc.source, 'main'); - assert.equal(loc.line, 1); - assert.equal(loc.column, 13); - }); - }); -}); - -describe('deprecations', () => { - it('warns on options.entry, but handles', () => { - const warnings = []; - return rollup - .rollup({ - entry: 'x', - plugins: [loader({ x: `export default 42` })], - onwarn: warning => { - warnings.push(warning); - } - }) - .then(executeBundle) - .then(result => { - assert.equal(result, 42); - assert.deepEqual(warnings, [ - { - code: 'DEPRECATED_OPTIONS', - deprecations: [ - { - new: 'input', - old: 'entry' - } - ], - message: `The following options have been renamed — please update your config: entry -> input` - } - ]); - }); - }); - - it('adds deprecations correctly for rollup', () => { - const warnings = []; - return rollup - .rollup({ - entry: 'x', - format: 'cjs', - indent: true, - sourceMap: true, - plugins: [loader({ x: `export default 42` })], - onwarn: warning => { - warnings.push(warning); - } - }) - .then(executeBundle) - .then(result => { - assert.equal(result, 42); - const deprecations = warnings[0].deprecations; - assert.equal(deprecations.length, 4); - assert.deepEqual(deprecations, [ - { new: 'input', old: 'entry' }, - { new: 'output.indent', old: 'indent' }, - { new: 'output.sourcemap', old: 'sourceMap' }, - { new: 'output.format', old: 'format' } - ]); - }); - }); - - it('throws a useful error on accessing code/map properties of bundle.generate promise', () => { - return rollup - .rollup({ - input: 'x', - plugins: [loader({ x: `console.log( 42 );` })] - }) - .then(bundle => { - let errored = false; - - try { - const { code, map } = bundle.generate({ format: 'es' }); - console.log(code, map); - } catch (err) { - assert.equal( - err.message, - `bundle.generate(...) now returns a Promise instead of a { code, map } object` - ); - errored = true; - } - - assert.ok(errored); - }); - }); - - it('supports esm format alias', () => { - return rollup - .rollup({ input: 'x', plugins: [loader({ x: 'export const x = function () {}' })] }) - .then(bundle => bundle.generate({ format: 'esm' })) - .then(({ code }) => { - assert.equal(code, 'const x = function () {};\n\nexport { x };\n'); - }); - }); -}); - -describe('bundle.write()', () => { - it('fails without options or options.file', () => { - return rollup - .rollup({ - input: 'x', - plugins: [ - { - resolveId: () => { - return 'test'; - }, - load: () => { - return '// empty'; - } - } - ] - }) - .then(bundle => { - assert.throws(() => { - bundle.write(); - }, /You must specify output\.file/); - - assert.throws(() => { - bundle.write({}); - }, /You must specify output\.file/); - }); - }); - - it('expects output.name for IIFE and UMD bundles', () => { - let bundle; - - return rollup - .rollup({ - input: 'x', - plugins: [ - { - resolveId: () => { - return 'test'; - }, - load: () => { - return 'export var foo = 42;'; - } - } - ] - }) - .then(rollupInstance => { - bundle = rollupInstance; - return bundle.generate({ - format: 'umd' - }); - }) - .catch(err => { - assert.throws(() => { - throw err; - }, /You must supply output\.name for UMD bundles/); - }) - .then(() => { - return bundle.generate({ - format: 'iife' - }); - }) - .catch(err => { - assert.throws(() => { - throw err; - }, /You must supply output\.name for IIFE bundles/); - }); - }); - - it('throws on es6 format', () => { - return rollup - .rollup({ - input: 'x', - plugins: [ - { - resolveId: () => { - return 'test'; - }, - load: () => { - return '// empty'; - } - } - ] - }) - .then(bundle => { - assert.throws(() => { - return bundle.generate({ format: 'es6' }); - }, /The `es6` output format is deprecated – use `es` instead/); - }); - }); - - it('works when output options is an array', () => { - const warnings = []; - const options = { - input: 'x', - plugins: [loader({ x: `console.log( 42 );` })], - onwarn: warning => warnings.push(warning), - output: [ - { - format: 'cjs' - }, - { - format: 'es' - } - ] - }; - return rollup.rollup(options).then(bundle => { - assert.equal(warnings.length, 0, 'No warnings for UNKNOWN'); - assert.throws(() => { - return Promise.all(options.output.map(o => bundle.write(o))); - }, /You must specify output\.file/); - }); - }); -}); - -describe('acorn plugins', () => { - // Acorn registers plugins globally per process. The tests in this suite - // use unique plugin names to make sure each plugin is registered in its - // proper test rather than in a test that ran earlier. - - it('injects plugins passed in acornInjectPlugins', () => { - let pluginAInjected = false; - let pluginBInjected = false; - - return rollup - .rollup({ - input: 'x.js', - plugins: [loader({ 'x.js': `export default 42` })], - acornInjectPlugins: [ - function pluginA(acorn) { - pluginAInjected = true; - return acorn; - }, - function pluginB(acorn) { - pluginBInjected = true; - return acorn; - } - ] - }) - .then(executeBundle) - .then(result => { - assert.equal(result, 42); - assert( - pluginAInjected, - 'A plugin passed via acornInjectPlugins should inject itself into Acorn.' - ); - assert( - pluginBInjected, - 'A plugin passed via acornInjectPlugins should inject itself into Acorn.' - ); - }); - }); - - it('injected plugins are registered with Acorn only if acorn.plugins is set', () => { - let pluginCRegistered = false; - let pluginDRegistered = false; - - function pluginC(acorn) { - acorn.plugins.pluginC = () => (pluginCRegistered = true); - return acorn; - } - - function pluginD(acorn) { - acorn.plugins.pluginD = () => (pluginDRegistered = true); - return acorn; - } - - return rollup - .rollup({ - input: 'x.js', - plugins: [loader({ 'x.js': `export default 42` })], - acorn: { - plugins: { - pluginC: true - } - }, - acornInjectPlugins: [pluginC, pluginD] - }) - .then(executeBundle) - .then(result => { - assert.equal(result, 42); - assert.equal( - pluginCRegistered, - true, - 'A plugin enabled in acorn.plugins should register with Acorn.' - ); - assert.equal( - pluginDRegistered, - false, - 'A plugin not enabled in acorn.plugins should not register with Acorn.' - ); - }); - }); - - it('throws if acorn.plugins is set and acornInjectPlugins is missing', () => { - return rollup - .rollup({ - input: 'x.js', - plugins: [loader({ 'x.js': `export default 42` })], - acorn: { - plugins: { - pluginE: true - } - } - }) - .then(executeBundle) - .then(() => { - throw new Error('Missing expected error'); - }) - .catch(error => { - assert.equal(error.message, "Plugin 'pluginE' not found"); - }); - }); - - it('throws if acorn.plugins is set and acornInjectPlugins is empty', () => { - return rollup - .rollup({ - input: 'x.js', - plugins: [loader({ 'x.js': `export default 42` })], - acorn: { - plugins: { - pluginF: true - } - }, - acornInjectPlugins: [] - }) - .then(executeBundle) - .then(() => { - throw new Error('Missing expected error'); - }) - .catch(error => { - assert.equal(error.message, "Plugin 'pluginF' not found"); - }); - }); -}); - -describe('misc', () => { - it('warns if node builtins are unresolved in a non-CJS, non-ES bundle (#1051)', () => { - const warnings = []; - - return rollup - .rollup({ - input: 'input', - plugins: [ - loader({ - input: `import { format } from 'util';\nexport default format( 'this is a %s', 'formatted string' );` - }) - ], - onwarn: warning => warnings.push(warning) - }) - .then(bundle => - bundle.generate({ - format: 'iife', - name: 'myBundle' - }) - ) - .then(() => { - const relevantWarnings = warnings.filter( - warning => warning.code === 'MISSING_NODE_BUILTINS' - ); - assert.equal(relevantWarnings.length, 1); - assert.equal( - relevantWarnings[0].message, - `Creating a browser bundle that depends on Node.js built-in module ('util'). You might need to include https://www.npmjs.com/package/rollup-plugin-node-builtins` - ); - }); - }); - - it('warns when globals option is specified and a global module name is guessed in a UMD bundle (#2358)', () => { - const warnings = []; - - return rollup - .rollup({ - input: 'input', - plugins: [ - loader({ - input: `import * as _ from 'lodash'` - }) - ], - onwarn: warning => warnings.push(warning) - }) - .then(bundle => - bundle.generate({ - format: 'umd', - globals: [], - name: 'myBundle' - }) - ) - .then(() => { - const relevantWarnings = warnings.filter(warning => warning.code === 'MISSING_GLOBAL_NAME'); - assert.equal(relevantWarnings.length, 1); - assert.equal( - relevantWarnings[0].message, - `No name was provided for external module 'lodash' in output.globals – guessing 'lodash'` - ); - }); - }); - - it('ignores falsy plugins', () => { - return rollup.rollup({ - input: 'x', - plugins: [loader({ x: `console.log( 42 );` }), null, false, undefined] - }); - }); -}); +require('./acorn-plugins'); +require('./deprecations'); +require('./in-memory-sourcemaps'); +require('./misc'); +require('./sanity-checks'); +require('./write-bundle'); diff --git a/test/misc/misc.js b/test/misc/misc.js new file mode 100644 index 00000000000..1f3d335773e --- /dev/null +++ b/test/misc/misc.js @@ -0,0 +1,73 @@ +const assert = require('assert'); +const rollup = require('../../dist/rollup'); +const { loader } = require('../utils.js'); + +describe('misc', () => { + it('warns if node builtins are unresolved in a non-CJS, non-ES bundle (#1051)', () => { + const warnings = []; + + return rollup + .rollup({ + input: 'input', + plugins: [ + loader({ + input: `import { format } from 'util';\nexport default format( 'this is a %s', 'formatted string' );` + }) + ], + onwarn: warning => warnings.push(warning) + }) + .then(bundle => + bundle.generate({ + format: 'iife', + name: 'myBundle' + }) + ) + .then(() => { + const relevantWarnings = warnings.filter( + warning => warning.code === 'MISSING_NODE_BUILTINS' + ); + assert.equal(relevantWarnings.length, 1); + assert.equal( + relevantWarnings[0].message, + `Creating a browser bundle that depends on Node.js built-in module ('util'). You might need to include https://www.npmjs.com/package/rollup-plugin-node-builtins` + ); + }); + }); + + it('warns when globals option is specified and a global module name is guessed in a UMD bundle (#2358)', () => { + const warnings = []; + + return rollup + .rollup({ + input: 'input', + plugins: [ + loader({ + input: `import * as _ from 'lodash'` + }) + ], + onwarn: warning => warnings.push(warning) + }) + .then(bundle => + bundle.generate({ + format: 'umd', + globals: [], + name: 'myBundle' + }) + ) + .then(() => { + const relevantWarnings = warnings.filter(warning => warning.code === 'MISSING_GLOBAL_NAME'); + assert.equal(relevantWarnings.length, 1); + assert.equal( + relevantWarnings[0].message, + `No name was provided for external module 'lodash' in output.globals – guessing 'lodash'` + ); + }); + }); + + it('ignores falsy plugins', () => { + return rollup.rollup({ + input: 'x', + plugins: [loader({ x: `console.log( 42 );` }), null, false, undefined] + }); + }); +}); diff --git a/test/misc/sanity-checks.js b/test/misc/sanity-checks.js new file mode 100644 index 00000000000..5bab7c44483 --- /dev/null +++ b/test/misc/sanity-checks.js @@ -0,0 +1,159 @@ +const assert = require('assert'); +const rollup = require('../../dist/rollup'); +const { loader } = require('../utils.js'); + +describe('sanity checks', () => { + it('exists', () => { + assert.ok(!!rollup); + }); + + it('has a rollup method', () => { + assert.equal(typeof rollup.rollup, 'function'); + }); + + it('fails without options', () => { + return rollup + .rollup() + .then(() => { + throw new Error('Missing expected error'); + }) + .catch(err => { + assert.equal(err.message, 'You must supply an options object to rollup'); + }); + }); + + it('node API passes warning and default handler to custom onwarn function', () => { + let args = []; + return rollup + .rollup({ + entry: 'x', + plugins: [loader({ x: `console.log( 42 );` })], + onwarn(warning, onwarn) { + args = [warning, onwarn]; + } + }) + .then(() => { + assert.deepEqual(args[0], { + code: 'DEPRECATED_OPTIONS', + deprecations: [ + { + new: 'input', + old: 'entry' + } + ], + message: `The following options have been renamed — please update your config: entry -> input` + }); + assert.equal(typeof args[1], 'function'); + }); + }); + + it('fails without options.input', () => { + return rollup + .rollup({}) + .then(() => { + throw new Error('Missing expected error'); + }) + .catch(err => { + assert.equal(err.message, 'You must supply options.input to rollup'); + }); + }); + + it('fails with invalid keys', () => { + const warnings = []; + const onwarn = warning => warnings.push(warning); + return rollup + .rollup({ input: 'x', onwarn, plUgins: [], plugins: [loader({ x: `console.log( 42 );` })] }) + .then(() => { + assert.deepEqual(warnings, [ + { + code: 'UNKNOWN_OPTION', + message: + 'Unknown input option: plUgins. Allowed options: ' + require('./optionList').input + } + ]); + }); + }); + + it('treats Literals as leaf nodes, even if first literal encountered is null', () => { + // this test has to be up here, otherwise the bug doesn't have + // an opportunity to present itself + return rollup.rollup({ + input: 'x', + plugins: [loader({ x: `var a = null; a = 'a string';` })] + }); + }); + + it('includes a newline at the end of the bundle', () => { + return rollup + .rollup({ + input: 'x', + plugins: [loader({ x: `console.log( 42 );` })] + }) + .then(bundle => { + return bundle.generate({ format: 'iife' }); + }) + .then(({ code }) => { + assert.ok(code[code.length - 1] === '\n'); + }); + }); + + it('throws on missing output options', () => { + const warnings = []; + + return rollup + .rollup({ + input: 'x', + plugins: [loader({ x: `console.log( 42 );` })], + onwarn: warning => warnings.push(warning) + }) + .then(bundle => { + assert.throws(() => { + bundle.generate(); + }, /You must supply an options object/); + }); + }); + + it('throws on missing format option', () => { + const warnings = []; + + return rollup + .rollup({ + input: 'x', + plugins: [loader({ x: `console.log( 42 );` })], + onwarn: warning => warnings.push(warning) + }) + .then(bundle => { + assert.throws(() => { + bundle.generate({ file: 'x' }); + }, /You must specify output\.format, which can be one of 'amd', 'cjs', 'system', 'esm', 'iife' or 'umd'/); + }); + }); + + it('reuses existing error object', () => { + let error; + + class CustomError extends Error { + constructor(message, x) { + super(message); + this.prop = x.toUpperCase(); + } + } + + return rollup + .rollup({ + input: 'x', + plugins: [ + loader({ x: `console.log( 42 );` }), + { + transform(code) { + error = new CustomError('foo', 'bar'); + this.error(error); + } + } + ] + }) + .catch(e => { + assert.equal(e, error); + }); + }); +}); diff --git a/test/misc/write-bundle.js b/test/misc/write-bundle.js new file mode 100644 index 00000000000..64e3d3f0979 --- /dev/null +++ b/test/misc/write-bundle.js @@ -0,0 +1,116 @@ +const assert = require('assert'); +const rollup = require('../../dist/rollup'); +const { loader } = require('../utils.js'); + +describe('bundle.write()', () => { + it('fails without options or options.file', () => { + return rollup + .rollup({ + input: 'x', + plugins: [ + { + resolveId: () => { + return 'test'; + }, + load: () => { + return '// empty'; + } + } + ] + }) + .then(bundle => { + assert.throws(() => { + bundle.write(); + }, /You must specify output\.file/); + + assert.throws(() => { + bundle.write({}); + }, /You must specify output\.file/); + }); + }); + + it('expects output.name for IIFE and UMD bundles', () => { + let bundle; + + return rollup + .rollup({ + input: 'x', + plugins: [ + { + resolveId: () => { + return 'test'; + }, + load: () => { + return 'export var foo = 42;'; + } + } + ] + }) + .then(rollupInstance => { + bundle = rollupInstance; + return bundle.generate({ + format: 'umd' + }); + }) + .catch(err => { + assert.throws(() => { + throw err; + }, /You must supply output\.name for UMD bundles/); + }) + .then(() => { + return bundle.generate({ + format: 'iife' + }); + }) + .catch(err => { + assert.throws(() => { + throw err; + }, /You must supply output\.name for IIFE bundles/); + }); + }); + + it('throws on es6 format', () => { + return rollup + .rollup({ + input: 'x', + plugins: [ + { + resolveId: () => { + return 'test'; + }, + load: () => { + return '// empty'; + } + } + ] + }) + .then(bundle => { + assert.throws(() => { + return bundle.generate({ format: 'es6' }); + }, /The `es6` output format is deprecated – use `es` instead/); + }); + }); + + it('works when output options is an array', () => { + const warnings = []; + const options = { + input: 'x', + plugins: [loader({ x: `console.log( 42 );` })], + onwarn: warning => warnings.push(warning), + output: [ + { + format: 'cjs' + }, + { + format: 'es' + } + ] + }; + return rollup.rollup(options).then(bundle => { + assert.equal(warnings.length, 0, 'No warnings for UNKNOWN'); + assert.throws(() => { + return Promise.all(options.output.map(o => bundle.write(o))); + }, /You must specify output\.file/); + }); + }); +}); From 9f921ef27acf271fd42ef78db95c84430a7c4ff9 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sun, 11 Nov 2018 16:42:10 +0100 Subject: [PATCH 02/23] Create basic bundle information test --- test/misc/bundle-information.js | 86 +++++++++++++++++++++++++++++++++ test/misc/index.js | 1 + 2 files changed, 87 insertions(+) create mode 100644 test/misc/bundle-information.js diff --git a/test/misc/bundle-information.js b/test/misc/bundle-information.js new file mode 100644 index 00000000000..a64f48966a3 --- /dev/null +++ b/test/misc/bundle-information.js @@ -0,0 +1,86 @@ +const assert = require('assert'); +const rollup = require('../../dist/rollup'); +const { loader } = require('../utils.js'); + +describe('The bundle object', () => { + it('contains information about the generated chunks', () => { + return rollup + .rollup({ + input: ['input1', 'input2'], + experimentalCodeSplitting: true, + plugins: [ + loader({ + input1: `import 'shared';\nconsole.log('input1');\nexport const out = true;`, + input2: `import 'shared';\nconsole.log('input2');`, + shared: `console.log('shared');\nexport const unused = null;` + }) + ] + }) + .then(bundle => + bundle.generate({ + format: 'esm', + dir: 'dist', + chunkFileNames: '[name].js' + }) + ) + .then(({ output }) => { + console.log(output); + console.log(output['chunk.js'].modules); + const sortedOutput = Object.keys(output) + .sort() + .map(key => output[key]); + assert.deepEqual( + sortedOutput.map(chunk => chunk.fileName), + ['chunk.js', 'input1.js', 'input2.js'], + 'fileName' + ); + assert.deepEqual( + sortedOutput.map(chunk => chunk.code), + [ + "console.log('shared');\n", + "import './chunk.js';\n\nconsole.log('input1');\nconst out = true;\n\nexport { out };\n", + "import './chunk.js';\n\nconsole.log('input2');\n" + ], + 'code' + ); + assert.deepEqual(sortedOutput.map(chunk => chunk.map), [null, null, null], 'map'); + assert.deepEqual(sortedOutput.map(chunk => chunk.isEntry), [false, true, true], 'isEntry'); + assert.deepEqual( + sortedOutput.map(chunk => chunk.imports), + [[], ['chunk.js'], ['chunk.js']], + 'imports' + ); + assert.deepEqual(sortedOutput.map(chunk => chunk.exports), [[], ['out'], []], 'exports'); + assert.deepEqual( + sortedOutput.map(chunk => chunk.modules), + [ + { + shared: { + originalLength: 50, + removedExports: ['unused'], + renderedExports: [], + renderedLength: 22 + } + }, + { + input1: { + originalLength: 64, + removedExports: [], + renderedExports: ['out'], + renderedLength: 40 + } + }, + { + input2: { + originalLength: 39, + removedExports: [], + renderedExports: [], + renderedLength: 22 + } + } + ], + 'modules' + ); + }); + }); +}); diff --git a/test/misc/index.js b/test/misc/index.js index 3479a3643b9..805a21b32a5 100644 --- a/test/misc/index.js +++ b/test/misc/index.js @@ -1,4 +1,5 @@ require('./acorn-plugins'); +require('./bundle-information'); require('./deprecations'); require('./in-memory-sourcemaps'); require('./misc'); From 9ae9bd72907d36569ed1cc79ce8ab932920964bb Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Mon, 12 Nov 2018 07:35:27 +0100 Subject: [PATCH 03/23] * Make sure "isEntry" is only true for entry facades * Give precedence to entry facades when deconflicting ids * Add entryModuleId to entry facades --- src/Chunk.ts | 2 +- src/Graph.ts | 2 +- src/rollup/index.ts | 32 +------ src/rollup/types.d.ts | 1 + src/utils/assignChunkIds.ts | 48 ++++++++++ .../{default-plugin.ts => defaultPlugin.ts} | 0 .../{execution-order.ts => executionOrder.ts} | 0 src/utils/pluginDriver.ts | 2 +- test/misc/bundle-information.js | 96 ++++++++++++++++--- 9 files changed, 141 insertions(+), 42 deletions(-) create mode 100644 src/utils/assignChunkIds.ts rename src/utils/{default-plugin.ts => defaultPlugin.ts} (100%) rename src/utils/{execution-order.ts => executionOrder.ts} (100%) diff --git a/src/Chunk.ts b/src/Chunk.ts index 2786843cb9e..a414aeeb344 100644 --- a/src/Chunk.ts +++ b/src/Chunk.ts @@ -23,7 +23,7 @@ import { Addons } from './utils/addons'; import { toBase64 } from './utils/base64'; import collapseSourcemaps from './utils/collapseSourcemaps'; import error from './utils/error'; -import { sortByExecutionOrder } from './utils/execution-order'; +import { sortByExecutionOrder } from './utils/executionOrder'; import getIndentString from './utils/getIndentString'; import { makeLegal } from './utils/identifierHelpers'; import { basename, dirname, isAbsolute, normalize, relative, resolve } from './utils/path'; diff --git a/src/Graph.ts b/src/Graph.ts index 6e3f28b18b7..6294795f16b 100644 --- a/src/Graph.ts +++ b/src/Graph.ts @@ -25,7 +25,7 @@ import { import { finaliseAsset } from './utils/assetHooks'; import { Uint8ArrayToHexString } from './utils/entryHashing'; import error from './utils/error'; -import { analyzeModuleExecution, sortByExecutionOrder } from './utils/execution-order'; +import { analyzeModuleExecution, sortByExecutionOrder } from './utils/executionOrder'; import { isRelative, resolve } from './utils/path'; import { createPluginDriver, PluginDriver } from './utils/pluginDriver'; import relativeId, { getAliasName } from './utils/relativeId'; diff --git a/src/rollup/index.ts b/src/rollup/index.ts index afe8cfe4bc3..bc455dfb8fc 100644 --- a/src/rollup/index.ts +++ b/src/rollup/index.ts @@ -3,6 +3,7 @@ import { optimizeChunks } from '../chunk-optimization'; import Graph from '../Graph'; import { createAddons } from '../utils/addons'; import { createAssetPluginHooks, finaliseAsset } from '../utils/assetHooks'; +import { assignChunkIds } from '../utils/assignChunkIds'; import commondir from '../utils/commondir'; import { Deprecation } from '../utils/deprecateOptions'; import error from '../utils/error'; @@ -287,33 +288,7 @@ export default function rollup( optimized = true; } - // name all chunks - const usedIds: Record = {}; - for (let i = 0; i < chunks.length; i++) { - const chunk = chunks[i]; - - if (chunk === singleChunk) { - singleChunk.id = basename( - outputOptions.file || - (inputOptions.input instanceof Array - ? inputOptions.input[0] - : inputOptions.input) - ); - } else if (inputOptions.experimentalPreserveModules) { - chunk.generateIdPreserveModules(inputBase, usedIds); - } else { - let pattern, patternName; - if (chunk.isEntryModuleFacade) { - pattern = outputOptions.entryFileNames || '[name].js'; - patternName = 'output.entryFileNames'; - } else { - pattern = outputOptions.chunkFileNames || '[name]-[hash].js'; - patternName = 'output.chunkFileNames'; - } - chunk.generateId(pattern, patternName, addons, outputOptions, usedIds); - } - usedIds[chunk.id] = true; - } + assignChunkIds(chunks, singleChunk, inputOptions, outputOptions, inputBase, addons); // assign to outputBundle for (let i = 0; i < chunks.length; i++) { @@ -321,7 +296,8 @@ export default function rollup( outputBundle[chunk.id] = { fileName: chunk.id, - isEntry: chunk.entryModule !== undefined, + isEntry: chunk.isEntryModuleFacade, + entryModuleId: chunk.isEntryModuleFacade ? chunk.entryModule.id : null, imports: chunk.getImportIds(), exports: chunk.getExportNames(), modules: chunk.renderedModules, diff --git a/src/rollup/types.d.ts b/src/rollup/types.d.ts index bf0d0be823a..960bd9123e3 100644 --- a/src/rollup/types.d.ts +++ b/src/rollup/types.d.ts @@ -365,6 +365,7 @@ export interface RenderedModule { export interface RenderedChunk { fileName: string; isEntry: boolean; + entryModuleId: string | null; imports: string[]; exports: string[]; modules: { diff --git a/src/utils/assignChunkIds.ts b/src/utils/assignChunkIds.ts new file mode 100644 index 00000000000..bf0f2dd7d0b --- /dev/null +++ b/src/utils/assignChunkIds.ts @@ -0,0 +1,48 @@ +import Chunk from '../Chunk'; +import { InputOptions, OutputOptions } from '../rollup/types'; +import { Addons } from './addons'; +import { basename } from './path'; + +export function assignChunkIds( + chunks: Chunk[], + singleChunk: Chunk | void, + inputOptions: InputOptions, + outputOptions: OutputOptions, + inputBase: string, + addons: Addons +) { + const usedIds: Record = {}; + const [entryChunks, otherChunks] = chunks.reduce( + ([entryChunks, otherChunks], chunk) => { + (chunk.isEntryModuleFacade ? entryChunks : otherChunks).push(chunk); + return [entryChunks, otherChunks]; + }, + [[], []] + ); + + // make sure entry chunk names take precedence with regard to deconflicting + const chunksForNaming: Chunk[] = entryChunks.concat(otherChunks); + for (let i = 0; i < chunksForNaming.length; i++) { + const chunk = chunksForNaming[i]; + + if (chunk === singleChunk) { + singleChunk.id = basename( + outputOptions.file || + (inputOptions.input instanceof Array ? inputOptions.input[0] : inputOptions.input) + ); + } else if (inputOptions.experimentalPreserveModules) { + chunk.generateIdPreserveModules(inputBase, usedIds); + } else { + let pattern, patternName; + if (chunk.isEntryModuleFacade) { + pattern = outputOptions.entryFileNames || '[name].js'; + patternName = 'output.entryFileNames'; + } else { + pattern = outputOptions.chunkFileNames || '[name]-[hash].js'; + patternName = 'output.chunkFileNames'; + } + chunk.generateId(pattern, patternName, addons, outputOptions, usedIds); + } + usedIds[chunk.id] = true; + } +} diff --git a/src/utils/default-plugin.ts b/src/utils/defaultPlugin.ts similarity index 100% rename from src/utils/default-plugin.ts rename to src/utils/defaultPlugin.ts diff --git a/src/utils/execution-order.ts b/src/utils/executionOrder.ts similarity index 100% rename from src/utils/execution-order.ts rename to src/utils/executionOrder.ts diff --git a/src/utils/pluginDriver.ts b/src/utils/pluginDriver.ts index bc2992e3497..9715317c3de 100644 --- a/src/utils/pluginDriver.ts +++ b/src/utils/pluginDriver.ts @@ -11,7 +11,7 @@ import { Watcher } from '../rollup/types'; import { createAssetPluginHooks, EmitAsset } from './assetHooks'; -import { getRollupDefaultPlugin } from './default-plugin'; +import { getRollupDefaultPlugin } from './defaultPlugin'; import error from './error'; export interface PluginDriver { diff --git a/test/misc/bundle-information.js b/test/misc/bundle-information.js index a64f48966a3..d22db91cf41 100644 --- a/test/misc/bundle-information.js +++ b/test/misc/bundle-information.js @@ -10,9 +10,9 @@ describe('The bundle object', () => { experimentalCodeSplitting: true, plugins: [ loader({ - input1: `import 'shared';\nconsole.log('input1');\nexport const out = true;`, - input2: `import 'shared';\nconsole.log('input2');`, - shared: `console.log('shared');\nexport const unused = null;` + input1: 'import "shared";\nconsole.log("input1");\nexport const out = true;', + input2: 'import "shared";\nconsole.log("input2");', + shared: 'console.log("shared");\nexport const unused = null;' }) ] }) @@ -20,34 +20,33 @@ describe('The bundle object', () => { bundle.generate({ format: 'esm', dir: 'dist', - chunkFileNames: '[name].js' + chunkFileNames: 'generated-[name].js' }) ) .then(({ output }) => { - console.log(output); - console.log(output['chunk.js'].modules); const sortedOutput = Object.keys(output) .sort() .map(key => output[key]); assert.deepEqual( sortedOutput.map(chunk => chunk.fileName), - ['chunk.js', 'input1.js', 'input2.js'], + ['generated-chunk.js', 'input1.js', 'input2.js'], 'fileName' ); assert.deepEqual( sortedOutput.map(chunk => chunk.code), [ - "console.log('shared');\n", - "import './chunk.js';\n\nconsole.log('input1');\nconst out = true;\n\nexport { out };\n", - "import './chunk.js';\n\nconsole.log('input2');\n" + 'console.log("shared");\n', + 'import \'./generated-chunk.js\';\n\nconsole.log("input1");\nconst out = true;\n\nexport { out };\n', + 'import \'./generated-chunk.js\';\n\nconsole.log("input2");\n' ], 'code' ); assert.deepEqual(sortedOutput.map(chunk => chunk.map), [null, null, null], 'map'); assert.deepEqual(sortedOutput.map(chunk => chunk.isEntry), [false, true, true], 'isEntry'); + assert.deepEqual(sortedOutput.map(chunk => chunk.entryModuleId), [null, 'input1', 'input2'], 'entryModuleId'); assert.deepEqual( sortedOutput.map(chunk => chunk.imports), - [[], ['chunk.js'], ['chunk.js']], + [[], ['generated-chunk.js'], ['generated-chunk.js']], 'imports' ); assert.deepEqual(sortedOutput.map(chunk => chunk.exports), [[], ['out'], []], 'exports'); @@ -83,4 +82,79 @@ describe('The bundle object', () => { ); }); }); + + it('handles entry facades as entry points but not the facaded chunk', () => { + return rollup + .rollup({ + input: ['input1', 'input2'], + experimentalCodeSplitting: true, + plugins: [ + loader({ + input1: + 'import {shared} from "shared";import {input2} from "input2";console.log(input2, shared);', + input2: 'import {shared} from "shared";export const input2 = "input2";', + shared: 'export const shared = "shared"' + }) + ] + }) + .then(bundle => + bundle.generate({ + format: 'esm', + dir: 'dist', + chunkFileNames: 'generated-[name].js' + }) + ) + .then(({ output }) => { + const sortedOutput = Object.keys(output) + .sort() + .map(key => output[key]); + assert.deepEqual( + sortedOutput.map(chunk => chunk.fileName), + ['generated-input2.js', 'input1.js', 'input2.js'], + 'fileName' + ); + assert.deepEqual( + sortedOutput.map(chunk => Object.keys(chunk.modules)), + [['shared', 'input2'], ['input1'], []], + 'modules' + ); + assert.deepEqual(sortedOutput.map(chunk => chunk.isEntry), [false, true, true], 'isEntry'); + assert.deepEqual(sortedOutput.map(chunk => chunk.entryModuleId), [null, 'input1', 'input2'], 'entryModuleId'); + }); + }); + + it('prioritizes the proper facade name over the proper facaded chunk name', () => { + return rollup + .rollup({ + input: ['input1', 'input2'], + experimentalCodeSplitting: true, + plugins: [ + loader({ + input1: + 'import {shared} from "shared";import {input2} from "input2";console.log(input2, shared);', + input2: 'import {shared} from "shared";export const input2 = "input2";', + shared: 'export const shared = "shared"' + }) + ] + }) + .then(bundle => + bundle.generate({ + format: 'esm', + dir: 'dist', + entryFileNames: '[name].js', + chunkFileNames: '[name].js' + }) + ) + .then(({ output }) => { + const sortedOutput = Object.keys(output) + .sort() + .map(key => output[key]); + assert.deepEqual( + sortedOutput.map(chunk => chunk.fileName), + ['input1.js', 'input2.js', 'input22.js'], + 'fileName' + ); + assert.deepEqual(sortedOutput.map(chunk => chunk.entryModuleId), ['input1', 'input2', null], 'entryModuleId'); + }); + }); }); From 73474b22d901f32004043bde33a2473d1459b0e6 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Thu, 15 Nov 2018 07:21:24 +0100 Subject: [PATCH 04/23] * Mark dynamic entry points as such and separate this from actual entry points * Use internal names for dynamic entry points * Do not generate dynamic entry points that are not used --- src/Chunk.ts | 17 ++-- src/Graph.ts | 25 ++---- src/Module.ts | 24 ++++-- src/ast/nodes/Import.ts | 5 ++ src/rollup/index.ts | 1 + src/rollup/types.d.ts | 1 + src/utils/executionOrder.ts | 11 +-- .../samples/aliasing-extensions/_config.js | 5 +- .../{main4.dynamic.js => generated-chunk.js} | 0 .../amd/{main5.js => generated-chunk2.js} | 0 .../_expected/amd/main1.js | 4 +- .../{main4.dynamic.js => generated-chunk.js} | 0 .../cjs/{main5.js => generated-chunk2.js} | 0 .../_expected/cjs/main1.js | 4 +- .../{main4.dynamic.js => generated-chunk.js} | 0 .../es/{main5.js => generated-chunk2.js} | 0 .../aliasing-extensions/_expected/es/main1.js | 4 +- .../{main4.dynamic.js => generated-chunk.js} | 0 .../system/{main5.js => generated-chunk2.js} | 0 .../_expected/system/main1.js | 4 +- .../amd/{dep2.js => chunk-8ea4f89e.js} | 2 - .../_expected/amd/main.js | 2 +- .../cjs/{dep2.js => chunk-38762abc.js} | 2 - .../_expected/cjs/main.js | 2 +- .../es/{dep2.js => chunk-a97cfc63.js} | 0 .../_expected/es/main.js | 2 +- .../system/{dep2.js => chunk-b7f9caf2.js} | 0 .../_expected/system/main.js | 2 +- .../_expected/amd/main.js | 4 +- .../_expected/cjs/main.js | 4 +- .../_expected/es/main.js | 4 +- .../_expected/system/main.js | 4 +- .../dynamic-import-inline-colouring/foo.js | 3 +- .../dynamic-import-inline-colouring/main.js | 4 +- .../_expected/amd/dep2.js | 11 --- .../_expected/cjs/dep2.js | 11 --- .../_expected/es/dep2.js | 7 -- .../_expected/system/dep2.js | 18 ---- .../samples/manual-chunks-dynamic/_config.js | 7 +- .../_expected/amd/dynamic-10698fc3.js | 5 -- .../_expected/amd/generated-dynamic.js | 7 ++ .../_expected/amd/main.js | 2 +- .../_expected/cjs/dynamic-5ab72169.js | 2 - .../_expected/cjs/generated-dynamic.js | 5 ++ .../_expected/cjs/main.js | 2 +- .../_expected/es/dynamic-12dc935a.js | 1 - .../_expected/es/generated-dynamic.js | 3 + .../_expected/es/main.js | 2 +- ...namic-e8bd5876.js => generated-dynamic.js} | 2 +- .../_expected/system/main.js | 2 +- .../samples/manual-chunks-dynamic/main.js | 2 +- test/hooks/index.js | 12 +-- test/misc/bundle-information.js | 83 ++++++++++++++++--- 53 files changed, 185 insertions(+), 139 deletions(-) rename test/chunking-form/samples/aliasing-extensions/_expected/amd/{main4.dynamic.js => generated-chunk.js} (100%) rename test/chunking-form/samples/aliasing-extensions/_expected/amd/{main5.js => generated-chunk2.js} (100%) rename test/chunking-form/samples/aliasing-extensions/_expected/cjs/{main4.dynamic.js => generated-chunk.js} (100%) rename test/chunking-form/samples/aliasing-extensions/_expected/cjs/{main5.js => generated-chunk2.js} (100%) rename test/chunking-form/samples/aliasing-extensions/_expected/es/{main4.dynamic.js => generated-chunk.js} (100%) rename test/chunking-form/samples/aliasing-extensions/_expected/es/{main5.js => generated-chunk2.js} (100%) rename test/chunking-form/samples/aliasing-extensions/_expected/system/{main4.dynamic.js => generated-chunk.js} (100%) rename test/chunking-form/samples/aliasing-extensions/_expected/system/{main5.js => generated-chunk2.js} (100%) rename test/chunking-form/samples/dynamic-import-chunking/_expected/amd/{dep2.js => chunk-8ea4f89e.js} (73%) rename test/chunking-form/samples/dynamic-import-chunking/_expected/cjs/{dep2.js => chunk-38762abc.js} (69%) rename test/chunking-form/samples/dynamic-import-chunking/_expected/es/{dep2.js => chunk-a97cfc63.js} (100%) rename test/chunking-form/samples/dynamic-import-chunking/_expected/system/{dep2.js => chunk-b7f9caf2.js} (100%) delete mode 100644 test/chunking-form/samples/dynamic-import-treeshaking/_expected/amd/dep2.js delete mode 100644 test/chunking-form/samples/dynamic-import-treeshaking/_expected/cjs/dep2.js delete mode 100644 test/chunking-form/samples/dynamic-import-treeshaking/_expected/es/dep2.js delete mode 100644 test/chunking-form/samples/dynamic-import-treeshaking/_expected/system/dep2.js delete mode 100644 test/chunking-form/samples/manual-chunks-dynamic/_expected/amd/dynamic-10698fc3.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic/_expected/amd/generated-dynamic.js delete mode 100644 test/chunking-form/samples/manual-chunks-dynamic/_expected/cjs/dynamic-5ab72169.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic/_expected/cjs/generated-dynamic.js delete mode 100644 test/chunking-form/samples/manual-chunks-dynamic/_expected/es/dynamic-12dc935a.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic/_expected/es/generated-dynamic.js rename test/chunking-form/samples/manual-chunks-dynamic/_expected/system/{dynamic-e8bd5876.js => generated-dynamic.js} (58%) diff --git a/src/Chunk.ts b/src/Chunk.ts index a414aeeb344..dcbae759fa2 100644 --- a/src/Chunk.ts +++ b/src/Chunk.ts @@ -131,6 +131,7 @@ export default class Chunk { // an input entry point module entryModule: Module = undefined; isEntryModuleFacade: boolean = false; + isDynamicEntryPoint: boolean = false; isManualChunk: boolean = false; private renderedHash: string = undefined; @@ -162,6 +163,12 @@ export default class Chunk { this.entryModule = module; this.isEntryModuleFacade = true; } + if (module.isDynamicEntryPoint) { + this.isDynamicEntryPoint = true; + if (!this.entryModule) { + this.entryModule = module; + } + } } if (this.entryModule) @@ -282,7 +289,7 @@ export default class Chunk { } } - if (preserveModules || this.isEntryModuleFacade) { + if (preserveModules || this.isEntryModuleFacade || this.isDynamicEntryPoint) { for (const [index, exportName] of entryExportEntries) { const traced = tracedExports[index]; if (!traced) { @@ -393,7 +400,7 @@ export default class Chunk { } generateInternalExports(options: OutputOptions) { - if (this.isEntryModuleFacade) return; + if (this.isEntryModuleFacade || this.isDynamicEntryPoint) return; const mangle = options.format === 'system' || options.format === 'es' || options.compact; let i = 0, safeExportName: string; @@ -460,7 +467,7 @@ export default class Chunk { if (!resolution) continue; if (resolution instanceof Module) { - if (resolution.chunk !== this) { + if (resolution.chunk && resolution.chunk !== this && resolution.chunk.id) { let relPath = normalize(relative(dirname(this.id), resolution.chunk.id)); if (!relPath.startsWith('../')) relPath = './' + relPath; node.renderFinalResolution(code, `"${relPath}"`); @@ -808,8 +815,8 @@ export default class Chunk { format: options.format }; - // if an entry point facade, inline the execution list to avoid loading latency - if (this.isEntryModuleFacade) { + // if an entry point facade or dynamic entry point, inline the execution list to avoid loading latency + if (this.isEntryModuleFacade || this.isDynamicEntryPoint) { for (const dep of this.dependencies) { if (dep instanceof Chunk) this.inlineChunkDependencies(dep, true); } diff --git a/src/Graph.ts b/src/Graph.ts index 6294795f16b..d1e00eaa21c 100644 --- a/src/Graph.ts +++ b/src/Graph.ts @@ -371,12 +371,7 @@ export default class Graph { this.link(); - const { - orderedModules, - dynamicImports, - dynamicImportAliases, - cyclePaths - } = analyzeModuleExecution( + const { orderedModules, dynamicImports, cyclePaths } = analyzeModuleExecution( entryModules, !preserveModules && !inlineDynamicImports, inlineDynamicImports, @@ -397,24 +392,13 @@ export default class Graph { } if (inlineDynamicImports) { - const entryModule = entryModules[0]; if (entryModules.length > 1) throw new Error( 'Internal Error: can only inline dynamic imports for single-file builds.' ); for (const dynamicImportModule of dynamicImports) { - if (entryModule !== dynamicImportModule) dynamicImportModule.markPublicExports(); dynamicImportModule.getOrCreateNamespace().include(); } - } else { - for (let i = 0; i < dynamicImports.length; i++) { - const dynamicImportModule = dynamicImports[i]; - if (entryModules.indexOf(dynamicImportModule) === -1) { - entryModules.push(dynamicImportModule); - if (!dynamicImportModule.chunkAlias) - dynamicImportModule.chunkAlias = dynamicImportAliases[i]; - } - } } timeEnd('analyse dependency graph', 2); @@ -422,8 +406,7 @@ export default class Graph { // Phase 3 – marking. We include all statements that should be included timeStart('mark included statements', 2); - for (const entryModule of entryModules) entryModule.markPublicExports(); - + for (const entryModule of entryModules) entryModule.includeAllExports(); // only include statements that should appear in the bundle this.includeMarked(orderedModules); @@ -474,7 +457,9 @@ export default class Graph { } // filter out empty dependencies - chunks = chunks.filter(chunk => !chunk.isEmpty || chunk.entryModule || chunk.isManualChunk); + chunks = chunks.filter( + chunk => !chunk.isEmpty || chunk.isEntryModuleFacade || chunk.isManualChunk + ); // then go over and ensure all entry chunks export their variables for (const chunk of chunks) { diff --git a/src/Module.ts b/src/Module.ts index a7de14f23f9..6b7035fb466 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -83,6 +83,7 @@ export interface AstContext { imports: { [name: string]: ImportDescription }; isCrossChunkImport: (importDescription: ImportDescription) => boolean; includeNamespace: () => void; + includeDynamicImport: (node: Import) => void; magicString: MagicString; moduleContext: string; nodeConstructors: { [name: string]: typeof NodeBase }; @@ -176,6 +177,7 @@ export default class Module { execIndex: number; isEntryPoint: boolean; + isDynamicEntryPoint: boolean; chunkAlias: string; entryPointsHash: Uint8Array; chunk: Chunk; @@ -201,6 +203,7 @@ export default class Module { this.importMetas = []; this.dynamicImportResolutions = []; this.isEntryPoint = false; + this.isDynamicEntryPoint = false; this.execIndex = Infinity; this.entryPointsHash = new Uint8Array(10); @@ -272,6 +275,7 @@ export default class Module { getModuleExecIndex: () => this.execIndex, getModuleName: this.basename.bind(this), imports: this.imports, + includeDynamicImport: this.includeDynamicImport.bind(this), includeNamespace: this.includeNamespace.bind(this), isCrossChunkImport: importDescription => importDescription.module.chunk !== this.chunk, magicString: this.magicString, @@ -445,13 +449,15 @@ export default class Module { return makeLegal(ext ? base.slice(0, -ext.length) : base); } - markPublicExports() { + includeAllExports() { for (const exportName of this.getExports()) { const variable = this.traceExport(exportName); - variable.exportName = exportName; variable.deoptimizePath(UNKNOWN_PATH); - variable.include(); + if (!variable.included) { + variable.include(); + this.needsTreeshakingPass = true; + } if (variable.isNamespace) { (variable).needsNamespaceBlock = true; @@ -461,13 +467,12 @@ export default class Module { for (const name of this.getReexports()) { const variable = this.traceExport(name); - variable.exportName = name; - if (variable.isExternal) { variable.reexported = (variable).module.reexported = true; - } else { + } else if (!variable.included) { variable.include(); variable.deoptimizePath(UNKNOWN_PATH); + this.needsTreeshakingPass = true; } } } @@ -619,6 +624,13 @@ export default class Module { return (this.namespaceVariable = new NamespaceVariable(this.astContext, this)); } + private includeDynamicImport(node: Import) { + const resolution = this.dynamicImportResolutions[this.dynamicImports.indexOf(node)].resolution; + if (resolution instanceof Module) { + resolution.includeAllExports(); + } + } + private includeNamespace() { const namespace = this.getOrCreateNamespace(); if (namespace.needsNamespaceBlock) return; diff --git a/src/ast/nodes/Import.ts b/src/ast/nodes/Import.ts index 1ce8b00630c..9b032f43ef6 100644 --- a/src/ast/nodes/Import.ts +++ b/src/ast/nodes/Import.ts @@ -49,6 +49,11 @@ export default class Import extends NodeBase { private resolutionInterop: boolean; private rendered: boolean; + include() { + this.included = true; + this.context.includeDynamicImport(this); + } + initialise() { this.included = false; this.resolutionNamespace = undefined; diff --git a/src/rollup/index.ts b/src/rollup/index.ts index bc455dfb8fc..8dad4956df0 100644 --- a/src/rollup/index.ts +++ b/src/rollup/index.ts @@ -297,6 +297,7 @@ export default function rollup( outputBundle[chunk.id] = { fileName: chunk.id, isEntry: chunk.isEntryModuleFacade, + isDynamicEntry: chunk.isDynamicEntryPoint, entryModuleId: chunk.isEntryModuleFacade ? chunk.entryModule.id : null, imports: chunk.getImportIds(), exports: chunk.getExportNames(), diff --git a/src/rollup/types.d.ts b/src/rollup/types.d.ts index 960bd9123e3..fdb27b69d54 100644 --- a/src/rollup/types.d.ts +++ b/src/rollup/types.d.ts @@ -365,6 +365,7 @@ export interface RenderedModule { export interface RenderedChunk { fileName: string; isEntry: boolean; + isDynamicEntry: boolean; entryModuleId: string | null; imports: string[]; exports: string[]; diff --git a/src/utils/executionOrder.ts b/src/utils/executionOrder.ts index 2e483593d19..bbd33b80243 100644 --- a/src/utils/executionOrder.ts +++ b/src/utils/executionOrder.ts @@ -30,7 +30,6 @@ export function analyzeModuleExecution( let analyzedModuleCount = 0; const dynamicImports: Module[] = []; - const dynamicImportAliases: string[] = []; let parents: { [id: string]: string }; @@ -80,7 +79,6 @@ export function analyzeModuleExecution( ) { if (dynamicImports.indexOf(dynamicModule.resolution) === -1) { dynamicImports.push(dynamicModule.resolution); - dynamicImportAliases.push(dynamicModule.alias); } } } @@ -123,14 +121,17 @@ Try defining "${chunkName}" first in the manualChunks definitions of the Rollup // new items can be added during this loop for (curEntry of dynamicImports) { - if (curEntry.isEntryPoint) continue; - if (!inlineDynamicImports) curEntry.isEntryPoint = true; + if (curEntry.isEntryPoint || curEntry.isDynamicEntryPoint) { + if (!inlineDynamicImports) curEntry.isDynamicEntryPoint = true; + continue; + } + if (!inlineDynamicImports) curEntry.isDynamicEntryPoint = true; curEntryHash = randomUint8Array(10); parents = { [curEntry.id]: null }; visit(curEntry); } - return { orderedModules, dynamicImports, dynamicImportAliases, cyclePaths }; + return { orderedModules, dynamicImports, cyclePaths }; } function getCyclePath(id: string, parentId: string, parents: { [id: string]: string | null }) { diff --git a/test/chunking-form/samples/aliasing-extensions/_config.js b/test/chunking-form/samples/aliasing-extensions/_config.js index aa5a872d5b7..238c925f8e4 100644 --- a/test/chunking-form/samples/aliasing-extensions/_config.js +++ b/test/chunking-form/samples/aliasing-extensions/_config.js @@ -1,6 +1,9 @@ module.exports = { description: 'chunk aliasing with extensions', options: { - input: ['main1', 'main2', 'main3.ts'] + input: ['main1', 'main2', 'main3.ts'], + output: { + chunkFileNames: 'generated-[name].js' + } } }; diff --git a/test/chunking-form/samples/aliasing-extensions/_expected/amd/main4.dynamic.js b/test/chunking-form/samples/aliasing-extensions/_expected/amd/generated-chunk.js similarity index 100% rename from test/chunking-form/samples/aliasing-extensions/_expected/amd/main4.dynamic.js rename to test/chunking-form/samples/aliasing-extensions/_expected/amd/generated-chunk.js diff --git a/test/chunking-form/samples/aliasing-extensions/_expected/amd/main5.js b/test/chunking-form/samples/aliasing-extensions/_expected/amd/generated-chunk2.js similarity index 100% rename from test/chunking-form/samples/aliasing-extensions/_expected/amd/main5.js rename to test/chunking-form/samples/aliasing-extensions/_expected/amd/generated-chunk2.js diff --git a/test/chunking-form/samples/aliasing-extensions/_expected/amd/main1.js b/test/chunking-form/samples/aliasing-extensions/_expected/amd/main1.js index 3913745da6c..3b27d3206d3 100644 --- a/test/chunking-form/samples/aliasing-extensions/_expected/amd/main1.js +++ b/test/chunking-form/samples/aliasing-extensions/_expected/amd/main1.js @@ -1,7 +1,7 @@ define(['require'], function (require) { 'use strict'; console.log('main1'); - new Promise(function (resolve, reject) { require(["./main4.dynamic.js"], resolve, reject) }); - new Promise(function (resolve, reject) { require(["./main5.js"], resolve, reject) }); + new Promise(function (resolve, reject) { require(["./generated-chunk.js"], resolve, reject) }); + new Promise(function (resolve, reject) { require(["./generated-chunk2.js"], resolve, reject) }); }); diff --git a/test/chunking-form/samples/aliasing-extensions/_expected/cjs/main4.dynamic.js b/test/chunking-form/samples/aliasing-extensions/_expected/cjs/generated-chunk.js similarity index 100% rename from test/chunking-form/samples/aliasing-extensions/_expected/cjs/main4.dynamic.js rename to test/chunking-form/samples/aliasing-extensions/_expected/cjs/generated-chunk.js diff --git a/test/chunking-form/samples/aliasing-extensions/_expected/cjs/main5.js b/test/chunking-form/samples/aliasing-extensions/_expected/cjs/generated-chunk2.js similarity index 100% rename from test/chunking-form/samples/aliasing-extensions/_expected/cjs/main5.js rename to test/chunking-form/samples/aliasing-extensions/_expected/cjs/generated-chunk2.js diff --git a/test/chunking-form/samples/aliasing-extensions/_expected/cjs/main1.js b/test/chunking-form/samples/aliasing-extensions/_expected/cjs/main1.js index c2db120ae65..a93a61559d3 100644 --- a/test/chunking-form/samples/aliasing-extensions/_expected/cjs/main1.js +++ b/test/chunking-form/samples/aliasing-extensions/_expected/cjs/main1.js @@ -1,5 +1,5 @@ 'use strict'; console.log('main1'); -Promise.resolve(require("./main4.dynamic.js")); -Promise.resolve(require("./main5.js")); +Promise.resolve(require("./generated-chunk.js")); +Promise.resolve(require("./generated-chunk2.js")); diff --git a/test/chunking-form/samples/aliasing-extensions/_expected/es/main4.dynamic.js b/test/chunking-form/samples/aliasing-extensions/_expected/es/generated-chunk.js similarity index 100% rename from test/chunking-form/samples/aliasing-extensions/_expected/es/main4.dynamic.js rename to test/chunking-form/samples/aliasing-extensions/_expected/es/generated-chunk.js diff --git a/test/chunking-form/samples/aliasing-extensions/_expected/es/main5.js b/test/chunking-form/samples/aliasing-extensions/_expected/es/generated-chunk2.js similarity index 100% rename from test/chunking-form/samples/aliasing-extensions/_expected/es/main5.js rename to test/chunking-form/samples/aliasing-extensions/_expected/es/generated-chunk2.js diff --git a/test/chunking-form/samples/aliasing-extensions/_expected/es/main1.js b/test/chunking-form/samples/aliasing-extensions/_expected/es/main1.js index 1d07e379985..60be58c15af 100644 --- a/test/chunking-form/samples/aliasing-extensions/_expected/es/main1.js +++ b/test/chunking-form/samples/aliasing-extensions/_expected/es/main1.js @@ -1,3 +1,3 @@ console.log('main1'); -import("./main4.dynamic.js"); -import("./main5.js"); +import("./generated-chunk.js"); +import("./generated-chunk2.js"); diff --git a/test/chunking-form/samples/aliasing-extensions/_expected/system/main4.dynamic.js b/test/chunking-form/samples/aliasing-extensions/_expected/system/generated-chunk.js similarity index 100% rename from test/chunking-form/samples/aliasing-extensions/_expected/system/main4.dynamic.js rename to test/chunking-form/samples/aliasing-extensions/_expected/system/generated-chunk.js diff --git a/test/chunking-form/samples/aliasing-extensions/_expected/system/main5.js b/test/chunking-form/samples/aliasing-extensions/_expected/system/generated-chunk2.js similarity index 100% rename from test/chunking-form/samples/aliasing-extensions/_expected/system/main5.js rename to test/chunking-form/samples/aliasing-extensions/_expected/system/generated-chunk2.js diff --git a/test/chunking-form/samples/aliasing-extensions/_expected/system/main1.js b/test/chunking-form/samples/aliasing-extensions/_expected/system/main1.js index 55da5619feb..5ee5a7f26b8 100644 --- a/test/chunking-form/samples/aliasing-extensions/_expected/system/main1.js +++ b/test/chunking-form/samples/aliasing-extensions/_expected/system/main1.js @@ -4,8 +4,8 @@ System.register([], function (exports, module) { execute: function () { console.log('main1'); - module.import("./main4.dynamic.js"); - module.import("./main5.js"); + module.import("./generated-chunk.js"); + module.import("./generated-chunk2.js"); } }; diff --git a/test/chunking-form/samples/dynamic-import-chunking/_expected/amd/dep2.js b/test/chunking-form/samples/dynamic-import-chunking/_expected/amd/chunk-8ea4f89e.js similarity index 73% rename from test/chunking-form/samples/dynamic-import-chunking/_expected/amd/dep2.js rename to test/chunking-form/samples/dynamic-import-chunking/_expected/amd/chunk-8ea4f89e.js index 0d4b271bf1a..60eba601593 100644 --- a/test/chunking-form/samples/dynamic-import-chunking/_expected/amd/dep2.js +++ b/test/chunking-form/samples/dynamic-import-chunking/_expected/amd/chunk-8ea4f89e.js @@ -6,6 +6,4 @@ define(['exports', './chunk-7b720877.js'], function (exports, __chunk_1) { 'use exports.mult = mult; - Object.defineProperty(exports, '__esModule', { value: true }); - }); diff --git a/test/chunking-form/samples/dynamic-import-chunking/_expected/amd/main.js b/test/chunking-form/samples/dynamic-import-chunking/_expected/amd/main.js index 9bbdca63f2e..db6fe608a75 100644 --- a/test/chunking-form/samples/dynamic-import-chunking/_expected/amd/main.js +++ b/test/chunking-form/samples/dynamic-import-chunking/_expected/amd/main.js @@ -9,7 +9,7 @@ define(['require', './chunk-7b720877.js'], function (require, __chunk_1) { 'use } function dynamic (num) { - return new Promise(function (resolve, reject) { require(["./dep2.js"], resolve, reject) }) + return new Promise(function (resolve, reject) { require(["./chunk-8ea4f89e.js"], resolve, reject) }) .then(dep2 => { return dep2.mult(num); }); diff --git a/test/chunking-form/samples/dynamic-import-chunking/_expected/cjs/dep2.js b/test/chunking-form/samples/dynamic-import-chunking/_expected/cjs/chunk-38762abc.js similarity index 69% rename from test/chunking-form/samples/dynamic-import-chunking/_expected/cjs/dep2.js rename to test/chunking-form/samples/dynamic-import-chunking/_expected/cjs/chunk-38762abc.js index 5c0ba52bcf6..e156f0e2be6 100644 --- a/test/chunking-form/samples/dynamic-import-chunking/_expected/cjs/dep2.js +++ b/test/chunking-form/samples/dynamic-import-chunking/_expected/cjs/chunk-38762abc.js @@ -1,7 +1,5 @@ 'use strict'; -Object.defineProperty(exports, '__esModule', { value: true }); - var __chunk_1 = require('./chunk-3a53aa58.js'); function mult (num) { diff --git a/test/chunking-form/samples/dynamic-import-chunking/_expected/cjs/main.js b/test/chunking-form/samples/dynamic-import-chunking/_expected/cjs/main.js index 1c4e4a31e0b..1d85666ece6 100644 --- a/test/chunking-form/samples/dynamic-import-chunking/_expected/cjs/main.js +++ b/test/chunking-form/samples/dynamic-import-chunking/_expected/cjs/main.js @@ -11,7 +11,7 @@ function fn (num) { } function dynamic (num) { - return Promise.resolve(require("./dep2.js")) + return Promise.resolve(require("./chunk-38762abc.js")) .then(dep2 => { return dep2.mult(num); }); diff --git a/test/chunking-form/samples/dynamic-import-chunking/_expected/es/dep2.js b/test/chunking-form/samples/dynamic-import-chunking/_expected/es/chunk-a97cfc63.js similarity index 100% rename from test/chunking-form/samples/dynamic-import-chunking/_expected/es/dep2.js rename to test/chunking-form/samples/dynamic-import-chunking/_expected/es/chunk-a97cfc63.js diff --git a/test/chunking-form/samples/dynamic-import-chunking/_expected/es/main.js b/test/chunking-form/samples/dynamic-import-chunking/_expected/es/main.js index ef18c5069dc..8314fb558c6 100644 --- a/test/chunking-form/samples/dynamic-import-chunking/_expected/es/main.js +++ b/test/chunking-form/samples/dynamic-import-chunking/_expected/es/main.js @@ -9,7 +9,7 @@ function fn (num) { } function dynamic (num) { - return import("./dep2.js") + return import("./chunk-a97cfc63.js") .then(dep2 => { return dep2.mult(num); }); diff --git a/test/chunking-form/samples/dynamic-import-chunking/_expected/system/dep2.js b/test/chunking-form/samples/dynamic-import-chunking/_expected/system/chunk-b7f9caf2.js similarity index 100% rename from test/chunking-form/samples/dynamic-import-chunking/_expected/system/dep2.js rename to test/chunking-form/samples/dynamic-import-chunking/_expected/system/chunk-b7f9caf2.js diff --git a/test/chunking-form/samples/dynamic-import-chunking/_expected/system/main.js b/test/chunking-form/samples/dynamic-import-chunking/_expected/system/main.js index 4478b7d425f..6db7e928aa5 100644 --- a/test/chunking-form/samples/dynamic-import-chunking/_expected/system/main.js +++ b/test/chunking-form/samples/dynamic-import-chunking/_expected/system/main.js @@ -16,7 +16,7 @@ System.register(['./chunk-4d8f4e43.js'], function (exports, module) { } function dynamic (num) { - return module.import("./dep2.js") + return module.import("./chunk-b7f9caf2.js") .then(dep2 => { return dep2.mult(num); }); diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main.js index ad52189480a..2bf301b34c8 100644 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main.js +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main.js @@ -1,9 +1,11 @@ define(['require'], function (require) { 'use strict'; var foo = "FOO"; + const x = 2; var foo$1 = /*#__PURE__*/Object.freeze({ - default: foo + default: foo, + x: x }); var main = Promise.resolve().then(function () { return foo$1; }); diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main.js index 1a883d8e104..9fb50d19ce9 100644 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main.js +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main.js @@ -1,9 +1,11 @@ 'use strict'; var foo = "FOO"; +const x = 2; var foo$1 = /*#__PURE__*/Object.freeze({ - default: foo + default: foo, + x: x }); var main = Promise.resolve().then(function () { return foo$1; }); diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main.js index c2c2c98a3ca..34c9cbc8357 100644 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main.js +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main.js @@ -1,7 +1,9 @@ var foo = "FOO"; +const x = 2; var foo$1 = /*#__PURE__*/Object.freeze({ - default: foo + default: foo, + x: x }); var main = Promise.resolve().then(function () { return foo$1; }); diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main.js index fa520cb9470..25ee215a741 100644 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main.js +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main.js @@ -4,9 +4,11 @@ System.register([], function (exports, module) { execute: function () { var foo = "FOO"; + const x = 2; var foo$1 = /*#__PURE__*/Object.freeze({ - default: foo + default: foo, + x: x }); var main = exports('default', Promise.resolve().then(function () { return foo$1; })); diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/foo.js b/test/chunking-form/samples/dynamic-import-inline-colouring/foo.js index 5337929ccbc..6d568106adb 100644 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/foo.js +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/foo.js @@ -1 +1,2 @@ -export default "FOO"; \ No newline at end of file +export default "FOO"; +export const x = 2 diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/main.js b/test/chunking-form/samples/dynamic-import-inline-colouring/main.js index 09ad58d8300..c7ecc83be08 100644 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/main.js +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/main.js @@ -1,3 +1,3 @@ -import foo from "./foo.js"; +import './foo.js'; -export default import("./foo.js"); \ No newline at end of file +export default import("./foo.js"); diff --git a/test/chunking-form/samples/dynamic-import-treeshaking/_expected/amd/dep2.js b/test/chunking-form/samples/dynamic-import-treeshaking/_expected/amd/dep2.js deleted file mode 100644 index 0d4b271bf1a..00000000000 --- a/test/chunking-form/samples/dynamic-import-treeshaking/_expected/amd/dep2.js +++ /dev/null @@ -1,11 +0,0 @@ -define(['exports', './chunk-7b720877.js'], function (exports, __chunk_1) { 'use strict'; - - function mult (num) { - return num + __chunk_1.multiplier; - } - - exports.mult = mult; - - Object.defineProperty(exports, '__esModule', { value: true }); - -}); diff --git a/test/chunking-form/samples/dynamic-import-treeshaking/_expected/cjs/dep2.js b/test/chunking-form/samples/dynamic-import-treeshaking/_expected/cjs/dep2.js deleted file mode 100644 index 5c0ba52bcf6..00000000000 --- a/test/chunking-form/samples/dynamic-import-treeshaking/_expected/cjs/dep2.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, '__esModule', { value: true }); - -var __chunk_1 = require('./chunk-3a53aa58.js'); - -function mult (num) { - return num + __chunk_1.multiplier; -} - -exports.mult = mult; diff --git a/test/chunking-form/samples/dynamic-import-treeshaking/_expected/es/dep2.js b/test/chunking-form/samples/dynamic-import-treeshaking/_expected/es/dep2.js deleted file mode 100644 index c0ed67ae72e..00000000000 --- a/test/chunking-form/samples/dynamic-import-treeshaking/_expected/es/dep2.js +++ /dev/null @@ -1,7 +0,0 @@ -import { a as multiplier } from './chunk-713732d9.js'; - -function mult (num) { - return num + multiplier; -} - -export { mult }; diff --git a/test/chunking-form/samples/dynamic-import-treeshaking/_expected/system/dep2.js b/test/chunking-form/samples/dynamic-import-treeshaking/_expected/system/dep2.js deleted file mode 100644 index 39e64c9d4e0..00000000000 --- a/test/chunking-form/samples/dynamic-import-treeshaking/_expected/system/dep2.js +++ /dev/null @@ -1,18 +0,0 @@ -System.register(['./chunk-4d8f4e43.js'], function (exports, module) { - 'use strict'; - var multiplier; - return { - setters: [function (module) { - multiplier = module.a; - }], - execute: function () { - - exports('mult', mult); - - function mult (num) { - return num + multiplier; - } - - } - }; -}); diff --git a/test/chunking-form/samples/manual-chunks-dynamic/_config.js b/test/chunking-form/samples/manual-chunks-dynamic/_config.js index 6a02c734e3f..943877edc50 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic/_config.js +++ b/test/chunking-form/samples/manual-chunks-dynamic/_config.js @@ -1,10 +1,15 @@ module.exports = { description: 'manual chunks to an empty dynamic chunk', - _single: true, + + // manual chunks which are also dynamic entry points do not work yet + skip: true, options: { input: ['main.js'], manualChunks: { dynamic: ['dynamic.js'] + }, + output: { + chunkFileNames: 'generated-[name].js' } } }; diff --git a/test/chunking-form/samples/manual-chunks-dynamic/_expected/amd/dynamic-10698fc3.js b/test/chunking-form/samples/manual-chunks-dynamic/_expected/amd/dynamic-10698fc3.js deleted file mode 100644 index f9f8229aa40..00000000000 --- a/test/chunking-form/samples/manual-chunks-dynamic/_expected/amd/dynamic-10698fc3.js +++ /dev/null @@ -1,5 +0,0 @@ -define(function () { 'use strict'; - - - -}); diff --git a/test/chunking-form/samples/manual-chunks-dynamic/_expected/amd/generated-dynamic.js b/test/chunking-form/samples/manual-chunks-dynamic/_expected/amd/generated-dynamic.js new file mode 100644 index 00000000000..94b0e40c8e0 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic/_expected/amd/generated-dynamic.js @@ -0,0 +1,7 @@ +define(['exports'], function (exports) { 'use strict'; + + const DYNAMIC_USED_BY_A = 'DYNAMIC_USED_BY_A'; + + exports.DYNAMIC_USED_BY_A = DYNAMIC_USED_BY_A; + +}); diff --git a/test/chunking-form/samples/manual-chunks-dynamic/_expected/amd/main.js b/test/chunking-form/samples/manual-chunks-dynamic/_expected/amd/main.js index 4ebb7e1db8e..f8d3226c002 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic/_expected/amd/main.js +++ b/test/chunking-form/samples/manual-chunks-dynamic/_expected/amd/main.js @@ -1,5 +1,5 @@ define(['require'], function (require) { 'use strict'; - new Promise(function (resolve, reject) { require(["./dynamic-10698fc3.js"], resolve, reject) }); + new Promise(function (resolve, reject) { require(["./generated-dynamic.js"], resolve, reject) }).then(({DYNAMIC_USED_BY_A}) => console.log(DYNAMIC_USED_BY_A)); }); diff --git a/test/chunking-form/samples/manual-chunks-dynamic/_expected/cjs/dynamic-5ab72169.js b/test/chunking-form/samples/manual-chunks-dynamic/_expected/cjs/dynamic-5ab72169.js deleted file mode 100644 index eb109abbed0..00000000000 --- a/test/chunking-form/samples/manual-chunks-dynamic/_expected/cjs/dynamic-5ab72169.js +++ /dev/null @@ -1,2 +0,0 @@ -'use strict'; - diff --git a/test/chunking-form/samples/manual-chunks-dynamic/_expected/cjs/generated-dynamic.js b/test/chunking-form/samples/manual-chunks-dynamic/_expected/cjs/generated-dynamic.js new file mode 100644 index 00000000000..28e15f91379 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic/_expected/cjs/generated-dynamic.js @@ -0,0 +1,5 @@ +'use strict'; + +const DYNAMIC_USED_BY_A = 'DYNAMIC_USED_BY_A'; + +exports.DYNAMIC_USED_BY_A = DYNAMIC_USED_BY_A; diff --git a/test/chunking-form/samples/manual-chunks-dynamic/_expected/cjs/main.js b/test/chunking-form/samples/manual-chunks-dynamic/_expected/cjs/main.js index f3310639beb..8c663eaa935 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic/_expected/cjs/main.js +++ b/test/chunking-form/samples/manual-chunks-dynamic/_expected/cjs/main.js @@ -1,3 +1,3 @@ 'use strict'; -Promise.resolve(require("./dynamic-5ab72169.js")); +Promise.resolve(require("./generated-dynamic.js")).then(({DYNAMIC_USED_BY_A}) => console.log(DYNAMIC_USED_BY_A)); diff --git a/test/chunking-form/samples/manual-chunks-dynamic/_expected/es/dynamic-12dc935a.js b/test/chunking-form/samples/manual-chunks-dynamic/_expected/es/dynamic-12dc935a.js deleted file mode 100644 index 8b137891791..00000000000 --- a/test/chunking-form/samples/manual-chunks-dynamic/_expected/es/dynamic-12dc935a.js +++ /dev/null @@ -1 +0,0 @@ - diff --git a/test/chunking-form/samples/manual-chunks-dynamic/_expected/es/generated-dynamic.js b/test/chunking-form/samples/manual-chunks-dynamic/_expected/es/generated-dynamic.js new file mode 100644 index 00000000000..4ccf6321419 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic/_expected/es/generated-dynamic.js @@ -0,0 +1,3 @@ +const DYNAMIC_USED_BY_A = 'DYNAMIC_USED_BY_A'; + +export { DYNAMIC_USED_BY_A }; diff --git a/test/chunking-form/samples/manual-chunks-dynamic/_expected/es/main.js b/test/chunking-form/samples/manual-chunks-dynamic/_expected/es/main.js index 0e83b245b59..346c6c18fb5 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic/_expected/es/main.js +++ b/test/chunking-form/samples/manual-chunks-dynamic/_expected/es/main.js @@ -1 +1 @@ -import("./dynamic-12dc935a.js"); +import("./generated-dynamic.js").then(({DYNAMIC_USED_BY_A}) => console.log(DYNAMIC_USED_BY_A)); diff --git a/test/chunking-form/samples/manual-chunks-dynamic/_expected/system/dynamic-e8bd5876.js b/test/chunking-form/samples/manual-chunks-dynamic/_expected/system/generated-dynamic.js similarity index 58% rename from test/chunking-form/samples/manual-chunks-dynamic/_expected/system/dynamic-e8bd5876.js rename to test/chunking-form/samples/manual-chunks-dynamic/_expected/system/generated-dynamic.js index 3b9098cda90..babdf3ed714 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic/_expected/system/dynamic-e8bd5876.js +++ b/test/chunking-form/samples/manual-chunks-dynamic/_expected/system/generated-dynamic.js @@ -3,7 +3,7 @@ System.register([], function (exports, module) { return { execute: function () { - + const DYNAMIC_USED_BY_A = exports('DYNAMIC_USED_BY_A', 'DYNAMIC_USED_BY_A'); } }; diff --git a/test/chunking-form/samples/manual-chunks-dynamic/_expected/system/main.js b/test/chunking-form/samples/manual-chunks-dynamic/_expected/system/main.js index 48d04548cf8..86c7fd46537 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic/_expected/system/main.js +++ b/test/chunking-form/samples/manual-chunks-dynamic/_expected/system/main.js @@ -3,7 +3,7 @@ System.register([], function (exports, module) { return { execute: function () { - module.import("./dynamic-e8bd5876.js"); + module.import("./generated-dynamic.js").then(({DYNAMIC_USED_BY_A}) => console.log(DYNAMIC_USED_BY_A)); } }; diff --git a/test/chunking-form/samples/manual-chunks-dynamic/main.js b/test/chunking-form/samples/manual-chunks-dynamic/main.js index a3d5cb1d641..c4c5988813a 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic/main.js +++ b/test/chunking-form/samples/manual-chunks-dynamic/main.js @@ -1 +1 @@ -import('./dynamic.js'); \ No newline at end of file +import('./dynamic.js').then(({DYNAMIC_USED_BY_A}) => console.log(DYNAMIC_USED_BY_A)); diff --git a/test/hooks/index.js b/test/hooks/index.js index 628ece9564f..7e4dc1a4963 100644 --- a/test/hooks/index.js +++ b/test/hooks/index.js @@ -1102,7 +1102,7 @@ module.exports = input; .then(bundle => bundle.generate({ entryFileNames: '[name].js', - chunkFileNames: '[name].js', + chunkFileNames: 'generated-[name].js', format: 'esm' }) ) @@ -1114,18 +1114,18 @@ module.exports = input; modules: ['input'] }, { - fileName: 'a.js', - imports: ['chunk.js'], + fileName: 'generated-chunk.js', + imports: ['generated-chunk2.js'], modules: ['d', 'a'] }, { - fileName: 'chunk.js', + fileName: 'generated-chunk2.js', imports: [], modules: ['c'] }, { - fileName: 'b.js', - imports: ['chunk.js'], + fileName: 'generated-chunk3.js', + imports: ['generated-chunk2.js'], modules: ['b'] } ]); diff --git a/test/misc/bundle-information.js b/test/misc/bundle-information.js index d22db91cf41..fb0edf18ce8 100644 --- a/test/misc/bundle-information.js +++ b/test/misc/bundle-information.js @@ -10,9 +10,9 @@ describe('The bundle object', () => { experimentalCodeSplitting: true, plugins: [ loader({ - input1: 'import "shared";\nconsole.log("input1");\nexport const out = true;', - input2: 'import "shared";\nconsole.log("input2");', - shared: 'console.log("shared");\nexport const unused = null;' + input1: 'import "shared";console.log("input1");export const out = true;', + input2: 'import "shared";console.log("input2");', + shared: 'console.log("shared");export const unused = null;' }) ] }) @@ -36,14 +36,18 @@ describe('The bundle object', () => { sortedOutput.map(chunk => chunk.code), [ 'console.log("shared");\n', - 'import \'./generated-chunk.js\';\n\nconsole.log("input1");\nconst out = true;\n\nexport { out };\n', + 'import \'./generated-chunk.js\';\n\nconsole.log("input1");const out = true;\n\nexport { out };\n', 'import \'./generated-chunk.js\';\n\nconsole.log("input2");\n' ], 'code' ); assert.deepEqual(sortedOutput.map(chunk => chunk.map), [null, null, null], 'map'); assert.deepEqual(sortedOutput.map(chunk => chunk.isEntry), [false, true, true], 'isEntry'); - assert.deepEqual(sortedOutput.map(chunk => chunk.entryModuleId), [null, 'input1', 'input2'], 'entryModuleId'); + assert.deepEqual( + sortedOutput.map(chunk => chunk.entryModuleId), + [null, 'input1', 'input2'], + 'entryModuleId' + ); assert.deepEqual( sortedOutput.map(chunk => chunk.imports), [[], ['generated-chunk.js'], ['generated-chunk.js']], @@ -55,7 +59,7 @@ describe('The bundle object', () => { [ { shared: { - originalLength: 50, + originalLength: 49, removedExports: ['unused'], renderedExports: [], renderedLength: 22 @@ -63,15 +67,15 @@ describe('The bundle object', () => { }, { input1: { - originalLength: 64, + originalLength: 62, removedExports: [], renderedExports: ['out'], - renderedLength: 40 + renderedLength: 39 } }, { input2: { - originalLength: 39, + originalLength: 38, removedExports: [], renderedExports: [], renderedLength: 22 @@ -119,7 +123,11 @@ describe('The bundle object', () => { 'modules' ); assert.deepEqual(sortedOutput.map(chunk => chunk.isEntry), [false, true, true], 'isEntry'); - assert.deepEqual(sortedOutput.map(chunk => chunk.entryModuleId), [null, 'input1', 'input2'], 'entryModuleId'); + assert.deepEqual( + sortedOutput.map(chunk => chunk.entryModuleId), + [null, 'input1', 'input2'], + 'entryModuleId' + ); }); }); @@ -154,7 +162,60 @@ describe('The bundle object', () => { ['input1.js', 'input2.js', 'input22.js'], 'fileName' ); - assert.deepEqual(sortedOutput.map(chunk => chunk.entryModuleId), ['input1', 'input2', null], 'entryModuleId'); + assert.deepEqual( + sortedOutput.map(chunk => chunk.entryModuleId), + ['input1', 'input2', null], + 'entryModuleId' + ); + }); + }); + + it('marks dynamic entry points but only marks them as normal entry points if they actually are', () => { + return rollup + .rollup({ + input: ['input', 'dynamic1'], + experimentalCodeSplitting: true, + plugins: [ + loader({ + input: + 'Promise.all([import("dynamic1"), import("dynamic2")]).then(([{dynamic1}, {dynamic2}]) => console.log(dynamic1, dynamic2));', + dynamic1: 'export const dynamic1 = "dynamic1"', + dynamic2: 'export const dynamic2 = "dynamic2"' + }) + ] + }) + .then(bundle => + bundle.generate({ + format: 'esm', + dir: 'dist', + entryFileNames: '[name].js', + chunkFileNames: 'generated-[name].js' + }) + ) + .then(({ output }) => { + const sortedOutput = Object.keys(output) + .sort() + .map(key => output[key]); + assert.deepEqual( + sortedOutput.map(chunk => chunk.fileName), + ['dynamic1.js', 'generated-chunk.js', 'input.js'], + 'fileName' + ); + assert.deepEqual(sortedOutput.map(chunk => chunk.isEntry), [true, false, true], 'isEntry'); + assert.deepEqual( + sortedOutput.map(chunk => chunk.code), + [ + 'const dynamic1 = "dynamic1";\n\nexport { dynamic1 };\n', + 'const dynamic2 = "dynamic2";\n\nexport { dynamic2 };\n', + 'Promise.all([import("./dynamic1.js"), import("./generated-chunk.js")]).then(([{dynamic1}, {dynamic2}]) => console.log(dynamic1, dynamic2));\n' + ], + 'code' + ); + assert.deepEqual( + sortedOutput.map(chunk => chunk.isDynamicEntry), + [true, true, false], + 'isDynamicEntry' + ); }); }); }); From 4bdd4382b75f66610e8ae7bcf3a991c636f4475d Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Fri, 16 Nov 2018 06:32:34 +0100 Subject: [PATCH 05/23] Add entryModuleIds to both static and dynamic entry points --- src/rollup/index.ts | 5 ++++- test/misc/bundle-information.js | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/rollup/index.ts b/src/rollup/index.ts index 8dad4956df0..d7504d9f25e 100644 --- a/src/rollup/index.ts +++ b/src/rollup/index.ts @@ -298,7 +298,10 @@ export default function rollup( fileName: chunk.id, isEntry: chunk.isEntryModuleFacade, isDynamicEntry: chunk.isDynamicEntryPoint, - entryModuleId: chunk.isEntryModuleFacade ? chunk.entryModule.id : null, + entryModuleId: + chunk.isEntryModuleFacade || chunk.isDynamicEntryPoint + ? chunk.entryModule.id + : null, imports: chunk.getImportIds(), exports: chunk.getExportNames(), modules: chunk.renderedModules, diff --git a/test/misc/bundle-information.js b/test/misc/bundle-information.js index fb0edf18ce8..0be3056b741 100644 --- a/test/misc/bundle-information.js +++ b/test/misc/bundle-information.js @@ -216,6 +216,11 @@ describe('The bundle object', () => { [true, true, false], 'isDynamicEntry' ); + assert.deepEqual( + sortedOutput.map(chunk => chunk.entryModuleId), + ['dynamic1', 'dynamic2', 'input'], + 'entryModuleId' + ); }); }); }); From a5ca4c3da3eead398f2ce8ea2c1d932903c04e09 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Fri, 16 Nov 2018 13:00:04 +0100 Subject: [PATCH 06/23] Add name to output --- src/Chunk.ts | 57 +++++++++++++++++++-------------- src/ExternalModule.ts | 6 ++-- src/Graph.ts | 1 - src/rollup/index.ts | 15 +++++---- src/rollup/types.d.ts | 9 +++--- test/misc/bundle-information.js | 16 ++++++--- 6 files changed, 61 insertions(+), 43 deletions(-) diff --git a/src/Chunk.ts b/src/Chunk.ts index dcbae759fa2..a3d060a56fd 100644 --- a/src/Chunk.ts +++ b/src/Chunk.ts @@ -90,12 +90,12 @@ function getGlobalName( graph.warn({ code: 'MISSING_GLOBAL_NAME', source: module.id, - guess: module.name, + guess: module.variableName, message: `No name was provided for external module '${ module.id - }' in output.globals – guessing '${module.name}'` + }' in output.globals – guessing '${module.variableName}'` }); - return module.name; + return module.variableName; } } @@ -109,7 +109,7 @@ export default class Chunk { exportMode: string = 'named'; usedModules: Module[] = undefined; id: string = undefined; - name: string; + variableName: string; graph: Graph; orderedModules: Module[]; execIndex: number; @@ -132,6 +132,7 @@ export default class Chunk { entryModule: Module = undefined; isEntryModuleFacade: boolean = false; isDynamicEntryPoint: boolean = false; + isEmpty: boolean; isManualChunk: boolean = false; private renderedHash: string = undefined; @@ -143,7 +144,7 @@ export default class Chunk { dependencies: ChunkDependencies; exports: ChunkExports; } = undefined; - isEmpty: boolean; + private chunkName: string | void; constructor(graph: Graph, orderedModules: Module[]) { this.graph = graph; @@ -172,12 +173,12 @@ export default class Chunk { } if (this.entryModule) - this.name = makeLegal( + this.variableName = makeLegal( basename( this.entryModule.chunkAlias || this.orderedModules[0].chunkAlias || this.entryModule.id ) ); - else this.name = '__chunk_' + ++graph.curChunkIndex; + else this.variableName = '__chunk_' + ++graph.curChunkIndex; } getImportIds(): string[] { @@ -521,9 +522,9 @@ export default class Chunk { if (!esm) { this.dependencies.forEach(module => { - const safeName = getSafeName(module.name); + const safeName = getSafeName(module.variableName); toDeshadow.add(safeName); - module.name = safeName; + module.variableName = safeName; }); } @@ -539,18 +540,18 @@ export default class Chunk { if (module instanceof ExternalModule) { if (variable.name === '*') { - safeName = module.name; + safeName = module.variableName; } else if (variable.name === 'default') { if ( options.interop !== false && (module.exportsNamespace || (!esm && module.exportsNames)) ) { - safeName = `${module.name}__default`; + safeName = `${module.variableName}__default`; } else { - safeName = module.name; + safeName = module.variableName; } } else { - safeName = esm ? variable.name : `${module.name}.${variable.name}`; + safeName = esm ? variable.name : `${module.variableName}.${variable.name}`; } if (esm) { safeName = getSafeName(safeName); @@ -561,8 +562,8 @@ export default class Chunk { toDeshadow.add(safeName); } else { const chunk = module.chunk; - if (chunk.exportMode === 'default') safeName = chunk.name; - else safeName = `${chunk.name}.${module.chunk.getVariableExportName(variable)}`; + if (chunk.exportMode === 'default') safeName = chunk.variableName; + else safeName = `${chunk.variableName}.${module.chunk.getVariableExportName(variable)}`; } if (safeName) variable.setSafeName(safeName); }); @@ -691,7 +692,7 @@ export default class Chunk { id, // chunk id updated on render namedExportsMode, globalName, - name: dep.name, + name: dep.variableName, isChunk: !(dep).isExternal, exportsNames, exportsDefault, @@ -771,7 +772,7 @@ export default class Chunk { return visitDep(this); } - private computeFullHash(addons: Addons, options: OutputOptions): string { + private computeContentHashWithDependencies(addons: Addons, options: OutputOptions): string { const hash = sha256(); // own rendered source, except for finalizer wrapping @@ -984,7 +985,7 @@ export default class Chunk { if (!into.exportsDefault && from.exportsDefault) { into.exportsDefault = true; } - into.name = this.name; + into.name = this.variableName; }; // go through the other chunks and update their dependencies @@ -1045,19 +1046,27 @@ export default class Chunk { case 'format': return options.format === 'es' ? 'esm' : options.format; case 'hash': - return this.computeFullHash(addons, options); + return this.computeContentHashWithDependencies(addons, options); case 'name': - if (this.entryModule && this.entryModule.chunkAlias) return this.entryModule.chunkAlias; - for (const module of this.orderedModules) { - if (module.chunkAlias) return module.chunkAlias; - } - return 'chunk'; + return this.getChunkName(); } }), existingNames ); } + getChunkName(): string { + return this.chunkName || (this.chunkName = this.computeChunkName()); + } + + private computeChunkName(): string { + if (this.entryModule && this.entryModule.chunkAlias) return this.entryModule.chunkAlias; + for (const module of this.orderedModules) { + if (module.chunkAlias) return module.chunkAlias; + } + return 'chunk'; + } + render(options: OutputOptions, addons: Addons, outputChunk: RenderedChunk) { timeStart('render format', 3); diff --git a/src/ExternalModule.ts b/src/ExternalModule.ts index 3be5b02fccb..3d488a82bb5 100644 --- a/src/ExternalModule.ts +++ b/src/ExternalModule.ts @@ -17,7 +17,7 @@ export default class ExternalModule { renormalizeRenderPath = false; isExternal = true; isEntryPoint = false; - name: string; + variableName: string; mostCommonSuggestion: number = 0; nameSuggestions: { [name: string]: number }; reexported: boolean = false; @@ -30,7 +30,7 @@ export default class ExternalModule { this.execIndex = Infinity; const parts = id.split(/[\\/]/); - this.name = makeLegal(parts.pop()); + this.variableName = makeLegal(parts.pop()); this.nameSuggestions = Object.create(null); this.declarations = Object.create(null); @@ -58,7 +58,7 @@ export default class ExternalModule { if (this.nameSuggestions[name] > this.mostCommonSuggestion) { this.mostCommonSuggestion = this.nameSuggestions[name]; - this.name = name; + this.variableName = name; } } diff --git a/src/Graph.ts b/src/Graph.ts index d1e00eaa21c..e66ba51227c 100644 --- a/src/Graph.ts +++ b/src/Graph.ts @@ -51,7 +51,6 @@ export default class Graph { context: string; externalModules: ExternalModule[] = []; getModuleContext: (id: string) => string; - hasLoaders: boolean; isPureExternalModule: (id: string) => boolean; moduleById = new Map(); assetsById = new Map(); diff --git a/src/rollup/index.ts b/src/rollup/index.ts index d7504d9f25e..aea82a066ac 100644 --- a/src/rollup/index.ts +++ b/src/rollup/index.ts @@ -295,18 +295,21 @@ export default function rollup( const chunk = chunks[i]; outputBundle[chunk.id] = { - fileName: chunk.id, - isEntry: chunk.isEntryModuleFacade, - isDynamicEntry: chunk.isDynamicEntryPoint, + code: undefined, entryModuleId: chunk.isEntryModuleFacade || chunk.isDynamicEntryPoint ? chunk.entryModule.id : null, - imports: chunk.getImportIds(), exports: chunk.getExportNames(), + fileName: chunk.id, + imports: chunk.getImportIds(), + isDynamicEntry: chunk.isDynamicEntryPoint, + isEntry: chunk.isEntryModuleFacade, + map: undefined, modules: chunk.renderedModules, - code: undefined, - map: undefined + get name() { + return chunk.getChunkName(); + } }; } diff --git a/src/rollup/types.d.ts b/src/rollup/types.d.ts index fdb27b69d54..c63d62e2376 100644 --- a/src/rollup/types.d.ts +++ b/src/rollup/types.d.ts @@ -363,15 +363,16 @@ export interface RenderedModule { } export interface RenderedChunk { - fileName: string; - isEntry: boolean; - isDynamicEntry: boolean; entryModuleId: string | null; - imports: string[]; exports: string[]; + fileName: string; + imports: string[]; + isDynamicEntry: boolean; + isEntry: boolean; modules: { [id: string]: RenderedModule; }; + name: string; } export interface OutputChunk extends RenderedChunk { diff --git a/test/misc/bundle-information.js b/test/misc/bundle-information.js index 0be3056b741..de1cea27215 100644 --- a/test/misc/bundle-information.js +++ b/test/misc/bundle-information.js @@ -20,7 +20,8 @@ describe('The bundle object', () => { bundle.generate({ format: 'esm', dir: 'dist', - chunkFileNames: 'generated-[name].js' + chunkFileNames: 'generated-[name]-[hash].js', + entryFileNames: '[name]-[hash].js' }) ) .then(({ output }) => { @@ -29,20 +30,25 @@ describe('The bundle object', () => { .map(key => output[key]); assert.deepEqual( sortedOutput.map(chunk => chunk.fileName), - ['generated-chunk.js', 'input1.js', 'input2.js'], + ['generated-chunk-dc742c8f.js', 'input1-00b2c9b1.js', 'input2-815cf3ef.js'], 'fileName' ); assert.deepEqual( sortedOutput.map(chunk => chunk.code), [ 'console.log("shared");\n', - 'import \'./generated-chunk.js\';\n\nconsole.log("input1");const out = true;\n\nexport { out };\n', - 'import \'./generated-chunk.js\';\n\nconsole.log("input2");\n' + 'import \'./generated-chunk-dc742c8f.js\';\n\nconsole.log("input1");const out = true;\n\nexport { out };\n', + 'import \'./generated-chunk-dc742c8f.js\';\n\nconsole.log("input2");\n' ], 'code' ); assert.deepEqual(sortedOutput.map(chunk => chunk.map), [null, null, null], 'map'); assert.deepEqual(sortedOutput.map(chunk => chunk.isEntry), [false, true, true], 'isEntry'); + assert.deepEqual( + sortedOutput.map(chunk => chunk.name), + ['chunk', 'input1', 'input2'], + 'name' + ); assert.deepEqual( sortedOutput.map(chunk => chunk.entryModuleId), [null, 'input1', 'input2'], @@ -50,7 +56,7 @@ describe('The bundle object', () => { ); assert.deepEqual( sortedOutput.map(chunk => chunk.imports), - [[], ['generated-chunk.js'], ['generated-chunk.js']], + [[], ['generated-chunk-dc742c8f.js'], ['generated-chunk-dc742c8f.js']], 'imports' ); assert.deepEqual(sortedOutput.map(chunk => chunk.exports), [[], ['out'], []], 'exports'); From c4f9a180aaf3d13a7cfffa44cd5bb1acdab7d24a Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sat, 17 Nov 2018 16:03:48 +0100 Subject: [PATCH 07/23] Separate execution order from chunk colouring --- src/Graph.ts | 14 +- src/rollup/index.ts | 2 - src/utils/chunkColouring.ts | 73 +++++++++++ src/utils/executionOrder.ts | 122 +++++------------- .../_config.js | 1 + ...and3-0c5d98d0.js => deps2and3-609a33db.js} | 4 +- .../manual-chunks/_expected/amd/main.js | 6 +- ...and3-9aeb2d5b.js => deps2and3-c8fe246d.js} | 4 +- .../manual-chunks/_expected/cjs/main.js | 6 +- 9 files changed, 122 insertions(+), 110 deletions(-) create mode 100644 src/utils/chunkColouring.ts rename test/chunking-form/samples/manual-chunks/_expected/amd/{deps2and3-0c5d98d0.js => deps2and3-609a33db.js} (86%) rename test/chunking-form/samples/manual-chunks/_expected/cjs/{deps2and3-9aeb2d5b.js => deps2and3-c8fe246d.js} (76%) diff --git a/src/Graph.ts b/src/Graph.ts index e66ba51227c..00abb33670b 100644 --- a/src/Graph.ts +++ b/src/Graph.ts @@ -23,9 +23,10 @@ import { Watcher } from './rollup/types'; import { finaliseAsset } from './utils/assetHooks'; +import { assignChunkColouringHashes } from './utils/chunkColouring'; import { Uint8ArrayToHexString } from './utils/entryHashing'; import error from './utils/error'; -import { analyzeModuleExecution, sortByExecutionOrder } from './utils/executionOrder'; +import { analyseModuleExecution, sortByExecutionOrder } from './utils/executionOrder'; import { isRelative, resolve } from './utils/path'; import { createPluginDriver, PluginDriver } from './utils/pluginDriver'; import relativeId, { getAliasName } from './utils/relativeId'; @@ -153,7 +154,7 @@ export default class Graph { this.shimMissingExports = options.shimMissingExports; this.scope = new GlobalScope(); - // TODO strictly speaking, this only applies with non-ES6, non-default-only bundles + // Strictly speaking, this only applies with non-ES6, non-default-only bundles for (const name of ['module', 'exports', '_interopDefault']) { this.scope.findVariable(name); // creates global variable as side-effect } @@ -370,11 +371,9 @@ export default class Graph { this.link(); - const { orderedModules, dynamicImports, cyclePaths } = analyzeModuleExecution( + const { orderedModules, dynamicImports, cyclePaths } = analyseModuleExecution( entryModules, - !preserveModules && !inlineDynamicImports, - inlineDynamicImports, - manualChunkModules + inlineDynamicImports ); for (const cyclePath of cyclePaths) { this.warn({ @@ -383,6 +382,9 @@ export default class Graph { message: `Circular dependency: ${cyclePath.join(' -> ')}` }); } + if (!preserveModules && !inlineDynamicImports) { + assignChunkColouringHashes(entryModules, dynamicImports, manualChunkModules); + } if (entryModuleAliases) { for (let i = entryModules.length - 1; i >= 0; i--) { diff --git a/src/rollup/index.ts b/src/rollup/index.ts index aea82a066ac..5b550decee4 100644 --- a/src/rollup/index.ts +++ b/src/rollup/index.ts @@ -205,11 +205,9 @@ export default function rollup( const singleInput = typeof inputOptions.input === 'string' || (inputOptions.input instanceof Array && inputOptions.input.length === 1); - //let imports: string[], exports: string[]; if (!inputOptions.experimentalPreserveModules) { if (singleInput) { for (const chunk of chunks) { - if (chunk.entryModule === undefined) continue; if (singleChunk) { singleChunk = undefined; break; diff --git a/src/utils/chunkColouring.ts b/src/utils/chunkColouring.ts new file mode 100644 index 00000000000..b1229bd7bfc --- /dev/null +++ b/src/utils/chunkColouring.ts @@ -0,0 +1,73 @@ +import ExternalModule from '../ExternalModule'; +import Module from '../Module'; +import { randomUint8Array, Uint8ArrayXor } from './entryHashing'; +import error from './error'; +import { relative } from './path'; + +export function assignChunkColouringHashes( + entryModules: Module[], + dynamicImports: Module[], + manualChunkModules: Record +) { + let currentEntry: Module, currentEntryHash: Uint8Array; + let modulesVisitedForCurrentEntry: { [id: string]: boolean }; + const handledEntryPoints: { [id: string]: boolean } = {}; + + const addCurrentEntryColourToModule = (module: Module) => { + if (currentEntry.chunkAlias) { + module.chunkAlias = currentEntry.chunkAlias; + module.entryPointsHash = currentEntryHash; + } else { + Uint8ArrayXor(module.entryPointsHash, currentEntryHash); + } + + for (const dependency of module.dependencies) { + if (dependency instanceof ExternalModule || dependency.id in modulesVisitedForCurrentEntry) { + continue; + } + modulesVisitedForCurrentEntry[dependency.id] = true; + if (!handledEntryPoints[dependency.id] && !dependency.chunkAlias) + addCurrentEntryColourToModule(dependency); + } + }; + + if (manualChunkModules) { + for (const chunkName of Object.keys(manualChunkModules)) { + currentEntryHash = randomUint8Array(10); + + for (currentEntry of manualChunkModules[chunkName]) { + if (currentEntry.chunkAlias) { + error({ + code: 'INVALID_CHUNK', + message: `Cannot assign ${relative( + process.cwd(), + currentEntry.id + )} to the "${chunkName}" chunk as it is already in the "${ + currentEntry.chunkAlias + }" chunk. +Try defining "${chunkName}" first in the manualChunks definitions of the Rollup configuration.` + }); + } + currentEntry.chunkAlias = chunkName; + modulesVisitedForCurrentEntry = { [currentEntry.id]: true }; + addCurrentEntryColourToModule(currentEntry); + } + } + } + + for (currentEntry of entryModules) { + handledEntryPoints[currentEntry.id] = true; + currentEntryHash = randomUint8Array(10); + modulesVisitedForCurrentEntry = { [currentEntry.id]: null }; + addCurrentEntryColourToModule(currentEntry); + } + + for (currentEntry of dynamicImports) { + if (handledEntryPoints[currentEntry.id]) { + continue; + } + currentEntryHash = randomUint8Array(10); + modulesVisitedForCurrentEntry = { [currentEntry.id]: null }; + addCurrentEntryColourToModule(currentEntry); + } +} diff --git a/src/utils/executionOrder.ts b/src/utils/executionOrder.ts index bbd33b80243..e358c4afc65 100644 --- a/src/utils/executionOrder.ts +++ b/src/utils/executionOrder.ts @@ -1,8 +1,5 @@ import ExternalModule from '../ExternalModule'; import Module from '../Module'; -import { randomUint8Array, Uint8ArrayEqual, Uint8ArrayXor } from './entryHashing'; -import error from './error'; -import { relative } from './path'; import relativeId from './relativeId'; interface OrderedExecutionUnit { @@ -16,119 +13,60 @@ export function sortByExecutionOrder(units: OrderedExecutionUnit[]) { units.sort(compareExecIndex); } -export function analyzeModuleExecution( - entryModules: Module[], - generateChunkColouringHashes: boolean, - inlineDynamicImports: boolean, - manualChunkModules: Record -) { - let curEntry: Module, curEntryHash: Uint8Array; +export function analyseModuleExecution(entryModules: Module[], inlineDynamicImports: boolean) { + let nextExecIndex = 0; const cyclePaths: string[][] = []; - const allSeen: { [id: string]: boolean } = {}; - + const analysedModules: { [id: string]: boolean } = {}; const orderedModules: Module[] = []; - let analyzedModuleCount = 0; - const dynamicImports: Module[] = []; + const parents: { [id: string]: string | null } = {}; - let parents: { [id: string]: string }; + const analyseModule = (module: Module | ExternalModule) => { + if (analysedModules[module.id]) return; - const visit = (module: Module) => { - // Track entry point graph colouring by tracing all modules loaded by a given - // entry point and colouring those modules by the hash of its id. Colours are mixed as - // hash xors, providing the unique colouring of the graph into unique hash chunks. - // This is really all there is to automated chunking, the rest is chunk wiring. - if (generateChunkColouringHashes) { - if (!curEntry.chunkAlias) { - Uint8ArrayXor(module.entryPointsHash, curEntryHash); - } else { - // manual chunks are indicated in this phase by having a chunk alias - // they are treated as a single colour in the colouring - // and aren't divisable by future colourings - module.chunkAlias = curEntry.chunkAlias; - module.entryPointsHash = curEntryHash; - } + if (module instanceof ExternalModule) { + module.execIndex = nextExecIndex++; + analysedModules[module.id] = true; + return; } - for (const depModule of module.dependencies) { - if (depModule instanceof ExternalModule) { - depModule.execIndex = analyzedModuleCount++; - continue; - } - - if (depModule.id in parents) { - if (!allSeen[depModule.id]) { - cyclePaths.push(getCyclePath(depModule.id, module.id, parents)); + for (const dependency of module.dependencies) { + if (dependency.id in parents) { + if (!analysedModules[dependency.id]) { + cyclePaths.push(getCyclePath(dependency.id, module.id, parents)); } continue; } - - parents[depModule.id] = module.id; - if (!depModule.isEntryPoint && !depModule.chunkAlias) visit(depModule); + parents[dependency.id] = module.id; + analyseModule(dependency); } for (const dynamicModule of module.dynamicImportResolutions) { if (!(dynamicModule.resolution instanceof Module)) continue; - // If the parent module of a dynamic import is to a child module whose graph - // colouring is the same as the parent module, then that dynamic import does - // not need to be treated as a new entry point as it is in the static graph - if ( - !generateChunkColouringHashes || - (!dynamicModule.resolution.chunkAlias && - !Uint8ArrayEqual(dynamicModule.resolution.entryPointsHash, curEntry.entryPointsHash)) - ) { - if (dynamicImports.indexOf(dynamicModule.resolution) === -1) { - dynamicImports.push(dynamicModule.resolution); - } + if (dynamicImports.indexOf(dynamicModule.resolution) === -1) { + dynamicImports.push(dynamicModule.resolution); } } - if (allSeen[module.id]) return; - allSeen[module.id] = true; - - module.execIndex = analyzedModuleCount++; + module.execIndex = nextExecIndex++; + analysedModules[module.id] = true; orderedModules.push(module); }; - if (generateChunkColouringHashes && manualChunkModules) { - for (const chunkName of Object.keys(manualChunkModules)) { - curEntryHash = randomUint8Array(10); - - for (curEntry of manualChunkModules[chunkName]) { - if (curEntry.chunkAlias) { - error({ - code: 'INVALID_CHUNK', - message: `Cannot assign ${relative( - process.cwd(), - curEntry.id - )} to the "${chunkName}" chunk as it is already in the "${curEntry.chunkAlias}" chunk. -Try defining "${chunkName}" first in the manualChunks definitions of the Rollup configuration.` - }); - } - curEntry.chunkAlias = chunkName; - parents = { [curEntry.id]: null }; - visit(curEntry); - } - } - } - - for (curEntry of entryModules) { + for (const curEntry of entryModules) { curEntry.isEntryPoint = true; - curEntryHash = randomUint8Array(10); - parents = { [curEntry.id]: null }; - visit(curEntry); + if (!parents[curEntry.id]) { + parents[curEntry.id] = null; + } + analyseModule(curEntry); } - // new items can be added during this loop - for (curEntry of dynamicImports) { - if (curEntry.isEntryPoint || curEntry.isDynamicEntryPoint) { - if (!inlineDynamicImports) curEntry.isDynamicEntryPoint = true; - continue; - } + for (const curEntry of dynamicImports) { if (!inlineDynamicImports) curEntry.isDynamicEntryPoint = true; - curEntryHash = randomUint8Array(10); - parents = { [curEntry.id]: null }; - visit(curEntry); + if (!parents[curEntry.id]) { + parents[curEntry.id] = null; + } + analyseModule(curEntry); } return { orderedModules, dynamicImports, cyclePaths }; diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_config.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_config.js index 703fbca1c5c..afe826a288e 100644 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/_config.js +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_config.js @@ -1,4 +1,5 @@ module.exports = { + skip: true, description: 'Dynamic import inlining for static colouring', options: { input: ['main.js'] diff --git a/test/chunking-form/samples/manual-chunks/_expected/amd/deps2and3-0c5d98d0.js b/test/chunking-form/samples/manual-chunks/_expected/amd/deps2and3-609a33db.js similarity index 86% rename from test/chunking-form/samples/manual-chunks/_expected/amd/deps2and3-0c5d98d0.js rename to test/chunking-form/samples/manual-chunks/_expected/amd/deps2and3-609a33db.js index b1034290429..a0f7deb92e5 100644 --- a/test/chunking-form/samples/manual-chunks/_expected/amd/deps2and3-0c5d98d0.js +++ b/test/chunking-form/samples/manual-chunks/_expected/amd/deps2and3-609a33db.js @@ -1,4 +1,4 @@ -define(['exports', './lib1-4c530ea2.js'], function (exports, __chunk_1) { 'use strict'; +define(['exports', './lib1-4c530ea2.js'], function (exports, __chunk_2) { 'use strict'; function fn () { console.log('lib2 fn'); @@ -10,7 +10,7 @@ define(['exports', './lib1-4c530ea2.js'], function (exports, __chunk_1) { 'use s } function fn$2 () { - __chunk_1.fn(); + __chunk_2.fn(); console.log('dep3 fn'); } diff --git a/test/chunking-form/samples/manual-chunks/_expected/amd/main.js b/test/chunking-form/samples/manual-chunks/_expected/amd/main.js index 8fc40e0fd45..4a0362d0325 100644 --- a/test/chunking-form/samples/manual-chunks/_expected/amd/main.js +++ b/test/chunking-form/samples/manual-chunks/_expected/amd/main.js @@ -1,4 +1,4 @@ -define(['./deps2and3-0c5d98d0.js', './lib1-4c530ea2.js'], function (__chunk_2, __chunk_1) { 'use strict'; +define(['./deps2and3-609a33db.js', './lib1-4c530ea2.js'], function (__chunk_1, __chunk_2) { 'use strict'; function fn () { console.log('dep1 fn'); @@ -7,8 +7,8 @@ define(['./deps2and3-0c5d98d0.js', './lib1-4c530ea2.js'], function (__chunk_2, _ class Main { constructor () { fn(); - __chunk_2.fn(); - __chunk_2.fn$1(); + __chunk_1.fn(); + __chunk_1.fn$1(); } } diff --git a/test/chunking-form/samples/manual-chunks/_expected/cjs/deps2and3-9aeb2d5b.js b/test/chunking-form/samples/manual-chunks/_expected/cjs/deps2and3-c8fe246d.js similarity index 76% rename from test/chunking-form/samples/manual-chunks/_expected/cjs/deps2and3-9aeb2d5b.js rename to test/chunking-form/samples/manual-chunks/_expected/cjs/deps2and3-c8fe246d.js index 4cac9e0c18f..48858923108 100644 --- a/test/chunking-form/samples/manual-chunks/_expected/cjs/deps2and3-9aeb2d5b.js +++ b/test/chunking-form/samples/manual-chunks/_expected/cjs/deps2and3-c8fe246d.js @@ -1,6 +1,6 @@ 'use strict'; -var __chunk_1 = require('./lib1-569e10cd.js'); +var __chunk_2 = require('./lib1-569e10cd.js'); function fn () { console.log('lib2 fn'); @@ -12,7 +12,7 @@ function fn$1 () { } function fn$2 () { - __chunk_1.fn(); + __chunk_2.fn(); console.log('dep3 fn'); } diff --git a/test/chunking-form/samples/manual-chunks/_expected/cjs/main.js b/test/chunking-form/samples/manual-chunks/_expected/cjs/main.js index a0e922407f9..da0bec22859 100644 --- a/test/chunking-form/samples/manual-chunks/_expected/cjs/main.js +++ b/test/chunking-form/samples/manual-chunks/_expected/cjs/main.js @@ -1,6 +1,6 @@ 'use strict'; -var __chunk_2 = require('./deps2and3-9aeb2d5b.js'); +var __chunk_1 = require('./deps2and3-c8fe246d.js'); require('./lib1-569e10cd.js'); function fn () { @@ -10,8 +10,8 @@ function fn () { class Main { constructor () { fn(); - __chunk_2.fn(); - __chunk_2.fn$1(); + __chunk_1.fn(); + __chunk_1.fn$1(); } } From 4434d92f4d531f3c8a94d6de41a84fd90ad110c0 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sun, 18 Nov 2018 16:44:36 +0100 Subject: [PATCH 08/23] Prefer named export and do not mix for better IDE support --- src/Chunk.ts | 2 +- src/Graph.ts | 2 +- src/Module.ts | 2 +- src/finalisers/iife.ts | 2 +- src/finalisers/umd.ts | 2 +- src/rollup/index.ts | 2 +- src/utils/addons.ts | 2 +- src/utils/assetHooks.ts | 2 +- src/utils/chunkColouring.ts | 2 +- src/utils/collapseSourcemaps.ts | 2 +- src/utils/defaultPlugin.ts | 2 +- src/utils/error.ts | 2 +- src/utils/getExportMode.ts | 2 +- src/utils/pluginDriver.ts | 2 +- src/utils/renderChunk.ts | 2 +- src/utils/renderNamePattern.ts | 2 +- src/utils/transform.ts | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Chunk.ts b/src/Chunk.ts index a3d060a56fd..09c8494a21f 100644 --- a/src/Chunk.ts +++ b/src/Chunk.ts @@ -22,7 +22,7 @@ import { import { Addons } from './utils/addons'; import { toBase64 } from './utils/base64'; import collapseSourcemaps from './utils/collapseSourcemaps'; -import error from './utils/error'; +import { error } from './utils/error'; import { sortByExecutionOrder } from './utils/executionOrder'; import getIndentString from './utils/getIndentString'; import { makeLegal } from './utils/identifierHelpers'; diff --git a/src/Graph.ts b/src/Graph.ts index 00abb33670b..fe6cf71e9bd 100644 --- a/src/Graph.ts +++ b/src/Graph.ts @@ -25,7 +25,7 @@ import { import { finaliseAsset } from './utils/assetHooks'; import { assignChunkColouringHashes } from './utils/chunkColouring'; import { Uint8ArrayToHexString } from './utils/entryHashing'; -import error from './utils/error'; +import { error } from './utils/error'; import { analyseModuleExecution, sortByExecutionOrder } from './utils/executionOrder'; import { isRelative, resolve } from './utils/path'; import { createPluginDriver, PluginDriver } from './utils/pluginDriver'; diff --git a/src/Module.ts b/src/Module.ts index 6b7035fb466..f6bec94983f 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -28,7 +28,7 @@ import Chunk from './Chunk'; import ExternalModule from './ExternalModule'; import Graph from './Graph'; import { Asset, IdMap, ModuleJSON, RawSourceMap, RollupError, RollupWarning } from './rollup/types'; -import error from './utils/error'; +import { error } from './utils/error'; import getCodeFrame from './utils/getCodeFrame'; import { getOriginalLocation } from './utils/getOriginalLocation'; import { makeLegal } from './utils/identifierHelpers'; diff --git a/src/finalisers/iife.ts b/src/finalisers/iife.ts index 7fe45c4e7d3..60d477e24d5 100644 --- a/src/finalisers/iife.ts +++ b/src/finalisers/iife.ts @@ -1,6 +1,6 @@ import { Bundle as MagicStringBundle } from 'magic-string'; import { OutputOptions } from '../rollup/types'; -import error from '../utils/error'; +import { error } from '../utils/error'; import { isLegal } from '../utils/identifierHelpers'; import { FinaliserOptions } from './index'; import getExportBlock from './shared/getExportBlock'; diff --git a/src/finalisers/umd.ts b/src/finalisers/umd.ts index 8127ff12b2e..92b1834ce29 100644 --- a/src/finalisers/umd.ts +++ b/src/finalisers/umd.ts @@ -1,6 +1,6 @@ import { Bundle as MagicStringBundle } from 'magic-string'; import { OutputOptions } from '../rollup/types'; -import error from '../utils/error'; +import { error } from '../utils/error'; import { FinaliserOptions } from './index'; import { compactEsModuleExport, esModuleExport } from './shared/esModuleExport'; import getExportBlock from './shared/getExportBlock'; diff --git a/src/rollup/index.ts b/src/rollup/index.ts index 5b550decee4..40857c7286e 100644 --- a/src/rollup/index.ts +++ b/src/rollup/index.ts @@ -6,7 +6,7 @@ import { createAssetPluginHooks, finaliseAsset } from '../utils/assetHooks'; import { assignChunkIds } from '../utils/assignChunkIds'; import commondir from '../utils/commondir'; import { Deprecation } from '../utils/deprecateOptions'; -import error from '../utils/error'; +import { error } from '../utils/error'; import { writeFile } from '../utils/fs'; import getExportMode from '../utils/getExportMode'; import mergeOptions, { GenericConfigObject } from '../utils/mergeOptions'; diff --git a/src/utils/addons.ts b/src/utils/addons.ts index f55a0bf394d..d4705048ffc 100644 --- a/src/utils/addons.ts +++ b/src/utils/addons.ts @@ -1,6 +1,6 @@ import Graph from '../Graph'; import { OutputOptions } from '../rollup/types'; -import error from './error'; +import { error } from './error'; export interface Addons { intro?: string; diff --git a/src/utils/assetHooks.ts b/src/utils/assetHooks.ts index dc062c15311..a800f1845d0 100644 --- a/src/utils/assetHooks.ts +++ b/src/utils/assetHooks.ts @@ -1,6 +1,6 @@ import sha256 from 'hash.js/lib/hash/sha/256'; import { Asset, OutputBundle } from '../rollup/types'; -import error from './error'; +import { error } from './error'; import { extname } from './path'; import { isPlainName } from './relativeId'; import { makeUnique, renderNamePattern } from './renderNamePattern'; diff --git a/src/utils/chunkColouring.ts b/src/utils/chunkColouring.ts index b1229bd7bfc..8ed961b4c72 100644 --- a/src/utils/chunkColouring.ts +++ b/src/utils/chunkColouring.ts @@ -1,7 +1,7 @@ import ExternalModule from '../ExternalModule'; import Module from '../Module'; import { randomUint8Array, Uint8ArrayXor } from './entryHashing'; -import error from './error'; +import { error } from './error'; import { relative } from './path'; export function assignChunkColouringHashes( diff --git a/src/utils/collapseSourcemaps.ts b/src/utils/collapseSourcemaps.ts index 1f624c0eba0..8c2da89822b 100644 --- a/src/utils/collapseSourcemaps.ts +++ b/src/utils/collapseSourcemaps.ts @@ -2,7 +2,7 @@ import { DecodedSourceMap, SourceMap } from 'magic-string'; import Chunk from '../Chunk'; import Module from '../Module'; import { ExistingRawSourceMap, RawSourceMap } from '../rollup/types'; -import error from './error'; +import { error } from './error'; import { basename, dirname, relative, resolve } from './path'; class Source { diff --git a/src/utils/defaultPlugin.ts b/src/utils/defaultPlugin.ts index 6997e175d79..6478e6a3410 100644 --- a/src/utils/defaultPlugin.ts +++ b/src/utils/defaultPlugin.ts @@ -1,5 +1,5 @@ import { InputOptions, Plugin } from '../rollup/types'; -import error from './error'; +import { error } from './error'; import { lstatSync, readdirSync, readFileSync, realpathSync } from './fs'; // eslint-disable-line import { basename, dirname, isAbsolute, resolve } from './path'; diff --git a/src/utils/error.ts b/src/utils/error.ts index b9e94049bb1..b7a20fc3f55 100644 --- a/src/utils/error.ts +++ b/src/utils/error.ts @@ -2,7 +2,7 @@ import { locate } from 'locate-character'; import { RollupError, RollupWarning } from '../rollup/types'; import getCodeFrame from './getCodeFrame'; -export default function error(base: Error | RollupError, props?: RollupError) { +export function error(base: Error | RollupError, props?: RollupError) { if (base instanceof Error === false) base = Object.assign(new Error(base.message), base); if (props) Object.assign(base, props); throw base; diff --git a/src/utils/getExportMode.ts b/src/utils/getExportMode.ts index 8a20416a61d..3c63cba6d59 100644 --- a/src/utils/getExportMode.ts +++ b/src/utils/getExportMode.ts @@ -1,6 +1,6 @@ import Chunk from '../Chunk'; import { OutputOptions } from '../rollup/types'; -import error from './error'; +import { error } from './error'; function badExports(option: string, keys: string[]) { error({ diff --git a/src/utils/pluginDriver.ts b/src/utils/pluginDriver.ts index 9715317c3de..959872ca9e9 100644 --- a/src/utils/pluginDriver.ts +++ b/src/utils/pluginDriver.ts @@ -12,7 +12,7 @@ import { } from '../rollup/types'; import { createAssetPluginHooks, EmitAsset } from './assetHooks'; import { getRollupDefaultPlugin } from './defaultPlugin'; -import error from './error'; +import { error } from './error'; export interface PluginDriver { emitAsset: EmitAsset; diff --git a/src/utils/renderChunk.ts b/src/utils/renderChunk.ts index 0fb3aff5a62..2056538ccb1 100644 --- a/src/utils/renderChunk.ts +++ b/src/utils/renderChunk.ts @@ -2,7 +2,7 @@ import { decode } from 'sourcemap-codec'; import Chunk from '../Chunk'; import Graph from '../Graph'; import { OutputOptions, Plugin, RawSourceMap, RenderedChunk } from '../rollup/types'; -import error from './error'; +import { error } from './error'; export default function renderChunk({ graph, diff --git a/src/utils/renderNamePattern.ts b/src/utils/renderNamePattern.ts index 765cbf336dd..12e14666b83 100644 --- a/src/utils/renderNamePattern.ts +++ b/src/utils/renderNamePattern.ts @@ -1,4 +1,4 @@ -import error from './error'; +import { error } from './error'; import { extname } from './path'; import { isPlainName } from './relativeId'; diff --git a/src/utils/transform.ts b/src/utils/transform.ts index 29c2b901554..45c20c8f6c1 100644 --- a/src/utils/transform.ts +++ b/src/utils/transform.ts @@ -13,7 +13,7 @@ import { TransformSourceDescription } from '../rollup/types'; import { createTransformEmitAsset, EmitAsset } from './assetHooks'; -import error, { augmentCodeLocation } from './error'; +import { augmentCodeLocation, error } from './error'; import { dirname, resolve } from './path'; import { trackPluginCache } from './pluginDriver'; From 3a52ba6ec03753f18ea9650216ced86e68287a79 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Tue, 20 Nov 2018 07:21:07 +0100 Subject: [PATCH 09/23] Move chunk colouring behind tree-shaking and add more tests --- src/Chunk.ts | 4 +- src/Graph.ts | 55 ++++----- src/Module.ts | 11 +- src/utils/chunkColouring.ts | 22 +++- src/utils/executionOrder.ts | 12 +- .../_config.js | 3 +- .../_expected/amd/chunk-a2558f00.js | 9 ++ .../_expected/amd/main.js | 15 --- .../_expected/amd/main1.js | 19 ++++ .../_expected/amd/main2.js | 9 ++ .../_expected/cjs/chunk-bc97caee.js | 7 ++ .../_expected/cjs/main.js | 13 --- .../_expected/cjs/main1.js | 19 ++++ .../_expected/cjs/main2.js | 7 ++ .../_expected/es/chunk-61f7224d.js | 5 + .../_expected/es/main.js | 11 -- .../_expected/es/main1.js | 14 +++ .../_expected/es/main2.js | 3 + .../_expected/system/chunk-9df34bdb.js | 11 ++ .../_expected/system/main.js | 18 --- .../_expected/system/main1.js | 20 ++++ .../_expected/system/main2.js | 10 ++ .../dynamic-import-inline-colouring/foo.js | 2 - .../inlined.js | 2 + .../dynamic-import-inline-colouring/main.js | 3 - .../dynamic-import-inline-colouring/main1.js | 5 + .../dynamic-import-inline-colouring/main2.js | 1 + .../separate.js | 2 + .../_config.js | 7 ++ .../_expected/amd/dynamic-included.js | 7 ++ .../_expected/amd/main.js | 5 + .../_expected/cjs/dynamic-included.js | 5 + .../_expected/cjs/main.js | 3 + .../_expected/es/dynamic-included.js | 3 + .../_expected/es/main.js | 1 + .../_expected/system/dynamic-included.js | 10 ++ .../_expected/system/main.js | 10 ++ .../dynamic-included.js | 1 + .../dynamic-removed.js | 1 + .../preserve-modules-dynamic-imports/main.js | 6 + .../samples/dynamic-import-inlining/main.js | 5 +- .../inline-imports-with-manual/_config.js | 15 +++ .../samples/inline-imports-with-manual/lib.js | 1 + .../inline-imports-with-manual/main.js | 1 + .../inline-imports-with-multiple/_config.js | 12 ++ .../inline-imports-with-multiple/lib.js | 1 + .../inline-imports-with-multiple/main.js | 1 + .../inline-imports-with-optimize/_config.js | 13 +++ .../inline-imports-with-optimize/lib.js | 1 + .../inline-imports-with-optimize/main.js | 1 + .../preserve-modules-with-inline/_config.js | 13 +++ .../preserve-modules-with-inline/lib.js | 1 + .../preserve-modules-with-inline/main.js | 1 + .../preserve-modules-with-manual/_config.js | 15 +++ .../preserve-modules-with-manual/lib.js | 1 + .../preserve-modules-with-manual/main.js | 3 + .../preserve-modules-with-optimize/_config.js | 13 +++ .../preserve-modules-with-optimize/lib.js | 1 + .../preserve-modules-with-optimize/main.js | 3 + test/misc/bundle-information.js | 106 ++++++++++++++++++ 60 files changed, 464 insertions(+), 115 deletions(-) create mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/chunk-a2558f00.js delete mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main.js create mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main1.js create mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main2.js create mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/chunk-bc97caee.js delete mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main.js create mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main1.js create mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main2.js create mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/chunk-61f7224d.js delete mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main.js create mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main1.js create mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main2.js create mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/chunk-9df34bdb.js delete mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main.js create mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main1.js create mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main2.js delete mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/foo.js create mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/inlined.js delete mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/main.js create mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/main1.js create mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/main2.js create mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/separate.js create mode 100644 test/chunking-form/samples/preserve-modules-dynamic-imports/_config.js create mode 100644 test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/amd/dynamic-included.js create mode 100644 test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/amd/main.js create mode 100644 test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/cjs/dynamic-included.js create mode 100644 test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/cjs/main.js create mode 100644 test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/es/dynamic-included.js create mode 100644 test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/es/main.js create mode 100644 test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/system/dynamic-included.js create mode 100644 test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/system/main.js create mode 100644 test/chunking-form/samples/preserve-modules-dynamic-imports/dynamic-included.js create mode 100644 test/chunking-form/samples/preserve-modules-dynamic-imports/dynamic-removed.js create mode 100644 test/chunking-form/samples/preserve-modules-dynamic-imports/main.js create mode 100644 test/function/samples/inline-imports-with-manual/_config.js create mode 100644 test/function/samples/inline-imports-with-manual/lib.js create mode 100644 test/function/samples/inline-imports-with-manual/main.js create mode 100644 test/function/samples/inline-imports-with-multiple/_config.js create mode 100644 test/function/samples/inline-imports-with-multiple/lib.js create mode 100644 test/function/samples/inline-imports-with-multiple/main.js create mode 100644 test/function/samples/inline-imports-with-optimize/_config.js create mode 100644 test/function/samples/inline-imports-with-optimize/lib.js create mode 100644 test/function/samples/inline-imports-with-optimize/main.js create mode 100644 test/function/samples/preserve-modules-with-inline/_config.js create mode 100644 test/function/samples/preserve-modules-with-inline/lib.js create mode 100644 test/function/samples/preserve-modules-with-inline/main.js create mode 100644 test/function/samples/preserve-modules-with-manual/_config.js create mode 100644 test/function/samples/preserve-modules-with-manual/lib.js create mode 100644 test/function/samples/preserve-modules-with-manual/main.js create mode 100644 test/function/samples/preserve-modules-with-optimize/_config.js create mode 100644 test/function/samples/preserve-modules-with-optimize/lib.js create mode 100644 test/function/samples/preserve-modules-with-optimize/main.js diff --git a/src/Chunk.ts b/src/Chunk.ts index 09c8494a21f..6a400d270b3 100644 --- a/src/Chunk.ts +++ b/src/Chunk.ts @@ -146,7 +146,7 @@ export default class Chunk { } = undefined; private chunkName: string | void; - constructor(graph: Graph, orderedModules: Module[]) { + constructor(graph: Graph, orderedModules: Module[], inlineDynamicImports: boolean) { this.graph = graph; this.orderedModules = orderedModules; this.execIndex = orderedModules.length > 0 ? orderedModules[0].execIndex : Infinity; @@ -164,7 +164,7 @@ export default class Chunk { this.entryModule = module; this.isEntryModuleFacade = true; } - if (module.isDynamicEntryPoint) { + if (module.isDynamicEntryPoint && !inlineDynamicImports) { this.isDynamicEntryPoint = true; if (!this.entryModule) { this.entryModule = module; diff --git a/src/Graph.ts b/src/Graph.ts index fe6cf71e9bd..d9cd311ae2f 100644 --- a/src/Graph.ts +++ b/src/Graph.ts @@ -56,6 +56,7 @@ export default class Graph { moduleById = new Map(); assetsById = new Map(); modules: Module[] = []; + needsTreeshakingPass: boolean = false; onwarn: WarningHandler; deoptimizationTracker: EntityPathTracker; scope: GlobalScope; @@ -262,18 +263,15 @@ export default class Graph { includeMarked(modules: Module[]) { if (this.treeshake) { - let needsTreeshakingPass, - treeshakingPass = 1; + let treeshakingPass = 1; do { timeStart(`treeshaking pass ${treeshakingPass}`, 3); - needsTreeshakingPass = false; + this.needsTreeshakingPass = false; for (const module of modules) { - if (module.include()) { - needsTreeshakingPass = true; - } + module.include(); } timeEnd(`treeshaking pass ${treeshakingPass++}`, 3); - } while (needsTreeshakingPass); + } while (this.needsTreeshakingPass); } else { // Necessary to properly replace namespace imports for (const module of modules) module.includeAllInBundle(); @@ -371,10 +369,7 @@ export default class Graph { this.link(); - const { orderedModules, dynamicImports, cyclePaths } = analyseModuleExecution( - entryModules, - inlineDynamicImports - ); + const { orderedModules, cyclePaths } = analyseModuleExecution(entryModules); for (const cyclePath of cyclePaths) { this.warn({ code: 'CIRCULAR_DEPENDENCY', @@ -382,33 +377,19 @@ export default class Graph { message: `Circular dependency: ${cyclePath.join(' -> ')}` }); } - if (!preserveModules && !inlineDynamicImports) { - assignChunkColouringHashes(entryModules, dynamicImports, manualChunkModules); - } - if (entryModuleAliases) { - for (let i = entryModules.length - 1; i >= 0; i--) { - entryModules[i].chunkAlias = entryModuleAliases[i]; - } - } + timeEnd('analyse dependency graph', 2); + + // Phase 3 – marking. We include all statements that should be included + timeStart('mark included statements', 2); if (inlineDynamicImports) { if (entryModules.length > 1) throw new Error( 'Internal Error: can only inline dynamic imports for single-file builds.' ); - for (const dynamicImportModule of dynamicImports) { - dynamicImportModule.getOrCreateNamespace().include(); - } } - - timeEnd('analyse dependency graph', 2); - - // Phase 3 – marking. We include all statements that should be included - timeStart('mark included statements', 2); - for (const entryModule of entryModules) entryModule.includeAllExports(); - // only include statements that should appear in the bundle this.includeMarked(orderedModules); // check for unused external imports @@ -420,6 +401,16 @@ export default class Graph { // entry point graph colouring, before generating the import and export facades timeStart('generate chunks', 2); + if (!preserveModules && !inlineDynamicImports) { + assignChunkColouringHashes(entryModules, manualChunkModules); + } + + if (entryModuleAliases) { + for (let i = entryModules.length - 1; i >= 0; i--) { + entryModules[i].chunkAlias = entryModuleAliases[i]; + } + } + // TODO: there is one special edge case unhandled here and that is that any module // exposed as an unresolvable export * (to a graph external export *, // either as a namespace import reexported or top-level export *) @@ -427,7 +418,7 @@ export default class Graph { let chunks: Chunk[] = []; if (preserveModules) { for (const module of orderedModules) { - const chunk = new Chunk(this, [module]); + const chunk = new Chunk(this, [module], inlineDynamicImports); if (module.isEntryPoint || !chunk.isEmpty) chunk.entryModule = module; chunks.push(chunk); } @@ -446,7 +437,7 @@ export default class Graph { for (const entryHashSum in chunkModules) { const chunkModulesOrdered = chunkModules[entryHashSum]; sortByExecutionOrder(chunkModulesOrdered); - const chunk = new Chunk(this, chunkModulesOrdered); + const chunk = new Chunk(this, chunkModulesOrdered, inlineDynamicImports); chunks.push(chunk); } } @@ -473,7 +464,7 @@ export default class Graph { if (!preserveModules) { for (const entryModule of entryModules) { if (!entryModule.chunk.isEntryModuleFacade) { - const entryPointFacade = new Chunk(this, []); + const entryPointFacade = new Chunk(this, [], inlineDynamicImports); entryPointFacade.linkFacade(entryModule); chunks.push(entryPointFacade); } diff --git a/src/Module.ts b/src/Module.ts index f6bec94983f..48da0241e77 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -190,7 +190,6 @@ export default class Module { private namespaceVariable: NamespaceVariable = undefined; private esTreeAst: ESTree.Program; private magicString: MagicString; - private needsTreeshakingPass: boolean = false; private transformDependencies: string[]; constructor(graph: Graph, id: string) { @@ -284,7 +283,7 @@ export default class Module { propertyReadSideEffects: !this.graph.treeshake || this.graph.treeshakingOptions.propertyReadSideEffects, deoptimizationTracker: this.graph.deoptimizationTracker, - requestTreeshakingPass: () => (this.needsTreeshakingPass = true), + requestTreeshakingPass: () => (this.graph.needsTreeshakingPass = true), traceExport: this.traceExport.bind(this), traceVariable: this.traceVariable.bind(this), treeshake: this.graph.treeshake, @@ -456,7 +455,7 @@ export default class Module { variable.deoptimizePath(UNKNOWN_PATH); if (!variable.included) { variable.include(); - this.needsTreeshakingPass = true; + this.graph.needsTreeshakingPass = true; } if (variable.isNamespace) { @@ -472,7 +471,7 @@ export default class Module { } else if (!variable.included) { variable.include(); variable.deoptimizePath(UNKNOWN_PATH); - this.needsTreeshakingPass = true; + this.graph.needsTreeshakingPass = true; } } } @@ -612,10 +611,8 @@ export default class Module { return this.ast.included; } - include(): boolean { - this.needsTreeshakingPass = false; + include(): void { if (this.ast.shouldBeIncluded()) this.ast.include(false); - return this.needsTreeshakingPass; } getOrCreateNamespace(): NamespaceVariable { diff --git a/src/utils/chunkColouring.ts b/src/utils/chunkColouring.ts index 8ed961b4c72..07c2f526d70 100644 --- a/src/utils/chunkColouring.ts +++ b/src/utils/chunkColouring.ts @@ -1,17 +1,17 @@ import ExternalModule from '../ExternalModule'; import Module from '../Module'; -import { randomUint8Array, Uint8ArrayXor } from './entryHashing'; +import { randomUint8Array, Uint8ArrayEqual, Uint8ArrayXor } from './entryHashing'; import { error } from './error'; import { relative } from './path'; export function assignChunkColouringHashes( entryModules: Module[], - dynamicImports: Module[], manualChunkModules: Record ) { let currentEntry: Module, currentEntryHash: Uint8Array; let modulesVisitedForCurrentEntry: { [id: string]: boolean }; const handledEntryPoints: { [id: string]: boolean } = {}; + const dynamicImports: Module[] = []; const addCurrentEntryColourToModule = (module: Module) => { if (currentEntry.chunkAlias) { @@ -29,6 +29,24 @@ export function assignChunkColouringHashes( if (!handledEntryPoints[dependency.id] && !dependency.chunkAlias) addCurrentEntryColourToModule(dependency); } + + for (const dynamicModule of module.dynamicImportResolutions) { + if (dynamicModule.resolution instanceof Module) { + if ( + dynamicModule.resolution.chunkAlias || + Uint8ArrayEqual(dynamicModule.resolution.entryPointsHash, currentEntry.entryPointsHash) + ) { + // We only assign separate colouring to a dynamic entry if it is not already + // part of the graph of a single entry point or a manual chunk + dynamicModule.resolution.isDynamicEntryPoint = false; + } else { + dynamicModule.resolution.isDynamicEntryPoint = true; + if (dynamicImports.indexOf(dynamicModule.resolution) === -1) { + dynamicImports.push(dynamicModule.resolution); + } + } + } + } }; if (manualChunkModules) { diff --git a/src/utils/executionOrder.ts b/src/utils/executionOrder.ts index e358c4afc65..6eff1e95213 100644 --- a/src/utils/executionOrder.ts +++ b/src/utils/executionOrder.ts @@ -13,7 +13,7 @@ export function sortByExecutionOrder(units: OrderedExecutionUnit[]) { units.sort(compareExecIndex); } -export function analyseModuleExecution(entryModules: Module[], inlineDynamicImports: boolean) { +export function analyseModuleExecution(entryModules: Module[]) { let nextExecIndex = 0; const cyclePaths: string[][] = []; const analysedModules: { [id: string]: boolean } = {}; @@ -42,8 +42,10 @@ export function analyseModuleExecution(entryModules: Module[], inlineDynamicImpo } for (const dynamicModule of module.dynamicImportResolutions) { - if (!(dynamicModule.resolution instanceof Module)) continue; - if (dynamicImports.indexOf(dynamicModule.resolution) === -1) { + if ( + dynamicModule.resolution instanceof Module && + dynamicImports.indexOf(dynamicModule.resolution) === -1 + ) { dynamicImports.push(dynamicModule.resolution); } } @@ -62,14 +64,14 @@ export function analyseModuleExecution(entryModules: Module[], inlineDynamicImpo } for (const curEntry of dynamicImports) { - if (!inlineDynamicImports) curEntry.isDynamicEntryPoint = true; + curEntry.isDynamicEntryPoint = true; if (!parents[curEntry.id]) { parents[curEntry.id] = null; } analyseModule(curEntry); } - return { orderedModules, dynamicImports, cyclePaths }; + return { orderedModules, cyclePaths }; } function getCyclePath(id: string, parentId: string, parents: { [id: string]: string | null }) { diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_config.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_config.js index afe826a288e..3455a5a1653 100644 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/_config.js +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_config.js @@ -1,7 +1,6 @@ module.exports = { - skip: true, description: 'Dynamic import inlining for static colouring', options: { - input: ['main.js'] + input: ['main1.js', 'main2.js'] } }; diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/chunk-a2558f00.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/chunk-a2558f00.js new file mode 100644 index 00000000000..c06b72922c5 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/chunk-a2558f00.js @@ -0,0 +1,9 @@ +define(['exports'], function (exports) { 'use strict'; + + var separate = 'separate'; + const x = 2; + + exports.default = separate; + exports.x = x; + +}); diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main.js deleted file mode 100644 index 2bf301b34c8..00000000000 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main.js +++ /dev/null @@ -1,15 +0,0 @@ -define(['require'], function (require) { 'use strict'; - - var foo = "FOO"; - const x = 2; - - var foo$1 = /*#__PURE__*/Object.freeze({ - default: foo, - x: x - }); - - var main = Promise.resolve().then(function () { return foo$1; }); - - return main; - -}); diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main1.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main1.js new file mode 100644 index 00000000000..feb411419db --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main1.js @@ -0,0 +1,19 @@ +define(['require', 'exports', './chunk-a2558f00.js'], function (require, exports, separate_js) { 'use strict'; + + var inlined = 'inlined'; + const x = 1; + + var inlined$1 = /*#__PURE__*/Object.freeze({ + default: inlined, + x: x + }); + + const inlined$2 = Promise.resolve().then(function () { return inlined$1; }); + const separate = new Promise(function (resolve, reject) { require(["./chunk-a2558f00.js"], resolve, reject) }); + + exports.inlined = inlined$2; + exports.separate = separate; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}); diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main2.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main2.js new file mode 100644 index 00000000000..035ef97d78d --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main2.js @@ -0,0 +1,9 @@ +define(['require', 'exports'], function (require, exports) { 'use strict'; + + const separate = new Promise(function (resolve, reject) { require(["./chunk-a2558f00.js"], resolve, reject) }); + + exports.separate = separate; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}); diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/chunk-bc97caee.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/chunk-bc97caee.js new file mode 100644 index 00000000000..6eb315e5cac --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/chunk-bc97caee.js @@ -0,0 +1,7 @@ +'use strict'; + +var separate = 'separate'; +const x = 2; + +exports.default = separate; +exports.x = x; diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main.js deleted file mode 100644 index 9fb50d19ce9..00000000000 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main.js +++ /dev/null @@ -1,13 +0,0 @@ -'use strict'; - -var foo = "FOO"; -const x = 2; - -var foo$1 = /*#__PURE__*/Object.freeze({ - default: foo, - x: x -}); - -var main = Promise.resolve().then(function () { return foo$1; }); - -module.exports = main; diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main1.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main1.js new file mode 100644 index 00000000000..70618272b71 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main1.js @@ -0,0 +1,19 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +require('./chunk-bc97caee.js'); + +var inlined = 'inlined'; +const x = 1; + +var inlined$1 = /*#__PURE__*/Object.freeze({ + default: inlined, + x: x +}); + +const inlined$2 = Promise.resolve().then(function () { return inlined$1; }); +const separate = Promise.resolve(require("./chunk-bc97caee.js")); + +exports.inlined = inlined$2; +exports.separate = separate; diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main2.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main2.js new file mode 100644 index 00000000000..4f8fc54321b --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main2.js @@ -0,0 +1,7 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +const separate = Promise.resolve(require("./chunk-bc97caee.js")); + +exports.separate = separate; diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/chunk-61f7224d.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/chunk-61f7224d.js new file mode 100644 index 00000000000..e7122e67004 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/chunk-61f7224d.js @@ -0,0 +1,5 @@ +var separate = 'separate'; +const x = 2; + +export default separate; +export { x }; diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main.js deleted file mode 100644 index 34c9cbc8357..00000000000 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main.js +++ /dev/null @@ -1,11 +0,0 @@ -var foo = "FOO"; -const x = 2; - -var foo$1 = /*#__PURE__*/Object.freeze({ - default: foo, - x: x -}); - -var main = Promise.resolve().then(function () { return foo$1; }); - -export default main; diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main1.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main1.js new file mode 100644 index 00000000000..cc5950d949a --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main1.js @@ -0,0 +1,14 @@ +import './chunk-61f7224d.js'; + +var inlined = 'inlined'; +const x = 1; + +var inlined$1 = /*#__PURE__*/Object.freeze({ + default: inlined, + x: x +}); + +const inlined$2 = Promise.resolve().then(function () { return inlined$1; }); +const separate = import("./chunk-61f7224d.js"); + +export { inlined$2 as inlined, separate }; diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main2.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main2.js new file mode 100644 index 00000000000..1398bd14f8e --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main2.js @@ -0,0 +1,3 @@ +const separate = import("./chunk-61f7224d.js"); + +export { separate }; diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/chunk-9df34bdb.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/chunk-9df34bdb.js new file mode 100644 index 00000000000..a6804f10504 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/chunk-9df34bdb.js @@ -0,0 +1,11 @@ +System.register([], function (exports, module) { + 'use strict'; + return { + execute: function () { + + var separate = exports('default', 'separate'); + const x = exports('x', 2); + + } + }; +}); diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main.js deleted file mode 100644 index 25ee215a741..00000000000 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main.js +++ /dev/null @@ -1,18 +0,0 @@ -System.register([], function (exports, module) { - 'use strict'; - return { - execute: function () { - - var foo = "FOO"; - const x = 2; - - var foo$1 = /*#__PURE__*/Object.freeze({ - default: foo, - x: x - }); - - var main = exports('default', Promise.resolve().then(function () { return foo$1; })); - - } - }; -}); diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main1.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main1.js new file mode 100644 index 00000000000..367d61a8569 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main1.js @@ -0,0 +1,20 @@ +System.register(['./chunk-9df34bdb.js'], function (exports, module) { + 'use strict'; + return { + setters: [function () {}], + execute: function () { + + var inlined = 'inlined'; + const x = 1; + + var inlined$1 = /*#__PURE__*/Object.freeze({ + default: inlined, + x: x + }); + + const inlined$2 = exports('inlined', Promise.resolve().then(function () { return inlined$1; })); + const separate = exports('separate', module.import("./chunk-9df34bdb.js")); + + } + }; +}); diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main2.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main2.js new file mode 100644 index 00000000000..18a6031b7a0 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main2.js @@ -0,0 +1,10 @@ +System.register([], function (exports, module) { + 'use strict'; + return { + execute: function () { + + const separate = exports('separate', module.import("./chunk-9df34bdb.js")); + + } + }; +}); diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/foo.js b/test/chunking-form/samples/dynamic-import-inline-colouring/foo.js deleted file mode 100644 index 6d568106adb..00000000000 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/foo.js +++ /dev/null @@ -1,2 +0,0 @@ -export default "FOO"; -export const x = 2 diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/inlined.js b/test/chunking-form/samples/dynamic-import-inline-colouring/inlined.js new file mode 100644 index 00000000000..179d1f36e2d --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/inlined.js @@ -0,0 +1,2 @@ +export default 'inlined'; +export const x = 1; diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/main.js b/test/chunking-form/samples/dynamic-import-inline-colouring/main.js deleted file mode 100644 index c7ecc83be08..00000000000 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/main.js +++ /dev/null @@ -1,3 +0,0 @@ -import './foo.js'; - -export default import("./foo.js"); diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/main1.js b/test/chunking-form/samples/dynamic-import-inline-colouring/main1.js new file mode 100644 index 00000000000..0d4b2856ca3 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/main1.js @@ -0,0 +1,5 @@ +import './inlined.js'; +import './separate.js'; + +export const inlined = import('./inlined.js'); +export const separate = import('./separate.js'); diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/main2.js b/test/chunking-form/samples/dynamic-import-inline-colouring/main2.js new file mode 100644 index 00000000000..81d5531d23c --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/main2.js @@ -0,0 +1 @@ +export const separate = import('./separate.js'); diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/separate.js b/test/chunking-form/samples/dynamic-import-inline-colouring/separate.js new file mode 100644 index 00000000000..8b13495bb7a --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/separate.js @@ -0,0 +1,2 @@ +export default 'separate'; +export const x = 2; diff --git a/test/chunking-form/samples/preserve-modules-dynamic-imports/_config.js b/test/chunking-form/samples/preserve-modules-dynamic-imports/_config.js new file mode 100644 index 00000000000..808cce48441 --- /dev/null +++ b/test/chunking-form/samples/preserve-modules-dynamic-imports/_config.js @@ -0,0 +1,7 @@ +module.exports = { + description: 'dynamic imports are handled correctly when preserving modules', + options: { + input: ['main.js'], + experimentalPreserveModules: true + } +}; diff --git a/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/amd/dynamic-included.js b/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/amd/dynamic-included.js new file mode 100644 index 00000000000..cf69ecdb66b --- /dev/null +++ b/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/amd/dynamic-included.js @@ -0,0 +1,7 @@ +define(['exports'], function (exports) { 'use strict'; + + const value = 'included'; + + exports.value = value; + +}); diff --git a/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/amd/main.js b/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/amd/main.js new file mode 100644 index 00000000000..0d0f86d426d --- /dev/null +++ b/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/amd/main.js @@ -0,0 +1,5 @@ +define(['require'], function (require) { 'use strict'; + + new Promise(function (resolve, reject) { require(["./dynamic-included.js"], resolve, reject) }).then(result => console.log(result)); + +}); diff --git a/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/cjs/dynamic-included.js b/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/cjs/dynamic-included.js new file mode 100644 index 00000000000..7ce0b0473fe --- /dev/null +++ b/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/cjs/dynamic-included.js @@ -0,0 +1,5 @@ +'use strict'; + +const value = 'included'; + +exports.value = value; diff --git a/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/cjs/main.js b/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/cjs/main.js new file mode 100644 index 00000000000..3bd435b43da --- /dev/null +++ b/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/cjs/main.js @@ -0,0 +1,3 @@ +'use strict'; + +Promise.resolve(require("./dynamic-included.js")).then(result => console.log(result)); diff --git a/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/es/dynamic-included.js b/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/es/dynamic-included.js new file mode 100644 index 00000000000..6370bf94358 --- /dev/null +++ b/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/es/dynamic-included.js @@ -0,0 +1,3 @@ +const value = 'included'; + +export { value }; diff --git a/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/es/main.js b/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/es/main.js new file mode 100644 index 00000000000..1c47244d33e --- /dev/null +++ b/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/es/main.js @@ -0,0 +1 @@ +import("./dynamic-included.js").then(result => console.log(result)); diff --git a/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/system/dynamic-included.js b/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/system/dynamic-included.js new file mode 100644 index 00000000000..2d9619f0134 --- /dev/null +++ b/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/system/dynamic-included.js @@ -0,0 +1,10 @@ +System.register([], function (exports, module) { + 'use strict'; + return { + execute: function () { + + const value = exports('value', 'included'); + + } + }; +}); diff --git a/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/system/main.js b/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/system/main.js new file mode 100644 index 00000000000..35bff8cf139 --- /dev/null +++ b/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/system/main.js @@ -0,0 +1,10 @@ +System.register([], function (exports, module) { + 'use strict'; + return { + execute: function () { + + module.import("./dynamic-included.js").then(result => console.log(result)); + + } + }; +}); diff --git a/test/chunking-form/samples/preserve-modules-dynamic-imports/dynamic-included.js b/test/chunking-form/samples/preserve-modules-dynamic-imports/dynamic-included.js new file mode 100644 index 00000000000..287c398f8d6 --- /dev/null +++ b/test/chunking-form/samples/preserve-modules-dynamic-imports/dynamic-included.js @@ -0,0 +1 @@ +export const value = 'included'; diff --git a/test/chunking-form/samples/preserve-modules-dynamic-imports/dynamic-removed.js b/test/chunking-form/samples/preserve-modules-dynamic-imports/dynamic-removed.js new file mode 100644 index 00000000000..a0203faa48b --- /dev/null +++ b/test/chunking-form/samples/preserve-modules-dynamic-imports/dynamic-removed.js @@ -0,0 +1 @@ +export const value = 'removed'; diff --git a/test/chunking-form/samples/preserve-modules-dynamic-imports/main.js b/test/chunking-form/samples/preserve-modules-dynamic-imports/main.js new file mode 100644 index 00000000000..9449616c8fe --- /dev/null +++ b/test/chunking-form/samples/preserve-modules-dynamic-imports/main.js @@ -0,0 +1,6 @@ +import('./dynamic-included').then(result => console.log(result)); + +const include = false; +if (include) { + import('./dynamic-removed').then(result => console.log(result)); +} diff --git a/test/form/samples/dynamic-import-inlining/main.js b/test/form/samples/dynamic-import-inlining/main.js index 17d42f4d6f5..ee3e6a770d6 100644 --- a/test/form/samples/dynamic-import-inlining/main.js +++ b/test/form/samples/dynamic-import-inlining/main.js @@ -1,3 +1,2 @@ -import { foo } from './foo.js'; -export const bar = 2 -import('./foo.js') \ No newline at end of file +export const bar = 2; +import('./foo.js'); diff --git a/test/function/samples/inline-imports-with-manual/_config.js b/test/function/samples/inline-imports-with-manual/_config.js new file mode 100644 index 00000000000..c77cccc9faf --- /dev/null +++ b/test/function/samples/inline-imports-with-manual/_config.js @@ -0,0 +1,15 @@ +module.exports = { + description: 'Manual chunks are not supported when inlining dynamic imports', + options: { + input: ['main.js'], + experimentalCodeSplitting: true, + inlineDynamicImports: true, + manualChunks: { + lib: ['lib.js'] + } + }, + error: { + code: 'INVALID_OPTION', + message: '"manualChunks" option is not supported for inlineDynamicImports.' + } +}; diff --git a/test/function/samples/inline-imports-with-manual/lib.js b/test/function/samples/inline-imports-with-manual/lib.js new file mode 100644 index 00000000000..46d3ca8c61f --- /dev/null +++ b/test/function/samples/inline-imports-with-manual/lib.js @@ -0,0 +1 @@ +export const value = 42; diff --git a/test/function/samples/inline-imports-with-manual/main.js b/test/function/samples/inline-imports-with-manual/main.js new file mode 100644 index 00000000000..4869dc82f38 --- /dev/null +++ b/test/function/samples/inline-imports-with-manual/main.js @@ -0,0 +1 @@ +import('./lib').then(({value}) => assert.equal(value, 42)); diff --git a/test/function/samples/inline-imports-with-multiple/_config.js b/test/function/samples/inline-imports-with-multiple/_config.js new file mode 100644 index 00000000000..c114010bc87 --- /dev/null +++ b/test/function/samples/inline-imports-with-multiple/_config.js @@ -0,0 +1,12 @@ +module.exports = { + description: 'Having multiple inputs is not supported when inlining dynamic imports', + options: { + input: ['main.js'], + experimentalCodeSplitting: true, + inlineDynamicImports: true + }, + error: { + code: 'INVALID_OPTION', + message: 'Multiple inputs are not supported for inlineDynamicImports.' + } +}; diff --git a/test/function/samples/inline-imports-with-multiple/lib.js b/test/function/samples/inline-imports-with-multiple/lib.js new file mode 100644 index 00000000000..46d3ca8c61f --- /dev/null +++ b/test/function/samples/inline-imports-with-multiple/lib.js @@ -0,0 +1 @@ +export const value = 42; diff --git a/test/function/samples/inline-imports-with-multiple/main.js b/test/function/samples/inline-imports-with-multiple/main.js new file mode 100644 index 00000000000..4869dc82f38 --- /dev/null +++ b/test/function/samples/inline-imports-with-multiple/main.js @@ -0,0 +1 @@ +import('./lib').then(({value}) => assert.equal(value, 42)); diff --git a/test/function/samples/inline-imports-with-optimize/_config.js b/test/function/samples/inline-imports-with-optimize/_config.js new file mode 100644 index 00000000000..59f6f5b0f33 --- /dev/null +++ b/test/function/samples/inline-imports-with-optimize/_config.js @@ -0,0 +1,13 @@ +module.exports = { + description: 'Optimizing chunks is not supported when inlining dynamic imports', + options: { + input: ['main.js'], + experimentalCodeSplitting: true, + inlineDynamicImports: true, + optimizeChunks: true + }, + error: { + code: 'INVALID_OPTION', + message: '"optimizeChunks" option is not supported for inlineDynamicImports.' + } +}; diff --git a/test/function/samples/inline-imports-with-optimize/lib.js b/test/function/samples/inline-imports-with-optimize/lib.js new file mode 100644 index 00000000000..46d3ca8c61f --- /dev/null +++ b/test/function/samples/inline-imports-with-optimize/lib.js @@ -0,0 +1 @@ +export const value = 42; diff --git a/test/function/samples/inline-imports-with-optimize/main.js b/test/function/samples/inline-imports-with-optimize/main.js new file mode 100644 index 00000000000..4869dc82f38 --- /dev/null +++ b/test/function/samples/inline-imports-with-optimize/main.js @@ -0,0 +1 @@ +import('./lib').then(({value}) => assert.equal(value, 42)); diff --git a/test/function/samples/preserve-modules-with-inline/_config.js b/test/function/samples/preserve-modules-with-inline/_config.js new file mode 100644 index 00000000000..621aec7d0cf --- /dev/null +++ b/test/function/samples/preserve-modules-with-inline/_config.js @@ -0,0 +1,13 @@ +module.exports = { + description: 'Inlining dynamic imports is not supported when preserving modules', + options: { + input: ['main.js'], + experimentalCodeSplitting: true, + experimentalPreserveModules: true, + inlineDynamicImports: true + }, + error: { + code: 'INVALID_OPTION', + message: 'experimentalPreserveModules does not support the inlineDynamicImports option.' + } +}; diff --git a/test/function/samples/preserve-modules-with-inline/lib.js b/test/function/samples/preserve-modules-with-inline/lib.js new file mode 100644 index 00000000000..46d3ca8c61f --- /dev/null +++ b/test/function/samples/preserve-modules-with-inline/lib.js @@ -0,0 +1 @@ +export const value = 42; diff --git a/test/function/samples/preserve-modules-with-inline/main.js b/test/function/samples/preserve-modules-with-inline/main.js new file mode 100644 index 00000000000..4869dc82f38 --- /dev/null +++ b/test/function/samples/preserve-modules-with-inline/main.js @@ -0,0 +1 @@ +import('./lib').then(({value}) => assert.equal(value, 42)); diff --git a/test/function/samples/preserve-modules-with-manual/_config.js b/test/function/samples/preserve-modules-with-manual/_config.js new file mode 100644 index 00000000000..76cb53b8b9e --- /dev/null +++ b/test/function/samples/preserve-modules-with-manual/_config.js @@ -0,0 +1,15 @@ +module.exports = { + description: 'Assigning manual chunks fails when preserving modules', + options: { + input: ['main.js'], + experimentalCodeSplitting: true, + experimentalPreserveModules: true, + manualChunks: { + lib: ['lib.js'] + } + }, + error: { + code: 'INVALID_OPTION', + message: 'experimentalPreserveModules does not support the manualChunks option.' + } +}; diff --git a/test/function/samples/preserve-modules-with-manual/lib.js b/test/function/samples/preserve-modules-with-manual/lib.js new file mode 100644 index 00000000000..46d3ca8c61f --- /dev/null +++ b/test/function/samples/preserve-modules-with-manual/lib.js @@ -0,0 +1 @@ +export const value = 42; diff --git a/test/function/samples/preserve-modules-with-manual/main.js b/test/function/samples/preserve-modules-with-manual/main.js new file mode 100644 index 00000000000..0786352d0f9 --- /dev/null +++ b/test/function/samples/preserve-modules-with-manual/main.js @@ -0,0 +1,3 @@ +import { value } from './lib'; + +assert.equal(value, 42); diff --git a/test/function/samples/preserve-modules-with-optimize/_config.js b/test/function/samples/preserve-modules-with-optimize/_config.js new file mode 100644 index 00000000000..56bdbf8a956 --- /dev/null +++ b/test/function/samples/preserve-modules-with-optimize/_config.js @@ -0,0 +1,13 @@ +module.exports = { + description: 'Optimizing chunks fails when preserving modules', + options: { + input: ['main.js'], + experimentalCodeSplitting: true, + experimentalPreserveModules: true, + optimizeChunks: true + }, + error: { + code: 'INVALID_OPTION', + message: 'experimentalPreserveModules does not support the optimizeChunks option.' + } +}; diff --git a/test/function/samples/preserve-modules-with-optimize/lib.js b/test/function/samples/preserve-modules-with-optimize/lib.js new file mode 100644 index 00000000000..46d3ca8c61f --- /dev/null +++ b/test/function/samples/preserve-modules-with-optimize/lib.js @@ -0,0 +1 @@ +export const value = 42; diff --git a/test/function/samples/preserve-modules-with-optimize/main.js b/test/function/samples/preserve-modules-with-optimize/main.js new file mode 100644 index 00000000000..0786352d0f9 --- /dev/null +++ b/test/function/samples/preserve-modules-with-optimize/main.js @@ -0,0 +1,3 @@ +import { value } from './lib'; + +assert.equal(value, 42); diff --git a/test/misc/bundle-information.js b/test/misc/bundle-information.js index de1cea27215..c321efd7a51 100644 --- a/test/misc/bundle-information.js +++ b/test/misc/bundle-information.js @@ -229,4 +229,110 @@ describe('The bundle object', () => { ); }); }); + + it('adds correct flags to files when preserving modules', () => { + return rollup + .rollup({ + input: ['input', 'dynamic1'], + experimentalCodeSplitting: true, + experimentalPreserveModules: true, + plugins: [ + loader({ + input: + 'import {other} from "other";console.log(other);Promise.all([import("dynamic1"), import("dynamic2")]).then(([{dynamic1}, {dynamic2}]) => console.log(dynamic1, dynamic2));', + dynamic1: 'export const dynamic1 = "dynamic1"', + dynamic2: 'export const dynamic2 = "dynamic2"', + other: 'export const other = "other"' + }) + ] + }) + .then(bundle => + bundle.generate({ + format: 'esm', + dir: 'dist', + entryFileNames: '[name].js', + chunkFileNames: 'generated-[name].js' + }) + ) + .then(({ output }) => { + const sortedOutput = Object.keys(output) + .sort() + .map(key => output[key]); + assert.deepEqual( + sortedOutput.map(chunk => chunk.fileName), + ['_virtual/dynamic1', '_virtual/dynamic2', '_virtual/input', '_virtual/other'], + 'fileName' + ); + assert.deepEqual(sortedOutput.map(chunk => chunk.isEntry), [true, false, true, false], 'isEntry'); + assert.deepEqual( + sortedOutput.map(chunk => chunk.code), + [ + 'const dynamic1 = "dynamic1";\n\nexport { dynamic1 };\n', + 'const dynamic2 = "dynamic2";\n\nexport { dynamic2 };\n', + 'import { other } from \'./other\';\n\nconsole.log(other);Promise.all([import("./dynamic1"), import("./dynamic2")]).then(([{dynamic1}, {dynamic2}]) => console.log(dynamic1, dynamic2));\n', + 'const other = "other";\n\nexport { other };\n' + ], + 'code' + ); + assert.deepEqual( + sortedOutput.map(chunk => chunk.name), + ['dynamic1', 'chunk', 'input', 'chunk'], + 'name' + ); + assert.deepEqual( + sortedOutput.map(chunk => chunk.imports), + [[], [], ['_virtual/other'], []], + 'imports' + ); + assert.deepEqual(sortedOutput.map(chunk => chunk.exports), [['dynamic1'], ['dynamic2'], [], ['other']], 'exports'); + assert.deepEqual( + sortedOutput.map(chunk => chunk.modules), + [ + { + dynamic1: { + originalLength: 34, + removedExports: [], + renderedExports: ['dynamic1'], + renderedLength: 28 + } + }, + { + dynamic2: { + originalLength: 34, + removedExports: [], + renderedExports: ['dynamic2'], + renderedLength: 28 + } + }, + { + input: { + originalLength: 169, + removedExports: [], + renderedExports: [], + renderedLength: 141 + } + }, + { + other: { + originalLength: 28, + removedExports: [], + renderedExports: ['other'], + renderedLength: 22 + } + } + ], + 'modules' + ); + assert.deepEqual( + sortedOutput.map(chunk => chunk.isDynamicEntry), + [true, true, false, false], + 'isDynamicEntry' + ); + assert.deepEqual( + sortedOutput.map(chunk => chunk.entryModuleId), + ['dynamic1', 'dynamic2', 'input', null], + 'entryModuleId' + ); + }); + }); }); From 1d2557b3aaf0e87ff998c933c44fa9fc62ee716c Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Mon, 26 Nov 2018 06:37:07 +0100 Subject: [PATCH 10/23] Use dynamic import tree-shaking information to optimize chunks --- src/Graph.ts | 2 +- src/Module.ts | 11 ++++++++++ src/ast/nodes/Program.ts | 3 ++- src/utils/chunkColouring.ts | 2 +- src/utils/executionOrder.ts | 5 +++++ src/utils/traverseStaticDependencies.ts | 19 ++++++++++++++++ .../samples/dynamic-import-chained/_config.js | 9 ++++++++ .../_expected/amd/generated-chunk.js | 5 +++++ .../_expected/amd/generated-chunk2.js | 6 +++++ .../_expected/amd/main.js | 6 +++++ .../_expected/cjs/generated-chunk.js | 3 +++ .../_expected/cjs/generated-chunk2.js | 4 ++++ .../_expected/cjs/main.js | 4 ++++ .../_expected/es/generated-chunk.js | 1 + .../_expected/es/generated-chunk2.js | 2 ++ .../_expected/es/main.js | 2 ++ .../_expected/system/generated-chunk.js} | 2 +- .../_expected/system/generated-chunk2.js | 11 ++++++++++ .../_expected/system/main.js | 11 ++++++++++ .../samples/dynamic-import-chained/dep1.js | 2 ++ .../samples/dynamic-import-chained/dep2.js | 1 + .../samples/dynamic-import-chained/main.js | 5 +++++ .../dynamic-import-tree-shaking-1/_config.js | 12 ++++++++++ .../_expected/amd/entryA.js | 9 ++++++++ .../_expected/amd/entryB.js | 5 +++++ .../_expected/cjs/entryA.js | 7 ++++++ .../_expected/cjs/entryB.js | 3 +++ .../_expected/es/entryA.js | 5 +++++ .../_expected/es/entryB.js | 1 + .../_expected/system/entryA.js | 14 ++++++++++++ .../_expected/system/entryB.js | 10 +++++++++ .../dynamic-import-tree-shaking-1/dep.js | 3 +++ .../dynamic-import-tree-shaking-1/dep2.js | 3 +++ .../dynamic-import-tree-shaking-1/main1.js | 3 +++ .../dynamic-import-tree-shaking-1/main2.js | 5 +++++ .../dynamic-import-treeshaking/_config.js | 6 ----- .../_expected/amd/chunk-7b720877.js | 7 ------ .../_expected/amd/main.js | 13 ----------- .../_expected/cjs/chunk-3a53aa58.js | 5 ----- .../_expected/cjs/main.js | 13 ----------- .../_expected/es/chunk-713732d9.js | 3 --- .../_expected/es/main.js | 11 ---------- .../_expected/system/main.js | 22 ------------------- .../dynamic-import-treeshaking/dep1.js | 12 ---------- .../dynamic-import-treeshaking/dep2.js | 5 ----- .../dynamic-import-treeshaking/dep3.js | 5 ----- .../dynamic-import-treeshaking/dep4.js | 1 - .../dynamic-import-treeshaking/main.js | 3 --- .../samples/manual-chunks-dynamic/_config.js | 4 +--- .../dynamic-import-inlining/_expected.js | 6 ++--- 50 files changed, 196 insertions(+), 116 deletions(-) create mode 100644 src/utils/traverseStaticDependencies.ts create mode 100644 test/chunking-form/samples/dynamic-import-chained/_config.js create mode 100644 test/chunking-form/samples/dynamic-import-chained/_expected/amd/generated-chunk.js create mode 100644 test/chunking-form/samples/dynamic-import-chained/_expected/amd/generated-chunk2.js create mode 100644 test/chunking-form/samples/dynamic-import-chained/_expected/amd/main.js create mode 100644 test/chunking-form/samples/dynamic-import-chained/_expected/cjs/generated-chunk.js create mode 100644 test/chunking-form/samples/dynamic-import-chained/_expected/cjs/generated-chunk2.js create mode 100644 test/chunking-form/samples/dynamic-import-chained/_expected/cjs/main.js create mode 100644 test/chunking-form/samples/dynamic-import-chained/_expected/es/generated-chunk.js create mode 100644 test/chunking-form/samples/dynamic-import-chained/_expected/es/generated-chunk2.js create mode 100644 test/chunking-form/samples/dynamic-import-chained/_expected/es/main.js rename test/chunking-form/samples/{dynamic-import-treeshaking/_expected/system/chunk-4d8f4e43.js => dynamic-import-chained/_expected/system/generated-chunk.js} (75%) create mode 100644 test/chunking-form/samples/dynamic-import-chained/_expected/system/generated-chunk2.js create mode 100644 test/chunking-form/samples/dynamic-import-chained/_expected/system/main.js create mode 100644 test/chunking-form/samples/dynamic-import-chained/dep1.js create mode 100644 test/chunking-form/samples/dynamic-import-chained/dep2.js create mode 100644 test/chunking-form/samples/dynamic-import-chained/main.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-1/_config.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/amd/entryA.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/amd/entryB.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/cjs/entryA.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/cjs/entryB.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/es/entryA.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/es/entryB.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/system/entryA.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/system/entryB.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-1/dep.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-1/dep2.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-1/main1.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-1/main2.js delete mode 100644 test/chunking-form/samples/dynamic-import-treeshaking/_config.js delete mode 100644 test/chunking-form/samples/dynamic-import-treeshaking/_expected/amd/chunk-7b720877.js delete mode 100644 test/chunking-form/samples/dynamic-import-treeshaking/_expected/amd/main.js delete mode 100644 test/chunking-form/samples/dynamic-import-treeshaking/_expected/cjs/chunk-3a53aa58.js delete mode 100644 test/chunking-form/samples/dynamic-import-treeshaking/_expected/cjs/main.js delete mode 100644 test/chunking-form/samples/dynamic-import-treeshaking/_expected/es/chunk-713732d9.js delete mode 100644 test/chunking-form/samples/dynamic-import-treeshaking/_expected/es/main.js delete mode 100644 test/chunking-form/samples/dynamic-import-treeshaking/_expected/system/main.js delete mode 100644 test/chunking-form/samples/dynamic-import-treeshaking/dep1.js delete mode 100644 test/chunking-form/samples/dynamic-import-treeshaking/dep2.js delete mode 100644 test/chunking-form/samples/dynamic-import-treeshaking/dep3.js delete mode 100644 test/chunking-form/samples/dynamic-import-treeshaking/dep4.js delete mode 100644 test/chunking-form/samples/dynamic-import-treeshaking/main.js diff --git a/src/Graph.ts b/src/Graph.ts index d9cd311ae2f..3e584c051fb 100644 --- a/src/Graph.ts +++ b/src/Graph.ts @@ -268,7 +268,7 @@ export default class Graph { timeStart(`treeshaking pass ${treeshakingPass}`, 3); this.needsTreeshakingPass = false; for (const module of modules) { - module.include(); + if (module.isExecuted) module.include(); } timeEnd(`treeshaking pass ${treeshakingPass++}`, 3); } while (this.needsTreeshakingPass); diff --git a/src/Module.ts b/src/Module.ts index 48da0241e77..cdf6b540e07 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -37,6 +37,7 @@ import relativeId from './utils/relativeId'; import { RenderOptions } from './utils/renderHelpers'; import { SOURCEMAPPING_URL_RE } from './utils/sourceMappingURL'; import { timeEnd, timeStart } from './utils/timers'; +import { visitStaticDependencies } from './utils/traverseStaticDependencies'; export interface CommentDescription { block: boolean; @@ -158,6 +159,7 @@ export default class Module { exportAllSources: string[]; id: string; imports: { [name: string]: ImportDescription }; + isExecuted: boolean = false; isExternal: false; originalCode: string; originalSourcemap: RawSourceMap | void; @@ -449,6 +451,15 @@ export default class Module { } includeAllExports() { + if (!this.isExecuted) { + this.graph.needsTreeshakingPass = true; + visitStaticDependencies(this, module => { + if (module instanceof ExternalModule || module.isExecuted) return true; + module.isExecuted = true; + return false; + }); + } + for (const exportName of this.getExports()) { const variable = this.traceExport(exportName); diff --git a/src/ast/nodes/Program.ts b/src/ast/nodes/Program.ts index 06952c8912b..102d4c02f1e 100644 --- a/src/ast/nodes/Program.ts +++ b/src/ast/nodes/Program.ts @@ -18,8 +18,9 @@ export default class Program extends NodeBase { include(includeAllChildrenRecursively: boolean) { this.included = true; for (const node of this.body) { - if (includeAllChildrenRecursively || node.shouldBeIncluded()) + if (includeAllChildrenRecursively || node.shouldBeIncluded()) { node.include(includeAllChildrenRecursively); + } } } diff --git a/src/utils/chunkColouring.ts b/src/utils/chunkColouring.ts index 07c2f526d70..9694ede5837 100644 --- a/src/utils/chunkColouring.ts +++ b/src/utils/chunkColouring.ts @@ -31,7 +31,7 @@ export function assignChunkColouringHashes( } for (const dynamicModule of module.dynamicImportResolutions) { - if (dynamicModule.resolution instanceof Module) { + if (dynamicModule.resolution instanceof Module && dynamicModule.resolution.isExecuted) { if ( dynamicModule.resolution.chunkAlias || Uint8ArrayEqual(dynamicModule.resolution.entryPointsHash, currentEntry.entryPointsHash) diff --git a/src/utils/executionOrder.ts b/src/utils/executionOrder.ts index 6eff1e95213..61bfa8795a2 100644 --- a/src/utils/executionOrder.ts +++ b/src/utils/executionOrder.ts @@ -15,6 +15,7 @@ export function sortByExecutionOrder(units: OrderedExecutionUnit[]) { export function analyseModuleExecution(entryModules: Module[]) { let nextExecIndex = 0; + let inStaticGraph = true; const cyclePaths: string[][] = []; const analysedModules: { [id: string]: boolean } = {}; const orderedModules: Module[] = []; @@ -30,6 +31,9 @@ export function analyseModuleExecution(entryModules: Module[]) { return; } + if (inStaticGraph) { + module.isExecuted = true; + } for (const dependency of module.dependencies) { if (dependency.id in parents) { if (!analysedModules[dependency.id]) { @@ -63,6 +67,7 @@ export function analyseModuleExecution(entryModules: Module[]) { analyseModule(curEntry); } + inStaticGraph = false; for (const curEntry of dynamicImports) { curEntry.isDynamicEntryPoint = true; if (!parents[curEntry.id]) { diff --git a/src/utils/traverseStaticDependencies.ts b/src/utils/traverseStaticDependencies.ts new file mode 100644 index 00000000000..c56fba4ad81 --- /dev/null +++ b/src/utils/traverseStaticDependencies.ts @@ -0,0 +1,19 @@ +import ExternalModule from '../ExternalModule'; +import Module from '../Module'; + +export function visitStaticDependencies( + entryModule: Module | ExternalModule, + areDependenciesSkipped: (module: Module | ExternalModule) => boolean +) { + const modules = [entryModule]; + const visitedModules: { [id: string]: true } = {}; + for (const module of modules) { + if (areDependenciesSkipped(module) || module instanceof ExternalModule) continue; + for (const dependency of module.dependencies) { + if (!visitedModules[dependency.id]) { + visitedModules[dependency.id] = true; + modules.push(dependency); + } + } + } +} diff --git a/test/chunking-form/samples/dynamic-import-chained/_config.js b/test/chunking-form/samples/dynamic-import-chained/_config.js new file mode 100644 index 00000000000..b510f0c0616 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-chained/_config.js @@ -0,0 +1,9 @@ +module.exports = { + description: 'includes chained dynamic imports', + options: { + input: 'main.js', + output: { + chunkFileNames: 'generated-chunk.js' + } + } +}; diff --git a/test/chunking-form/samples/dynamic-import-chained/_expected/amd/generated-chunk.js b/test/chunking-form/samples/dynamic-import-chained/_expected/amd/generated-chunk.js new file mode 100644 index 00000000000..af27f254599 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-chained/_expected/amd/generated-chunk.js @@ -0,0 +1,5 @@ +define(function () { 'use strict'; + + console.log('dep2'); + +}); diff --git a/test/chunking-form/samples/dynamic-import-chained/_expected/amd/generated-chunk2.js b/test/chunking-form/samples/dynamic-import-chained/_expected/amd/generated-chunk2.js new file mode 100644 index 00000000000..49f374817d1 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-chained/_expected/amd/generated-chunk2.js @@ -0,0 +1,6 @@ +define(['require'], function (require) { 'use strict'; + + console.log('dep1'); + new Promise(function (resolve, reject) { require(["./generated-chunk.js"], resolve, reject) }); + +}); diff --git a/test/chunking-form/samples/dynamic-import-chained/_expected/amd/main.js b/test/chunking-form/samples/dynamic-import-chained/_expected/amd/main.js new file mode 100644 index 00000000000..6c24d50ea37 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-chained/_expected/amd/main.js @@ -0,0 +1,6 @@ +define(['require'], function (require) { 'use strict'; + + console.log('main'); + new Promise(function (resolve, reject) { require(["./generated-chunk2.js"], resolve, reject) }); + +}); diff --git a/test/chunking-form/samples/dynamic-import-chained/_expected/cjs/generated-chunk.js b/test/chunking-form/samples/dynamic-import-chained/_expected/cjs/generated-chunk.js new file mode 100644 index 00000000000..132fb447b0c --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-chained/_expected/cjs/generated-chunk.js @@ -0,0 +1,3 @@ +'use strict'; + +console.log('dep2'); diff --git a/test/chunking-form/samples/dynamic-import-chained/_expected/cjs/generated-chunk2.js b/test/chunking-form/samples/dynamic-import-chained/_expected/cjs/generated-chunk2.js new file mode 100644 index 00000000000..e4194322104 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-chained/_expected/cjs/generated-chunk2.js @@ -0,0 +1,4 @@ +'use strict'; + +console.log('dep1'); +Promise.resolve(require("./generated-chunk.js")); diff --git a/test/chunking-form/samples/dynamic-import-chained/_expected/cjs/main.js b/test/chunking-form/samples/dynamic-import-chained/_expected/cjs/main.js new file mode 100644 index 00000000000..3525048b260 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-chained/_expected/cjs/main.js @@ -0,0 +1,4 @@ +'use strict'; + +console.log('main'); +Promise.resolve(require("./generated-chunk2.js")); diff --git a/test/chunking-form/samples/dynamic-import-chained/_expected/es/generated-chunk.js b/test/chunking-form/samples/dynamic-import-chained/_expected/es/generated-chunk.js new file mode 100644 index 00000000000..f5325d80e8a --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-chained/_expected/es/generated-chunk.js @@ -0,0 +1 @@ +console.log('dep2'); diff --git a/test/chunking-form/samples/dynamic-import-chained/_expected/es/generated-chunk2.js b/test/chunking-form/samples/dynamic-import-chained/_expected/es/generated-chunk2.js new file mode 100644 index 00000000000..a6dcf6e8496 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-chained/_expected/es/generated-chunk2.js @@ -0,0 +1,2 @@ +console.log('dep1'); +import("./generated-chunk.js"); diff --git a/test/chunking-form/samples/dynamic-import-chained/_expected/es/main.js b/test/chunking-form/samples/dynamic-import-chained/_expected/es/main.js new file mode 100644 index 00000000000..575719c8eb4 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-chained/_expected/es/main.js @@ -0,0 +1,2 @@ +console.log('main'); +import("./generated-chunk2.js"); diff --git a/test/chunking-form/samples/dynamic-import-treeshaking/_expected/system/chunk-4d8f4e43.js b/test/chunking-form/samples/dynamic-import-chained/_expected/system/generated-chunk.js similarity index 75% rename from test/chunking-form/samples/dynamic-import-treeshaking/_expected/system/chunk-4d8f4e43.js rename to test/chunking-form/samples/dynamic-import-chained/_expected/system/generated-chunk.js index 134a5203f20..135361ec64d 100644 --- a/test/chunking-form/samples/dynamic-import-treeshaking/_expected/system/chunk-4d8f4e43.js +++ b/test/chunking-form/samples/dynamic-import-chained/_expected/system/generated-chunk.js @@ -3,7 +3,7 @@ System.register([], function (exports, module) { return { execute: function () { - var multiplier = exports('a', 7); + console.log('dep2'); } }; diff --git a/test/chunking-form/samples/dynamic-import-chained/_expected/system/generated-chunk2.js b/test/chunking-form/samples/dynamic-import-chained/_expected/system/generated-chunk2.js new file mode 100644 index 00000000000..91207f17141 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-chained/_expected/system/generated-chunk2.js @@ -0,0 +1,11 @@ +System.register([], function (exports, module) { + 'use strict'; + return { + execute: function () { + + console.log('dep1'); + module.import("./generated-chunk.js"); + + } + }; +}); diff --git a/test/chunking-form/samples/dynamic-import-chained/_expected/system/main.js b/test/chunking-form/samples/dynamic-import-chained/_expected/system/main.js new file mode 100644 index 00000000000..a64e73af4f3 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-chained/_expected/system/main.js @@ -0,0 +1,11 @@ +System.register([], function (exports, module) { + 'use strict'; + return { + execute: function () { + + console.log('main'); + module.import("./generated-chunk2.js"); + + } + }; +}); diff --git a/test/chunking-form/samples/dynamic-import-chained/dep1.js b/test/chunking-form/samples/dynamic-import-chained/dep1.js new file mode 100644 index 00000000000..78b71aab977 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-chained/dep1.js @@ -0,0 +1,2 @@ +console.log('dep1'); +import('./dep2.js'); diff --git a/test/chunking-form/samples/dynamic-import-chained/dep2.js b/test/chunking-form/samples/dynamic-import-chained/dep2.js new file mode 100644 index 00000000000..f5325d80e8a --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-chained/dep2.js @@ -0,0 +1 @@ +console.log('dep2'); diff --git a/test/chunking-form/samples/dynamic-import-chained/main.js b/test/chunking-form/samples/dynamic-import-chained/main.js new file mode 100644 index 00000000000..6626641d177 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-chained/main.js @@ -0,0 +1,5 @@ +console.log('main'); + +// to mess up the internal execution order +if (false) import('./dep2.js') +import('./dep1.js'); diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-1/_config.js b/test/chunking-form/samples/dynamic-import-tree-shaking-1/_config.js new file mode 100644 index 00000000000..467c722b112 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-1/_config.js @@ -0,0 +1,12 @@ +module.exports = { + description: 'uses tree-shaking information to improve chunking', + options: { + input: { + entryA: 'main1.js', + entryB: 'main2.js' + }, + output: { + chunkFileNames: 'generated-chunk.js' + } + } +}; diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/amd/entryA.js b/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/amd/entryA.js new file mode 100644 index 00000000000..0f3a098cf76 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/amd/entryA.js @@ -0,0 +1,9 @@ +define(function () { 'use strict'; + + console.log('dep'); + + var value = 1; + + console.log('main1', value); + +}); diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/amd/entryB.js b/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/amd/entryB.js new file mode 100644 index 00000000000..ece2de9a3ae --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/amd/entryB.js @@ -0,0 +1,5 @@ +define(['require'], function (require) { 'use strict'; + + console.log('main2'); + +}); diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/cjs/entryA.js b/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/cjs/entryA.js new file mode 100644 index 00000000000..cb112f038c4 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/cjs/entryA.js @@ -0,0 +1,7 @@ +'use strict'; + +console.log('dep'); + +var value = 1; + +console.log('main1', value); diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/cjs/entryB.js b/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/cjs/entryB.js new file mode 100644 index 00000000000..33fe6f320c2 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/cjs/entryB.js @@ -0,0 +1,3 @@ +'use strict'; + +console.log('main2'); diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/es/entryA.js b/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/es/entryA.js new file mode 100644 index 00000000000..a4fe2a7630b --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/es/entryA.js @@ -0,0 +1,5 @@ +console.log('dep'); + +var value = 1; + +console.log('main1', value); diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/es/entryB.js b/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/es/entryB.js new file mode 100644 index 00000000000..ac653633351 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/es/entryB.js @@ -0,0 +1 @@ +console.log('main2'); diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/system/entryA.js b/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/system/entryA.js new file mode 100644 index 00000000000..08e561ffa22 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/system/entryA.js @@ -0,0 +1,14 @@ +System.register([], function (exports, module) { + 'use strict'; + return { + execute: function () { + + console.log('dep'); + + var value = 1; + + console.log('main1', value); + + } + }; +}); diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/system/entryB.js b/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/system/entryB.js new file mode 100644 index 00000000000..80e8224ee07 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/system/entryB.js @@ -0,0 +1,10 @@ +System.register([], function (exports, module) { + 'use strict'; + return { + execute: function () { + + console.log('main2'); + + } + }; +}); diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-1/dep.js b/test/chunking-form/samples/dynamic-import-tree-shaking-1/dep.js new file mode 100644 index 00000000000..6687babb629 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-1/dep.js @@ -0,0 +1,3 @@ +console.log('dep'); + +export var value = 1; diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-1/dep2.js b/test/chunking-form/samples/dynamic-import-tree-shaking-1/dep2.js new file mode 100644 index 00000000000..8a3785fdfce --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-1/dep2.js @@ -0,0 +1,3 @@ +console.log('dep2'); + +export { value } from './dep'; diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-1/main1.js b/test/chunking-form/samples/dynamic-import-tree-shaking-1/main1.js new file mode 100644 index 00000000000..dae9519a864 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-1/main1.js @@ -0,0 +1,3 @@ +import { value } from './dep'; + +console.log('main1', value); diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-1/main2.js b/test/chunking-form/samples/dynamic-import-tree-shaking-1/main2.js new file mode 100644 index 00000000000..b4d6090cce9 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-1/main2.js @@ -0,0 +1,5 @@ +if (false) { + import('./dep2').then(({ value }) => console.log('main2', value)); +} + +console.log('main2'); diff --git a/test/chunking-form/samples/dynamic-import-treeshaking/_config.js b/test/chunking-form/samples/dynamic-import-treeshaking/_config.js deleted file mode 100644 index f74eb51af17..00000000000 --- a/test/chunking-form/samples/dynamic-import-treeshaking/_config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - description: 'Treeshaking with dynamic import', - options: { - input: ['main.js'] - } -}; diff --git a/test/chunking-form/samples/dynamic-import-treeshaking/_expected/amd/chunk-7b720877.js b/test/chunking-form/samples/dynamic-import-treeshaking/_expected/amd/chunk-7b720877.js deleted file mode 100644 index 972a328006d..00000000000 --- a/test/chunking-form/samples/dynamic-import-treeshaking/_expected/amd/chunk-7b720877.js +++ /dev/null @@ -1,7 +0,0 @@ -define(['exports'], function (exports) { 'use strict'; - - var multiplier = 7; - - exports.multiplier = multiplier; - -}); diff --git a/test/chunking-form/samples/dynamic-import-treeshaking/_expected/amd/main.js b/test/chunking-form/samples/dynamic-import-treeshaking/_expected/amd/main.js deleted file mode 100644 index b492836791b..00000000000 --- a/test/chunking-form/samples/dynamic-import-treeshaking/_expected/amd/main.js +++ /dev/null @@ -1,13 +0,0 @@ -define(['require', './chunk-7b720877.js'], function (require, __chunk_1) { 'use strict'; - - function calc (num) { - return num * __chunk_1.multiplier; - } - - function fn (num) { - return num * calc(num); - } - - console.log(fn(5)); - -}); diff --git a/test/chunking-form/samples/dynamic-import-treeshaking/_expected/cjs/chunk-3a53aa58.js b/test/chunking-form/samples/dynamic-import-treeshaking/_expected/cjs/chunk-3a53aa58.js deleted file mode 100644 index 6c19ba5bed9..00000000000 --- a/test/chunking-form/samples/dynamic-import-treeshaking/_expected/cjs/chunk-3a53aa58.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -var multiplier = 7; - -exports.multiplier = multiplier; diff --git a/test/chunking-form/samples/dynamic-import-treeshaking/_expected/cjs/main.js b/test/chunking-form/samples/dynamic-import-treeshaking/_expected/cjs/main.js deleted file mode 100644 index c005f8502dd..00000000000 --- a/test/chunking-form/samples/dynamic-import-treeshaking/_expected/cjs/main.js +++ /dev/null @@ -1,13 +0,0 @@ -'use strict'; - -var __chunk_1 = require('./chunk-3a53aa58.js'); - -function calc (num) { - return num * __chunk_1.multiplier; -} - -function fn (num) { - return num * calc(num); -} - -console.log(fn(5)); diff --git a/test/chunking-form/samples/dynamic-import-treeshaking/_expected/es/chunk-713732d9.js b/test/chunking-form/samples/dynamic-import-treeshaking/_expected/es/chunk-713732d9.js deleted file mode 100644 index f112a633446..00000000000 --- a/test/chunking-form/samples/dynamic-import-treeshaking/_expected/es/chunk-713732d9.js +++ /dev/null @@ -1,3 +0,0 @@ -var multiplier = 7; - -export { multiplier as a }; diff --git a/test/chunking-form/samples/dynamic-import-treeshaking/_expected/es/main.js b/test/chunking-form/samples/dynamic-import-treeshaking/_expected/es/main.js deleted file mode 100644 index c25970cb9bf..00000000000 --- a/test/chunking-form/samples/dynamic-import-treeshaking/_expected/es/main.js +++ /dev/null @@ -1,11 +0,0 @@ -import { a as multiplier } from './chunk-713732d9.js'; - -function calc (num) { - return num * multiplier; -} - -function fn (num) { - return num * calc(num); -} - -console.log(fn(5)); diff --git a/test/chunking-form/samples/dynamic-import-treeshaking/_expected/system/main.js b/test/chunking-form/samples/dynamic-import-treeshaking/_expected/system/main.js deleted file mode 100644 index 2d6a3c22efb..00000000000 --- a/test/chunking-form/samples/dynamic-import-treeshaking/_expected/system/main.js +++ /dev/null @@ -1,22 +0,0 @@ -System.register(['./chunk-4d8f4e43.js'], function (exports, module) { - 'use strict'; - var multiplier; - return { - setters: [function (module) { - multiplier = module.a; - }], - execute: function () { - - function calc (num) { - return num * multiplier; - } - - function fn (num) { - return num * calc(num); - } - - console.log(fn(5)); - - } - }; -}); diff --git a/test/chunking-form/samples/dynamic-import-treeshaking/dep1.js b/test/chunking-form/samples/dynamic-import-treeshaking/dep1.js deleted file mode 100644 index 8c2268595b7..00000000000 --- a/test/chunking-form/samples/dynamic-import-treeshaking/dep1.js +++ /dev/null @@ -1,12 +0,0 @@ -import { calc } from './dep3.js'; - -export function fn (num) { - return num * calc(num); -} - -export function dynamic (num) { - return import('./dep2.js') - .then(dep2 => { - return dep2.mult(num); - }); -} \ No newline at end of file diff --git a/test/chunking-form/samples/dynamic-import-treeshaking/dep2.js b/test/chunking-form/samples/dynamic-import-treeshaking/dep2.js deleted file mode 100644 index b9eaabe5d6d..00000000000 --- a/test/chunking-form/samples/dynamic-import-treeshaking/dep2.js +++ /dev/null @@ -1,5 +0,0 @@ -import { multiplier } from './dep4.js'; - -export function mult (num) { - return num + multiplier; -} \ No newline at end of file diff --git a/test/chunking-form/samples/dynamic-import-treeshaking/dep3.js b/test/chunking-form/samples/dynamic-import-treeshaking/dep3.js deleted file mode 100644 index 2e319b70744..00000000000 --- a/test/chunking-form/samples/dynamic-import-treeshaking/dep3.js +++ /dev/null @@ -1,5 +0,0 @@ -import { multiplier } from './dep4.js'; - -export function calc (num) { - return num * multiplier; -} \ No newline at end of file diff --git a/test/chunking-form/samples/dynamic-import-treeshaking/dep4.js b/test/chunking-form/samples/dynamic-import-treeshaking/dep4.js deleted file mode 100644 index 7468ccc2b3f..00000000000 --- a/test/chunking-form/samples/dynamic-import-treeshaking/dep4.js +++ /dev/null @@ -1 +0,0 @@ -export var multiplier = 7; \ No newline at end of file diff --git a/test/chunking-form/samples/dynamic-import-treeshaking/main.js b/test/chunking-form/samples/dynamic-import-treeshaking/main.js deleted file mode 100644 index baaa2998adf..00000000000 --- a/test/chunking-form/samples/dynamic-import-treeshaking/main.js +++ /dev/null @@ -1,3 +0,0 @@ -import { fn } from './dep1.js'; - -console.log(fn(5)); \ No newline at end of file diff --git a/test/chunking-form/samples/manual-chunks-dynamic/_config.js b/test/chunking-form/samples/manual-chunks-dynamic/_config.js index 943877edc50..14709021bd9 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic/_config.js +++ b/test/chunking-form/samples/manual-chunks-dynamic/_config.js @@ -1,7 +1,5 @@ module.exports = { - description: 'manual chunks to an empty dynamic chunk', - - // manual chunks which are also dynamic entry points do not work yet + description: 'supports dynamic manual chunks', skip: true, options: { input: ['main.js'], diff --git a/test/form/samples/dynamic-import-inlining/_expected.js b/test/form/samples/dynamic-import-inlining/_expected.js index 06bbf4869d3..03ab247516e 100644 --- a/test/form/samples/dynamic-import-inlining/_expected.js +++ b/test/form/samples/dynamic-import-inlining/_expected.js @@ -1,10 +1,10 @@ +const bar = 2; +Promise.resolve().then(function () { return foo$1; }); + const foo = 1; var foo$1 = /*#__PURE__*/Object.freeze({ foo: foo }); -const bar = 2; -Promise.resolve().then(function () { return foo$1; }); - export { bar }; From 55118bc74e67a5d3b31e4d8243a854599228e234 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Tue, 27 Nov 2018 08:12:04 +0100 Subject: [PATCH 11/23] Create proper facades for dynamic imports if necessary that are actually used in place of the facaded module. Also no longer inline dynamic imports that are part of the static graph for now as this logic would fail if those are then dynamically imported by another chunk. --- src/Chunk.ts | 34 ++++++++++--------- src/Graph.ts | 25 ++++++++++++-- src/Module.ts | 1 + src/rollup/index.ts | 4 +-- src/utils/chunkColouring.ts | 15 ++++---- src/utils/executionOrder.ts | 7 ++-- .../samples/dynamic-import-facade/_config.js | 7 ++++ .../_expected/amd/chunk-822f1303.js | 7 ++++ .../_expected/amd/chunk-d42319c1.js | 13 +++++++ .../_expected/amd/main1.js | 5 +++ .../_expected/amd/main2.js | 5 +++ .../_expected/cjs/chunk-0ad7c258.js | 7 ++++ .../_expected/cjs/chunk-57ff6d6d.js | 11 ++++++ .../_expected/cjs/main1.js | 3 ++ .../_expected/cjs/main2.js | 5 +++ .../_expected/es/chunk-9fd0b968.js | 1 + .../_expected/es/chunk-fa3f0c72.js | 8 +++++ .../_expected/es/main1.js | 1 + .../_expected/es/main2.js | 3 ++ .../_expected/system/chunk-55e635b3.js | 15 ++++++++ .../_expected/system/chunk-d225f367.js | 13 +++++++ .../_expected/system/main1.js | 10 ++++++ .../_expected/system/main2.js | 15 ++++++++ .../samples/dynamic-import-facade/dep.js | 3 ++ .../samples/dynamic-import-facade/dynamic.js | 4 +++ .../samples/dynamic-import-facade/main1.js | 1 + .../samples/dynamic-import-facade/main2.js | 4 +++ .../_config.js | 2 +- .../_expected/amd/chunk-d309b27d.js | 9 +++++ .../_expected/amd/main1.js | 14 ++------ .../_expected/cjs/chunk-e4f8b8db.js | 7 ++++ .../_expected/cjs/main1.js | 13 ++----- .../_expected/es/chunk-6d572aec.js | 5 +++ .../_expected/es/main1.js | 13 ++----- .../_expected/system/chunk-cdaf79ed.js | 11 ++++++ .../_expected/system/main1.js | 14 ++------ .../dynamic-import-tree-shaking-2/_config.js | 6 ++++ .../_expected/amd/main1.js | 5 +++ .../_expected/amd/main2.js | 10 ++++++ .../_expected/cjs/main1.js | 3 ++ .../_expected/cjs/main2.js | 8 +++++ .../_expected/es/main1.js | 1 + .../_expected/es/main2.js | 6 ++++ .../_expected/system/main1.js | 10 ++++++ .../_expected/system/main2.js | 15 ++++++++ .../dynamic-import-tree-shaking-2/dep.js | 2 ++ .../dynamic-import-tree-shaking-2/dynamic.js | 4 +++ .../dynamic-import-tree-shaking-2/main1.js | 4 +++ .../dynamic-import-tree-shaking-2/main2.js | 4 +++ 49 files changed, 318 insertions(+), 75 deletions(-) create mode 100644 test/chunking-form/samples/dynamic-import-facade/_config.js create mode 100644 test/chunking-form/samples/dynamic-import-facade/_expected/amd/chunk-822f1303.js create mode 100644 test/chunking-form/samples/dynamic-import-facade/_expected/amd/chunk-d42319c1.js create mode 100644 test/chunking-form/samples/dynamic-import-facade/_expected/amd/main1.js create mode 100644 test/chunking-form/samples/dynamic-import-facade/_expected/amd/main2.js create mode 100644 test/chunking-form/samples/dynamic-import-facade/_expected/cjs/chunk-0ad7c258.js create mode 100644 test/chunking-form/samples/dynamic-import-facade/_expected/cjs/chunk-57ff6d6d.js create mode 100644 test/chunking-form/samples/dynamic-import-facade/_expected/cjs/main1.js create mode 100644 test/chunking-form/samples/dynamic-import-facade/_expected/cjs/main2.js create mode 100644 test/chunking-form/samples/dynamic-import-facade/_expected/es/chunk-9fd0b968.js create mode 100644 test/chunking-form/samples/dynamic-import-facade/_expected/es/chunk-fa3f0c72.js create mode 100644 test/chunking-form/samples/dynamic-import-facade/_expected/es/main1.js create mode 100644 test/chunking-form/samples/dynamic-import-facade/_expected/es/main2.js create mode 100644 test/chunking-form/samples/dynamic-import-facade/_expected/system/chunk-55e635b3.js create mode 100644 test/chunking-form/samples/dynamic-import-facade/_expected/system/chunk-d225f367.js create mode 100644 test/chunking-form/samples/dynamic-import-facade/_expected/system/main1.js create mode 100644 test/chunking-form/samples/dynamic-import-facade/_expected/system/main2.js create mode 100644 test/chunking-form/samples/dynamic-import-facade/dep.js create mode 100644 test/chunking-form/samples/dynamic-import-facade/dynamic.js create mode 100644 test/chunking-form/samples/dynamic-import-facade/main1.js create mode 100644 test/chunking-form/samples/dynamic-import-facade/main2.js create mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/chunk-d309b27d.js create mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/chunk-e4f8b8db.js create mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/chunk-6d572aec.js create mode 100644 test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/chunk-cdaf79ed.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-2/_config.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/amd/main1.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/amd/main2.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/cjs/main1.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/cjs/main2.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/es/main1.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/es/main2.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/system/main1.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/system/main2.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-2/dep.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-2/dynamic.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-2/main1.js create mode 100644 test/chunking-form/samples/dynamic-import-tree-shaking-2/main2.js diff --git a/src/Chunk.ts b/src/Chunk.ts index 6a400d270b3..877b91566fb 100644 --- a/src/Chunk.ts +++ b/src/Chunk.ts @@ -131,7 +131,8 @@ export default class Chunk { // an input entry point module entryModule: Module = undefined; isEntryModuleFacade: boolean = false; - isDynamicEntryPoint: boolean = false; + isDynamicEntryFacade: boolean = false; + facadeChunk: Chunk | null = null; isEmpty: boolean; isManualChunk: boolean = false; @@ -165,7 +166,7 @@ export default class Chunk { this.isEntryModuleFacade = true; } if (module.isDynamicEntryPoint && !inlineDynamicImports) { - this.isDynamicEntryPoint = true; + this.isDynamicEntryFacade = true; if (!this.entryModule) { this.entryModule = module; } @@ -201,15 +202,13 @@ export default class Chunk { } } - // note we assume the facade module chunk is itself linked - // with generateEntryExports called - linkFacade(entryFacade: Module) { - this.dependencies = [entryFacade.chunk]; - this.entryModule = entryFacade; - this.isEntryModuleFacade = true; - for (const exportName of entryFacade.getAllExports()) { - const tracedVariable = entryFacade.traceExport(exportName); - this.exports.set(tracedVariable, entryFacade); + turnIntoFacade(facadedModule: Module) { + this.dependencies = [facadedModule.chunk]; + this.entryModule = facadedModule; + facadedModule.chunk.facadeChunk = this; + for (const exportName of facadedModule.getAllExports()) { + const tracedVariable = facadedModule.traceExport(exportName); + this.exports.set(tracedVariable, facadedModule); this.exportNames[exportName] = tracedVariable; } } @@ -280,17 +279,19 @@ export default class Chunk { // tainted entryModule boundary if (existingExport && existingExport !== traced.variable) { this.isEntryModuleFacade = false; + this.isDynamicEntryFacade = false; } } // tainted if we've already exposed something not corresponding to entry exports for (const exposedVariable of Array.from(this.exports.keys())) { if (tracedExports.every(({ variable }) => variable !== exposedVariable)) { this.isEntryModuleFacade = false; + this.isDynamicEntryFacade = false; return; } } - if (preserveModules || this.isEntryModuleFacade || this.isDynamicEntryPoint) { + if (preserveModules || this.isEntryModuleFacade || this.isDynamicEntryFacade) { for (const [index, exportName] of entryExportEntries) { const traced = tracedExports[index]; if (!traced) { @@ -401,7 +402,7 @@ export default class Chunk { } generateInternalExports(options: OutputOptions) { - if (this.isEntryModuleFacade || this.isDynamicEntryPoint) return; + if (this.isEntryModuleFacade || this.isDynamicEntryFacade) return; const mangle = options.format === 'system' || options.format === 'es' || options.compact; let i = 0, safeExportName: string; @@ -468,8 +469,9 @@ export default class Chunk { if (!resolution) continue; if (resolution instanceof Module) { - if (resolution.chunk && resolution.chunk !== this && resolution.chunk.id) { - let relPath = normalize(relative(dirname(this.id), resolution.chunk.id)); + const resolutionChunk = resolution.chunk.facadeChunk || resolution.chunk; + if (resolutionChunk && resolutionChunk !== this && resolutionChunk.id) { + let relPath = normalize(relative(dirname(this.id), resolutionChunk.id)); if (!relPath.startsWith('../')) relPath = './' + relPath; node.renderFinalResolution(code, `"${relPath}"`); } @@ -817,7 +819,7 @@ export default class Chunk { }; // if an entry point facade or dynamic entry point, inline the execution list to avoid loading latency - if (this.isEntryModuleFacade || this.isDynamicEntryPoint) { + if (this.isEntryModuleFacade || this.isDynamicEntryFacade) { for (const dep of this.dependencies) { if (dep instanceof Chunk) this.inlineChunkDependencies(dep, true); } diff --git a/src/Graph.ts b/src/Graph.ts index 3e584c051fb..a099fef6024 100644 --- a/src/Graph.ts +++ b/src/Graph.ts @@ -369,7 +369,7 @@ export default class Graph { this.link(); - const { orderedModules, cyclePaths } = analyseModuleExecution(entryModules); + const { orderedModules, cyclePaths, dynamicImports } = analyseModuleExecution(entryModules); for (const cyclePath of cyclePaths) { this.warn({ code: 'CIRCULAR_DEPENDENCY', @@ -450,7 +450,11 @@ export default class Graph { // filter out empty dependencies chunks = chunks.filter( - chunk => !chunk.isEmpty || chunk.isEntryModuleFacade || chunk.isManualChunk + chunk => + !chunk.isEmpty || + chunk.isEntryModuleFacade || + chunk.isDynamicEntryFacade || + chunk.isManualChunk ); // then go over and ensure all entry chunks export their variables @@ -465,10 +469,25 @@ export default class Graph { for (const entryModule of entryModules) { if (!entryModule.chunk.isEntryModuleFacade) { const entryPointFacade = new Chunk(this, [], inlineDynamicImports); - entryPointFacade.linkFacade(entryModule); + entryPointFacade.turnIntoFacade(entryModule); + entryPointFacade.isEntryModuleFacade = true; chunks.push(entryPointFacade); } } + if (!inlineDynamicImports) { + for (const entryModule of dynamicImports) { + if ( + entryModule.isDynamicEntryPoint && + !entryModule.chunk.isDynamicEntryFacade && + !entryModule.chunk.facadeChunk + ) { + const entryPointFacade = new Chunk(this, [], inlineDynamicImports); + entryPointFacade.turnIntoFacade(entryModule); + entryPointFacade.isDynamicEntryFacade = true; + chunks.push(entryPointFacade); + } + } + } } timeEnd('generate chunks', 2); diff --git a/src/Module.ts b/src/Module.ts index cdf6b540e07..a7e47622a7d 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -635,6 +635,7 @@ export default class Module { private includeDynamicImport(node: Import) { const resolution = this.dynamicImportResolutions[this.dynamicImports.indexOf(node)].resolution; if (resolution instanceof Module) { + resolution.isDynamicEntryPoint = true; resolution.includeAllExports(); } } diff --git a/src/rollup/index.ts b/src/rollup/index.ts index 40857c7286e..b67cbc62498 100644 --- a/src/rollup/index.ts +++ b/src/rollup/index.ts @@ -295,13 +295,13 @@ export default function rollup( outputBundle[chunk.id] = { code: undefined, entryModuleId: - chunk.isEntryModuleFacade || chunk.isDynamicEntryPoint + chunk.isEntryModuleFacade || chunk.isDynamicEntryFacade ? chunk.entryModule.id : null, exports: chunk.getExportNames(), fileName: chunk.id, imports: chunk.getImportIds(), - isDynamicEntry: chunk.isDynamicEntryPoint, + isDynamicEntry: chunk.isDynamicEntryFacade, isEntry: chunk.isEntryModuleFacade, map: undefined, modules: chunk.renderedModules, diff --git a/src/utils/chunkColouring.ts b/src/utils/chunkColouring.ts index 9694ede5837..2abd8658de9 100644 --- a/src/utils/chunkColouring.ts +++ b/src/utils/chunkColouring.ts @@ -1,6 +1,6 @@ import ExternalModule from '../ExternalModule'; import Module from '../Module'; -import { randomUint8Array, Uint8ArrayEqual, Uint8ArrayXor } from './entryHashing'; +import { randomUint8Array, Uint8ArrayXor } from './entryHashing'; import { error } from './error'; import { relative } from './path'; @@ -31,13 +31,14 @@ export function assignChunkColouringHashes( } for (const dynamicModule of module.dynamicImportResolutions) { - if (dynamicModule.resolution instanceof Module && dynamicModule.resolution.isExecuted) { - if ( - dynamicModule.resolution.chunkAlias || - Uint8ArrayEqual(dynamicModule.resolution.entryPointsHash, currentEntry.entryPointsHash) - ) { + if ( + dynamicModule.resolution instanceof Module && + dynamicModule.resolution.isDynamicEntryPoint + ) { + if (dynamicModule.resolution.chunkAlias) { // We only assign separate colouring to a dynamic entry if it is not already - // part of the graph of a single entry point or a manual chunk + // part of the graph of a manual chunk + // TODO Lukas test this dynamicModule.resolution.isDynamicEntryPoint = false; } else { dynamicModule.resolution.isDynamicEntryPoint = true; diff --git a/src/utils/executionOrder.ts b/src/utils/executionOrder.ts index 61bfa8795a2..929f1958ba6 100644 --- a/src/utils/executionOrder.ts +++ b/src/utils/executionOrder.ts @@ -63,20 +63,19 @@ export function analyseModuleExecution(entryModules: Module[]) { curEntry.isEntryPoint = true; if (!parents[curEntry.id]) { parents[curEntry.id] = null; + analyseModule(curEntry); } - analyseModule(curEntry); } inStaticGraph = false; for (const curEntry of dynamicImports) { - curEntry.isDynamicEntryPoint = true; if (!parents[curEntry.id]) { parents[curEntry.id] = null; + analyseModule(curEntry); } - analyseModule(curEntry); } - return { orderedModules, cyclePaths }; + return { orderedModules, dynamicImports, cyclePaths }; } function getCyclePath(id: string, parentId: string, parents: { [id: string]: string | null }) { diff --git a/test/chunking-form/samples/dynamic-import-facade/_config.js b/test/chunking-form/samples/dynamic-import-facade/_config.js new file mode 100644 index 00000000000..a39a4962dc4 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-facade/_config.js @@ -0,0 +1,7 @@ +module.exports = { + description: 'makes sure dynamic chunks are not tainted', + options: { + input: ['main1.js', 'main2.js'] + } +}; +// TODO Lukas also test this has the right bundle information diff --git a/test/chunking-form/samples/dynamic-import-facade/_expected/amd/chunk-822f1303.js b/test/chunking-form/samples/dynamic-import-facade/_expected/amd/chunk-822f1303.js new file mode 100644 index 00000000000..74adaf7720f --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-facade/_expected/amd/chunk-822f1303.js @@ -0,0 +1,7 @@ +define(['exports', './chunk-d42319c1.js'], function (exports, dynamic_js) { 'use strict'; + + + + exports.dynamic = dynamic_js.dynamic; + +}); diff --git a/test/chunking-form/samples/dynamic-import-facade/_expected/amd/chunk-d42319c1.js b/test/chunking-form/samples/dynamic-import-facade/_expected/amd/chunk-d42319c1.js new file mode 100644 index 00000000000..7c2370c19a3 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-facade/_expected/amd/chunk-d42319c1.js @@ -0,0 +1,13 @@ +define(['exports'], function (exports) { 'use strict'; + + console.log('dep'); + + const dep = 'dep'; + + console.log('dynamic', dep); + const dynamic = 'dynamic'; + + exports.dep = dep; + exports.dynamic = dynamic; + +}); diff --git a/test/chunking-form/samples/dynamic-import-facade/_expected/amd/main1.js b/test/chunking-form/samples/dynamic-import-facade/_expected/amd/main1.js new file mode 100644 index 00000000000..607164a3716 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-facade/_expected/amd/main1.js @@ -0,0 +1,5 @@ +define(['require'], function (require) { 'use strict'; + + new Promise(function (resolve, reject) { require(["./chunk-822f1303.js"], resolve, reject) }).then(({dynamic}) => console.log('main1', dynamic)); + +}); diff --git a/test/chunking-form/samples/dynamic-import-facade/_expected/amd/main2.js b/test/chunking-form/samples/dynamic-import-facade/_expected/amd/main2.js new file mode 100644 index 00000000000..7897d3f5089 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-facade/_expected/amd/main2.js @@ -0,0 +1,5 @@ +define(['./chunk-d42319c1.js'], function (dynamic_js) { 'use strict'; + + console.log('main2', dynamic_js.dynamic, dynamic_js.dep); + +}); diff --git a/test/chunking-form/samples/dynamic-import-facade/_expected/cjs/chunk-0ad7c258.js b/test/chunking-form/samples/dynamic-import-facade/_expected/cjs/chunk-0ad7c258.js new file mode 100644 index 00000000000..2ec3ea65c66 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-facade/_expected/cjs/chunk-0ad7c258.js @@ -0,0 +1,7 @@ +'use strict'; + +var dynamic_js = require('./chunk-57ff6d6d.js'); + + + +exports.dynamic = dynamic_js.dynamic; diff --git a/test/chunking-form/samples/dynamic-import-facade/_expected/cjs/chunk-57ff6d6d.js b/test/chunking-form/samples/dynamic-import-facade/_expected/cjs/chunk-57ff6d6d.js new file mode 100644 index 00000000000..210a1e1c5bc --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-facade/_expected/cjs/chunk-57ff6d6d.js @@ -0,0 +1,11 @@ +'use strict'; + +console.log('dep'); + +const dep = 'dep'; + +console.log('dynamic', dep); +const dynamic = 'dynamic'; + +exports.dep = dep; +exports.dynamic = dynamic; diff --git a/test/chunking-form/samples/dynamic-import-facade/_expected/cjs/main1.js b/test/chunking-form/samples/dynamic-import-facade/_expected/cjs/main1.js new file mode 100644 index 00000000000..9b8a6ecd10f --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-facade/_expected/cjs/main1.js @@ -0,0 +1,3 @@ +'use strict'; + +Promise.resolve(require("./chunk-0ad7c258.js")).then(({dynamic}) => console.log('main1', dynamic)); diff --git a/test/chunking-form/samples/dynamic-import-facade/_expected/cjs/main2.js b/test/chunking-form/samples/dynamic-import-facade/_expected/cjs/main2.js new file mode 100644 index 00000000000..db275b5f6e4 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-facade/_expected/cjs/main2.js @@ -0,0 +1,5 @@ +'use strict'; + +var dynamic_js = require('./chunk-57ff6d6d.js'); + +console.log('main2', dynamic_js.dynamic, dynamic_js.dep); diff --git a/test/chunking-form/samples/dynamic-import-facade/_expected/es/chunk-9fd0b968.js b/test/chunking-form/samples/dynamic-import-facade/_expected/es/chunk-9fd0b968.js new file mode 100644 index 00000000000..14faa75894f --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-facade/_expected/es/chunk-9fd0b968.js @@ -0,0 +1 @@ +export { b as dynamic } from './chunk-fa3f0c72.js'; diff --git a/test/chunking-form/samples/dynamic-import-facade/_expected/es/chunk-fa3f0c72.js b/test/chunking-form/samples/dynamic-import-facade/_expected/es/chunk-fa3f0c72.js new file mode 100644 index 00000000000..37053a9255c --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-facade/_expected/es/chunk-fa3f0c72.js @@ -0,0 +1,8 @@ +console.log('dep'); + +const dep = 'dep'; + +console.log('dynamic', dep); +const dynamic = 'dynamic'; + +export { dep as a, dynamic as b }; diff --git a/test/chunking-form/samples/dynamic-import-facade/_expected/es/main1.js b/test/chunking-form/samples/dynamic-import-facade/_expected/es/main1.js new file mode 100644 index 00000000000..26f490bcf17 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-facade/_expected/es/main1.js @@ -0,0 +1 @@ +import("./chunk-9fd0b968.js").then(({dynamic}) => console.log('main1', dynamic)); diff --git a/test/chunking-form/samples/dynamic-import-facade/_expected/es/main2.js b/test/chunking-form/samples/dynamic-import-facade/_expected/es/main2.js new file mode 100644 index 00000000000..288ebafb02c --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-facade/_expected/es/main2.js @@ -0,0 +1,3 @@ +import { a as dep, b as dynamic } from './chunk-fa3f0c72.js'; + +console.log('main2', dynamic, dep); diff --git a/test/chunking-form/samples/dynamic-import-facade/_expected/system/chunk-55e635b3.js b/test/chunking-form/samples/dynamic-import-facade/_expected/system/chunk-55e635b3.js new file mode 100644 index 00000000000..0092d9f8101 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-facade/_expected/system/chunk-55e635b3.js @@ -0,0 +1,15 @@ +System.register([], function (exports, module) { + 'use strict'; + return { + execute: function () { + + console.log('dep'); + + const dep = exports('a', 'dep'); + + console.log('dynamic', dep); + const dynamic = exports('b', 'dynamic'); + + } + }; +}); diff --git a/test/chunking-form/samples/dynamic-import-facade/_expected/system/chunk-d225f367.js b/test/chunking-form/samples/dynamic-import-facade/_expected/system/chunk-d225f367.js new file mode 100644 index 00000000000..db29f31bc42 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-facade/_expected/system/chunk-d225f367.js @@ -0,0 +1,13 @@ +System.register(['./chunk-55e635b3.js'], function (exports, module) { + 'use strict'; + return { + setters: [function (module) { + exports('dynamic', module.b); + }], + execute: function () { + + + + } + }; +}); diff --git a/test/chunking-form/samples/dynamic-import-facade/_expected/system/main1.js b/test/chunking-form/samples/dynamic-import-facade/_expected/system/main1.js new file mode 100644 index 00000000000..4bfd130f92a --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-facade/_expected/system/main1.js @@ -0,0 +1,10 @@ +System.register([], function (exports, module) { + 'use strict'; + return { + execute: function () { + + module.import("./chunk-d225f367.js").then(({dynamic}) => console.log('main1', dynamic)); + + } + }; +}); diff --git a/test/chunking-form/samples/dynamic-import-facade/_expected/system/main2.js b/test/chunking-form/samples/dynamic-import-facade/_expected/system/main2.js new file mode 100644 index 00000000000..96e037f1b38 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-facade/_expected/system/main2.js @@ -0,0 +1,15 @@ +System.register(['./chunk-55e635b3.js'], function (exports, module) { + 'use strict'; + var dep, dynamic; + return { + setters: [function (module) { + dep = module.a; + dynamic = module.b; + }], + execute: function () { + + console.log('main2', dynamic, dep); + + } + }; +}); diff --git a/test/chunking-form/samples/dynamic-import-facade/dep.js b/test/chunking-form/samples/dynamic-import-facade/dep.js new file mode 100644 index 00000000000..4a9a55b5887 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-facade/dep.js @@ -0,0 +1,3 @@ +console.log('dep'); + +export const dep = 'dep'; diff --git a/test/chunking-form/samples/dynamic-import-facade/dynamic.js b/test/chunking-form/samples/dynamic-import-facade/dynamic.js new file mode 100644 index 00000000000..89989daed6f --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-facade/dynamic.js @@ -0,0 +1,4 @@ +import {dep} from './dep'; + +console.log('dynamic', dep); +export const dynamic = 'dynamic'; diff --git a/test/chunking-form/samples/dynamic-import-facade/main1.js b/test/chunking-form/samples/dynamic-import-facade/main1.js new file mode 100644 index 00000000000..69910b8e505 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-facade/main1.js @@ -0,0 +1 @@ +import('./dynamic.js').then(({dynamic}) => console.log('main1', dynamic)); diff --git a/test/chunking-form/samples/dynamic-import-facade/main2.js b/test/chunking-form/samples/dynamic-import-facade/main2.js new file mode 100644 index 00000000000..9833454d148 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-facade/main2.js @@ -0,0 +1,4 @@ +import { dep } from './dep.js'; +import { dynamic } from './dynamic.js'; + +console.log('main2', dynamic, dep); diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_config.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_config.js index 3455a5a1653..b5769882caf 100644 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/_config.js +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_config.js @@ -1,5 +1,5 @@ module.exports = { - description: 'Dynamic import inlining for static colouring', + description: 'Handle dynamic imports that are part of a static graph', options: { input: ['main1.js', 'main2.js'] } diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/chunk-d309b27d.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/chunk-d309b27d.js new file mode 100644 index 00000000000..eeab6552e64 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/chunk-d309b27d.js @@ -0,0 +1,9 @@ +define(['exports'], function (exports) { 'use strict'; + + var inlined = 'inlined'; + const x = 1; + + exports.default = inlined; + exports.x = x; + +}); diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main1.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main1.js index feb411419db..054ae669217 100644 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main1.js +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main1.js @@ -1,17 +1,9 @@ -define(['require', 'exports', './chunk-a2558f00.js'], function (require, exports, separate_js) { 'use strict'; +define(['require', 'exports', './chunk-d309b27d.js', './chunk-a2558f00.js'], function (require, exports, inlined_js, separate_js) { 'use strict'; - var inlined = 'inlined'; - const x = 1; - - var inlined$1 = /*#__PURE__*/Object.freeze({ - default: inlined, - x: x - }); - - const inlined$2 = Promise.resolve().then(function () { return inlined$1; }); + const inlined = new Promise(function (resolve, reject) { require(["./chunk-d309b27d.js"], resolve, reject) }); const separate = new Promise(function (resolve, reject) { require(["./chunk-a2558f00.js"], resolve, reject) }); - exports.inlined = inlined$2; + exports.inlined = inlined; exports.separate = separate; Object.defineProperty(exports, '__esModule', { value: true }); diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/chunk-e4f8b8db.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/chunk-e4f8b8db.js new file mode 100644 index 00000000000..42f7789b8cf --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/chunk-e4f8b8db.js @@ -0,0 +1,7 @@ +'use strict'; + +var inlined = 'inlined'; +const x = 1; + +exports.default = inlined; +exports.x = x; diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main1.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main1.js index 70618272b71..830463ba9ac 100644 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main1.js +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main1.js @@ -2,18 +2,11 @@ Object.defineProperty(exports, '__esModule', { value: true }); +require('./chunk-e4f8b8db.js'); require('./chunk-bc97caee.js'); -var inlined = 'inlined'; -const x = 1; - -var inlined$1 = /*#__PURE__*/Object.freeze({ - default: inlined, - x: x -}); - -const inlined$2 = Promise.resolve().then(function () { return inlined$1; }); +const inlined = Promise.resolve(require("./chunk-e4f8b8db.js")); const separate = Promise.resolve(require("./chunk-bc97caee.js")); -exports.inlined = inlined$2; +exports.inlined = inlined; exports.separate = separate; diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/chunk-6d572aec.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/chunk-6d572aec.js new file mode 100644 index 00000000000..d13cbecbfa4 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/chunk-6d572aec.js @@ -0,0 +1,5 @@ +var inlined = 'inlined'; +const x = 1; + +export default inlined; +export { x }; diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main1.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main1.js index cc5950d949a..d9aab466259 100644 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main1.js +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main1.js @@ -1,14 +1,7 @@ +import './chunk-6d572aec.js'; import './chunk-61f7224d.js'; -var inlined = 'inlined'; -const x = 1; - -var inlined$1 = /*#__PURE__*/Object.freeze({ - default: inlined, - x: x -}); - -const inlined$2 = Promise.resolve().then(function () { return inlined$1; }); +const inlined = import("./chunk-6d572aec.js"); const separate = import("./chunk-61f7224d.js"); -export { inlined$2 as inlined, separate }; +export { inlined, separate }; diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/chunk-cdaf79ed.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/chunk-cdaf79ed.js new file mode 100644 index 00000000000..d0c94460fe2 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/chunk-cdaf79ed.js @@ -0,0 +1,11 @@ +System.register([], function (exports, module) { + 'use strict'; + return { + execute: function () { + + var inlined = exports('default', 'inlined'); + const x = exports('x', 1); + + } + }; +}); diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main1.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main1.js index 367d61a8569..beaa04b0d0a 100644 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main1.js +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main1.js @@ -1,18 +1,10 @@ -System.register(['./chunk-9df34bdb.js'], function (exports, module) { +System.register(['./chunk-cdaf79ed.js', './chunk-9df34bdb.js'], function (exports, module) { 'use strict'; return { - setters: [function () {}], + setters: [function () {}, function () {}], execute: function () { - var inlined = 'inlined'; - const x = 1; - - var inlined$1 = /*#__PURE__*/Object.freeze({ - default: inlined, - x: x - }); - - const inlined$2 = exports('inlined', Promise.resolve().then(function () { return inlined$1; })); + const inlined = exports('inlined', module.import("./chunk-cdaf79ed.js")); const separate = exports('separate', module.import("./chunk-9df34bdb.js")); } diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-2/_config.js b/test/chunking-form/samples/dynamic-import-tree-shaking-2/_config.js new file mode 100644 index 00000000000..6d2783787e6 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-2/_config.js @@ -0,0 +1,6 @@ +module.exports = { + description: 'does not expose exports of chunks which were used by tree-shaken dynamic imports', + options: { + input: ['main1.js', 'main2.js'] + } +}; diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/amd/main1.js b/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/amd/main1.js new file mode 100644 index 00000000000..a2d15717cea --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/amd/main1.js @@ -0,0 +1,5 @@ +define(['require'], function (require) { 'use strict'; + + console.log('main1'); + +}); diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/amd/main2.js b/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/amd/main2.js new file mode 100644 index 00000000000..25c0aadce80 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/amd/main2.js @@ -0,0 +1,10 @@ +define(function () { 'use strict'; + + console.log('dep'); + const dep = 'dep'; + + console.log('dynamic', dep); + + console.log('main2', dep); + +}); diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/cjs/main1.js b/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/cjs/main1.js new file mode 100644 index 00000000000..34e0c8c26cd --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/cjs/main1.js @@ -0,0 +1,3 @@ +'use strict'; + +console.log('main1'); diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/cjs/main2.js b/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/cjs/main2.js new file mode 100644 index 00000000000..bdbac3ae29b --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/cjs/main2.js @@ -0,0 +1,8 @@ +'use strict'; + +console.log('dep'); +const dep = 'dep'; + +console.log('dynamic', dep); + +console.log('main2', dep); diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/es/main1.js b/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/es/main1.js new file mode 100644 index 00000000000..fda34828717 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/es/main1.js @@ -0,0 +1 @@ +console.log('main1'); diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/es/main2.js b/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/es/main2.js new file mode 100644 index 00000000000..f65207f3ed1 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/es/main2.js @@ -0,0 +1,6 @@ +console.log('dep'); +const dep = 'dep'; + +console.log('dynamic', dep); + +console.log('main2', dep); diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/system/main1.js b/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/system/main1.js new file mode 100644 index 00000000000..d426b473433 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/system/main1.js @@ -0,0 +1,10 @@ +System.register([], function (exports, module) { + 'use strict'; + return { + execute: function () { + + console.log('main1'); + + } + }; +}); diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/system/main2.js b/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/system/main2.js new file mode 100644 index 00000000000..74d18f428b8 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/system/main2.js @@ -0,0 +1,15 @@ +System.register([], function (exports, module) { + 'use strict'; + return { + execute: function () { + + console.log('dep'); + const dep = 'dep'; + + console.log('dynamic', dep); + + console.log('main2', dep); + + } + }; +}); diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-2/dep.js b/test/chunking-form/samples/dynamic-import-tree-shaking-2/dep.js new file mode 100644 index 00000000000..ba2dab33f2d --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-2/dep.js @@ -0,0 +1,2 @@ +console.log('dep'); +export const dep = 'dep'; diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-2/dynamic.js b/test/chunking-form/samples/dynamic-import-tree-shaking-2/dynamic.js new file mode 100644 index 00000000000..630fbf0a902 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-2/dynamic.js @@ -0,0 +1,4 @@ +import { dep } from './dep'; + +console.log('dynamic', dep); +export const dynamic = 'dynamic'; diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-2/main1.js b/test/chunking-form/samples/dynamic-import-tree-shaking-2/main1.js new file mode 100644 index 00000000000..3911a49e217 --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-2/main1.js @@ -0,0 +1,4 @@ +if (false) { + import('./dynamic.js'); +} +console.log('main1'); diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-2/main2.js b/test/chunking-form/samples/dynamic-import-tree-shaking-2/main2.js new file mode 100644 index 00000000000..c54398cb4db --- /dev/null +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-2/main2.js @@ -0,0 +1,4 @@ +import { dep } from './dep.js'; +import './dynamic.js'; + +console.log('main2', dep); From 32aa5f402cef4179bbde5b213d0ae2efb28bd437 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Tue, 27 Nov 2018 08:30:54 +0100 Subject: [PATCH 12/23] As with normal imports, also use single quotes for dynamic imports --- src/Chunk.ts | 4 ++-- .../aliasing-extensions/_expected/amd/main1.js | 4 ++-- .../aliasing-extensions/_expected/cjs/main1.js | 4 ++-- .../aliasing-extensions/_expected/es/main1.js | 4 ++-- .../aliasing-extensions/_expected/system/main1.js | 4 ++-- .../_expected/amd/generated-chunk2.js | 2 +- .../dynamic-import-chained/_expected/amd/main.js | 2 +- .../_expected/cjs/generated-chunk2.js | 2 +- .../dynamic-import-chained/_expected/cjs/main.js | 2 +- .../_expected/es/generated-chunk2.js | 2 +- .../dynamic-import-chained/_expected/es/main.js | 2 +- .../_expected/system/generated-chunk2.js | 2 +- .../_expected/system/main.js | 2 +- .../dynamic-import-chunking/_expected/amd/main.js | 2 +- .../dynamic-import-chunking/_expected/cjs/main.js | 2 +- .../dynamic-import-chunking/_expected/es/main.js | 2 +- .../_expected/system/main.js | 2 +- .../dynamic-import-facade/_expected/amd/main1.js | 2 +- .../dynamic-import-facade/_expected/cjs/main1.js | 2 +- .../dynamic-import-facade/_expected/es/main1.js | 2 +- .../_expected/system/main1.js | 2 +- .../_expected/amd/main1.js | 4 ++-- .../_expected/amd/main2.js | 2 +- .../_expected/cjs/main1.js | 4 ++-- .../_expected/cjs/main2.js | 2 +- .../_expected/es/main1.js | 4 ++-- .../_expected/es/main2.js | 2 +- .../_expected/system/main1.js | 4 ++-- .../_expected/system/main2.js | 2 +- .../_expected/amd/main.js | 2 +- .../_expected/cjs/main.js | 2 +- .../_expected/es/main.js | 2 +- .../_expected/system/main.js | 2 +- test/misc/bundle-information.js | 14 ++++++++------ 34 files changed, 50 insertions(+), 48 deletions(-) diff --git a/src/Chunk.ts b/src/Chunk.ts index 877b91566fb..c76e7dcfcb4 100644 --- a/src/Chunk.ts +++ b/src/Chunk.ts @@ -473,10 +473,10 @@ export default class Chunk { if (resolutionChunk && resolutionChunk !== this && resolutionChunk.id) { let relPath = normalize(relative(dirname(this.id), resolutionChunk.id)); if (!relPath.startsWith('../')) relPath = './' + relPath; - node.renderFinalResolution(code, `"${relPath}"`); + node.renderFinalResolution(code, `'${relPath}'`); } } else if (resolution instanceof ExternalModule) { - node.renderFinalResolution(code, `"${resolution.id}"`); + node.renderFinalResolution(code, `'${resolution.id}'`); // AST Node -> source replacement } else { node.renderFinalResolution(code, resolution); diff --git a/test/chunking-form/samples/aliasing-extensions/_expected/amd/main1.js b/test/chunking-form/samples/aliasing-extensions/_expected/amd/main1.js index 3b27d3206d3..97a0f22a858 100644 --- a/test/chunking-form/samples/aliasing-extensions/_expected/amd/main1.js +++ b/test/chunking-form/samples/aliasing-extensions/_expected/amd/main1.js @@ -1,7 +1,7 @@ define(['require'], function (require) { 'use strict'; console.log('main1'); - new Promise(function (resolve, reject) { require(["./generated-chunk.js"], resolve, reject) }); - new Promise(function (resolve, reject) { require(["./generated-chunk2.js"], resolve, reject) }); + new Promise(function (resolve, reject) { require(['./generated-chunk.js'], resolve, reject) }); + new Promise(function (resolve, reject) { require(['./generated-chunk2.js'], resolve, reject) }); }); diff --git a/test/chunking-form/samples/aliasing-extensions/_expected/cjs/main1.js b/test/chunking-form/samples/aliasing-extensions/_expected/cjs/main1.js index a93a61559d3..ffb10b14b6d 100644 --- a/test/chunking-form/samples/aliasing-extensions/_expected/cjs/main1.js +++ b/test/chunking-form/samples/aliasing-extensions/_expected/cjs/main1.js @@ -1,5 +1,5 @@ 'use strict'; console.log('main1'); -Promise.resolve(require("./generated-chunk.js")); -Promise.resolve(require("./generated-chunk2.js")); +Promise.resolve(require('./generated-chunk.js')); +Promise.resolve(require('./generated-chunk2.js')); diff --git a/test/chunking-form/samples/aliasing-extensions/_expected/es/main1.js b/test/chunking-form/samples/aliasing-extensions/_expected/es/main1.js index 60be58c15af..de1c78214cd 100644 --- a/test/chunking-form/samples/aliasing-extensions/_expected/es/main1.js +++ b/test/chunking-form/samples/aliasing-extensions/_expected/es/main1.js @@ -1,3 +1,3 @@ console.log('main1'); -import("./generated-chunk.js"); -import("./generated-chunk2.js"); +import('./generated-chunk.js'); +import('./generated-chunk2.js'); diff --git a/test/chunking-form/samples/aliasing-extensions/_expected/system/main1.js b/test/chunking-form/samples/aliasing-extensions/_expected/system/main1.js index 5ee5a7f26b8..fe72dd01fb6 100644 --- a/test/chunking-form/samples/aliasing-extensions/_expected/system/main1.js +++ b/test/chunking-form/samples/aliasing-extensions/_expected/system/main1.js @@ -4,8 +4,8 @@ System.register([], function (exports, module) { execute: function () { console.log('main1'); - module.import("./generated-chunk.js"); - module.import("./generated-chunk2.js"); + module.import('./generated-chunk.js'); + module.import('./generated-chunk2.js'); } }; diff --git a/test/chunking-form/samples/dynamic-import-chained/_expected/amd/generated-chunk2.js b/test/chunking-form/samples/dynamic-import-chained/_expected/amd/generated-chunk2.js index 49f374817d1..dd1c3279a6c 100644 --- a/test/chunking-form/samples/dynamic-import-chained/_expected/amd/generated-chunk2.js +++ b/test/chunking-form/samples/dynamic-import-chained/_expected/amd/generated-chunk2.js @@ -1,6 +1,6 @@ define(['require'], function (require) { 'use strict'; console.log('dep1'); - new Promise(function (resolve, reject) { require(["./generated-chunk.js"], resolve, reject) }); + new Promise(function (resolve, reject) { require(['./generated-chunk.js'], resolve, reject) }); }); diff --git a/test/chunking-form/samples/dynamic-import-chained/_expected/amd/main.js b/test/chunking-form/samples/dynamic-import-chained/_expected/amd/main.js index 6c24d50ea37..5ccfb90eecb 100644 --- a/test/chunking-form/samples/dynamic-import-chained/_expected/amd/main.js +++ b/test/chunking-form/samples/dynamic-import-chained/_expected/amd/main.js @@ -1,6 +1,6 @@ define(['require'], function (require) { 'use strict'; console.log('main'); - new Promise(function (resolve, reject) { require(["./generated-chunk2.js"], resolve, reject) }); + new Promise(function (resolve, reject) { require(['./generated-chunk2.js'], resolve, reject) }); }); diff --git a/test/chunking-form/samples/dynamic-import-chained/_expected/cjs/generated-chunk2.js b/test/chunking-form/samples/dynamic-import-chained/_expected/cjs/generated-chunk2.js index e4194322104..264ed3db946 100644 --- a/test/chunking-form/samples/dynamic-import-chained/_expected/cjs/generated-chunk2.js +++ b/test/chunking-form/samples/dynamic-import-chained/_expected/cjs/generated-chunk2.js @@ -1,4 +1,4 @@ 'use strict'; console.log('dep1'); -Promise.resolve(require("./generated-chunk.js")); +Promise.resolve(require('./generated-chunk.js')); diff --git a/test/chunking-form/samples/dynamic-import-chained/_expected/cjs/main.js b/test/chunking-form/samples/dynamic-import-chained/_expected/cjs/main.js index 3525048b260..f94f250a8bb 100644 --- a/test/chunking-form/samples/dynamic-import-chained/_expected/cjs/main.js +++ b/test/chunking-form/samples/dynamic-import-chained/_expected/cjs/main.js @@ -1,4 +1,4 @@ 'use strict'; console.log('main'); -Promise.resolve(require("./generated-chunk2.js")); +Promise.resolve(require('./generated-chunk2.js')); diff --git a/test/chunking-form/samples/dynamic-import-chained/_expected/es/generated-chunk2.js b/test/chunking-form/samples/dynamic-import-chained/_expected/es/generated-chunk2.js index a6dcf6e8496..829d0490ba6 100644 --- a/test/chunking-form/samples/dynamic-import-chained/_expected/es/generated-chunk2.js +++ b/test/chunking-form/samples/dynamic-import-chained/_expected/es/generated-chunk2.js @@ -1,2 +1,2 @@ console.log('dep1'); -import("./generated-chunk.js"); +import('./generated-chunk.js'); diff --git a/test/chunking-form/samples/dynamic-import-chained/_expected/es/main.js b/test/chunking-form/samples/dynamic-import-chained/_expected/es/main.js index 575719c8eb4..8e124b5d186 100644 --- a/test/chunking-form/samples/dynamic-import-chained/_expected/es/main.js +++ b/test/chunking-form/samples/dynamic-import-chained/_expected/es/main.js @@ -1,2 +1,2 @@ console.log('main'); -import("./generated-chunk2.js"); +import('./generated-chunk2.js'); diff --git a/test/chunking-form/samples/dynamic-import-chained/_expected/system/generated-chunk2.js b/test/chunking-form/samples/dynamic-import-chained/_expected/system/generated-chunk2.js index 91207f17141..83e8602aefd 100644 --- a/test/chunking-form/samples/dynamic-import-chained/_expected/system/generated-chunk2.js +++ b/test/chunking-form/samples/dynamic-import-chained/_expected/system/generated-chunk2.js @@ -4,7 +4,7 @@ System.register([], function (exports, module) { execute: function () { console.log('dep1'); - module.import("./generated-chunk.js"); + module.import('./generated-chunk.js'); } }; diff --git a/test/chunking-form/samples/dynamic-import-chained/_expected/system/main.js b/test/chunking-form/samples/dynamic-import-chained/_expected/system/main.js index a64e73af4f3..7dfd4a28cae 100644 --- a/test/chunking-form/samples/dynamic-import-chained/_expected/system/main.js +++ b/test/chunking-form/samples/dynamic-import-chained/_expected/system/main.js @@ -4,7 +4,7 @@ System.register([], function (exports, module) { execute: function () { console.log('main'); - module.import("./generated-chunk2.js"); + module.import('./generated-chunk2.js'); } }; diff --git a/test/chunking-form/samples/dynamic-import-chunking/_expected/amd/main.js b/test/chunking-form/samples/dynamic-import-chunking/_expected/amd/main.js index db6fe608a75..30e89b9397c 100644 --- a/test/chunking-form/samples/dynamic-import-chunking/_expected/amd/main.js +++ b/test/chunking-form/samples/dynamic-import-chunking/_expected/amd/main.js @@ -9,7 +9,7 @@ define(['require', './chunk-7b720877.js'], function (require, __chunk_1) { 'use } function dynamic (num) { - return new Promise(function (resolve, reject) { require(["./chunk-8ea4f89e.js"], resolve, reject) }) + return new Promise(function (resolve, reject) { require(['./chunk-8ea4f89e.js'], resolve, reject) }) .then(dep2 => { return dep2.mult(num); }); diff --git a/test/chunking-form/samples/dynamic-import-chunking/_expected/cjs/main.js b/test/chunking-form/samples/dynamic-import-chunking/_expected/cjs/main.js index 1d85666ece6..1aa12cb7927 100644 --- a/test/chunking-form/samples/dynamic-import-chunking/_expected/cjs/main.js +++ b/test/chunking-form/samples/dynamic-import-chunking/_expected/cjs/main.js @@ -11,7 +11,7 @@ function fn (num) { } function dynamic (num) { - return Promise.resolve(require("./chunk-38762abc.js")) + return Promise.resolve(require('./chunk-38762abc.js')) .then(dep2 => { return dep2.mult(num); }); diff --git a/test/chunking-form/samples/dynamic-import-chunking/_expected/es/main.js b/test/chunking-form/samples/dynamic-import-chunking/_expected/es/main.js index 8314fb558c6..c4b407daf5c 100644 --- a/test/chunking-form/samples/dynamic-import-chunking/_expected/es/main.js +++ b/test/chunking-form/samples/dynamic-import-chunking/_expected/es/main.js @@ -9,7 +9,7 @@ function fn (num) { } function dynamic (num) { - return import("./chunk-a97cfc63.js") + return import('./chunk-a97cfc63.js') .then(dep2 => { return dep2.mult(num); }); diff --git a/test/chunking-form/samples/dynamic-import-chunking/_expected/system/main.js b/test/chunking-form/samples/dynamic-import-chunking/_expected/system/main.js index 6db7e928aa5..d9cfae39e95 100644 --- a/test/chunking-form/samples/dynamic-import-chunking/_expected/system/main.js +++ b/test/chunking-form/samples/dynamic-import-chunking/_expected/system/main.js @@ -16,7 +16,7 @@ System.register(['./chunk-4d8f4e43.js'], function (exports, module) { } function dynamic (num) { - return module.import("./chunk-b7f9caf2.js") + return module.import('./chunk-b7f9caf2.js') .then(dep2 => { return dep2.mult(num); }); diff --git a/test/chunking-form/samples/dynamic-import-facade/_expected/amd/main1.js b/test/chunking-form/samples/dynamic-import-facade/_expected/amd/main1.js index 607164a3716..f86b485fbd0 100644 --- a/test/chunking-form/samples/dynamic-import-facade/_expected/amd/main1.js +++ b/test/chunking-form/samples/dynamic-import-facade/_expected/amd/main1.js @@ -1,5 +1,5 @@ define(['require'], function (require) { 'use strict'; - new Promise(function (resolve, reject) { require(["./chunk-822f1303.js"], resolve, reject) }).then(({dynamic}) => console.log('main1', dynamic)); + new Promise(function (resolve, reject) { require(['./chunk-822f1303.js'], resolve, reject) }).then(({dynamic}) => console.log('main1', dynamic)); }); diff --git a/test/chunking-form/samples/dynamic-import-facade/_expected/cjs/main1.js b/test/chunking-form/samples/dynamic-import-facade/_expected/cjs/main1.js index 9b8a6ecd10f..935d3463248 100644 --- a/test/chunking-form/samples/dynamic-import-facade/_expected/cjs/main1.js +++ b/test/chunking-form/samples/dynamic-import-facade/_expected/cjs/main1.js @@ -1,3 +1,3 @@ 'use strict'; -Promise.resolve(require("./chunk-0ad7c258.js")).then(({dynamic}) => console.log('main1', dynamic)); +Promise.resolve(require('./chunk-0ad7c258.js')).then(({dynamic}) => console.log('main1', dynamic)); diff --git a/test/chunking-form/samples/dynamic-import-facade/_expected/es/main1.js b/test/chunking-form/samples/dynamic-import-facade/_expected/es/main1.js index 26f490bcf17..64d20ffd0d1 100644 --- a/test/chunking-form/samples/dynamic-import-facade/_expected/es/main1.js +++ b/test/chunking-form/samples/dynamic-import-facade/_expected/es/main1.js @@ -1 +1 @@ -import("./chunk-9fd0b968.js").then(({dynamic}) => console.log('main1', dynamic)); +import('./chunk-9fd0b968.js').then(({dynamic}) => console.log('main1', dynamic)); diff --git a/test/chunking-form/samples/dynamic-import-facade/_expected/system/main1.js b/test/chunking-form/samples/dynamic-import-facade/_expected/system/main1.js index 4bfd130f92a..35f39e567cb 100644 --- a/test/chunking-form/samples/dynamic-import-facade/_expected/system/main1.js +++ b/test/chunking-form/samples/dynamic-import-facade/_expected/system/main1.js @@ -3,7 +3,7 @@ System.register([], function (exports, module) { return { execute: function () { - module.import("./chunk-d225f367.js").then(({dynamic}) => console.log('main1', dynamic)); + module.import('./chunk-d225f367.js').then(({dynamic}) => console.log('main1', dynamic)); } }; diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main1.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main1.js index 054ae669217..4a6cf7a204a 100644 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main1.js +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main1.js @@ -1,7 +1,7 @@ define(['require', 'exports', './chunk-d309b27d.js', './chunk-a2558f00.js'], function (require, exports, inlined_js, separate_js) { 'use strict'; - const inlined = new Promise(function (resolve, reject) { require(["./chunk-d309b27d.js"], resolve, reject) }); - const separate = new Promise(function (resolve, reject) { require(["./chunk-a2558f00.js"], resolve, reject) }); + const inlined = new Promise(function (resolve, reject) { require(['./chunk-d309b27d.js'], resolve, reject) }); + const separate = new Promise(function (resolve, reject) { require(['./chunk-a2558f00.js'], resolve, reject) }); exports.inlined = inlined; exports.separate = separate; diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main2.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main2.js index 035ef97d78d..efd0fdd1e70 100644 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main2.js +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/amd/main2.js @@ -1,6 +1,6 @@ define(['require', 'exports'], function (require, exports) { 'use strict'; - const separate = new Promise(function (resolve, reject) { require(["./chunk-a2558f00.js"], resolve, reject) }); + const separate = new Promise(function (resolve, reject) { require(['./chunk-a2558f00.js'], resolve, reject) }); exports.separate = separate; diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main1.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main1.js index 830463ba9ac..0ea38c8b561 100644 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main1.js +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main1.js @@ -5,8 +5,8 @@ Object.defineProperty(exports, '__esModule', { value: true }); require('./chunk-e4f8b8db.js'); require('./chunk-bc97caee.js'); -const inlined = Promise.resolve(require("./chunk-e4f8b8db.js")); -const separate = Promise.resolve(require("./chunk-bc97caee.js")); +const inlined = Promise.resolve(require('./chunk-e4f8b8db.js')); +const separate = Promise.resolve(require('./chunk-bc97caee.js')); exports.inlined = inlined; exports.separate = separate; diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main2.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main2.js index 4f8fc54321b..602133f2047 100644 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main2.js +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/cjs/main2.js @@ -2,6 +2,6 @@ Object.defineProperty(exports, '__esModule', { value: true }); -const separate = Promise.resolve(require("./chunk-bc97caee.js")); +const separate = Promise.resolve(require('./chunk-bc97caee.js')); exports.separate = separate; diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main1.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main1.js index d9aab466259..84ceaf1e669 100644 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main1.js +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main1.js @@ -1,7 +1,7 @@ import './chunk-6d572aec.js'; import './chunk-61f7224d.js'; -const inlined = import("./chunk-6d572aec.js"); -const separate = import("./chunk-61f7224d.js"); +const inlined = import('./chunk-6d572aec.js'); +const separate = import('./chunk-61f7224d.js'); export { inlined, separate }; diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main2.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main2.js index 1398bd14f8e..ef6e5c38ceb 100644 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main2.js +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/es/main2.js @@ -1,3 +1,3 @@ -const separate = import("./chunk-61f7224d.js"); +const separate = import('./chunk-61f7224d.js'); export { separate }; diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main1.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main1.js index beaa04b0d0a..0f36bf48128 100644 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main1.js +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main1.js @@ -4,8 +4,8 @@ System.register(['./chunk-cdaf79ed.js', './chunk-9df34bdb.js'], function (export setters: [function () {}, function () {}], execute: function () { - const inlined = exports('inlined', module.import("./chunk-cdaf79ed.js")); - const separate = exports('separate', module.import("./chunk-9df34bdb.js")); + const inlined = exports('inlined', module.import('./chunk-cdaf79ed.js')); + const separate = exports('separate', module.import('./chunk-9df34bdb.js')); } }; diff --git a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main2.js b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main2.js index 18a6031b7a0..c0e58609b00 100644 --- a/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main2.js +++ b/test/chunking-form/samples/dynamic-import-inline-colouring/_expected/system/main2.js @@ -3,7 +3,7 @@ System.register([], function (exports, module) { return { execute: function () { - const separate = exports('separate', module.import("./chunk-9df34bdb.js")); + const separate = exports('separate', module.import('./chunk-9df34bdb.js')); } }; diff --git a/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/amd/main.js b/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/amd/main.js index 0d0f86d426d..83b30a7c2ee 100644 --- a/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/amd/main.js +++ b/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/amd/main.js @@ -1,5 +1,5 @@ define(['require'], function (require) { 'use strict'; - new Promise(function (resolve, reject) { require(["./dynamic-included.js"], resolve, reject) }).then(result => console.log(result)); + new Promise(function (resolve, reject) { require(['./dynamic-included.js'], resolve, reject) }).then(result => console.log(result)); }); diff --git a/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/cjs/main.js b/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/cjs/main.js index 3bd435b43da..4c20525ca3f 100644 --- a/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/cjs/main.js +++ b/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/cjs/main.js @@ -1,3 +1,3 @@ 'use strict'; -Promise.resolve(require("./dynamic-included.js")).then(result => console.log(result)); +Promise.resolve(require('./dynamic-included.js')).then(result => console.log(result)); diff --git a/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/es/main.js b/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/es/main.js index 1c47244d33e..72ed76ddf10 100644 --- a/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/es/main.js +++ b/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/es/main.js @@ -1 +1 @@ -import("./dynamic-included.js").then(result => console.log(result)); +import('./dynamic-included.js').then(result => console.log(result)); diff --git a/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/system/main.js b/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/system/main.js index 35bff8cf139..26c21dcccb5 100644 --- a/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/system/main.js +++ b/test/chunking-form/samples/preserve-modules-dynamic-imports/_expected/system/main.js @@ -3,7 +3,7 @@ System.register([], function (exports, module) { return { execute: function () { - module.import("./dynamic-included.js").then(result => console.log(result)); + module.import('./dynamic-included.js').then(result => console.log(result)); } }; diff --git a/test/misc/bundle-information.js b/test/misc/bundle-information.js index c321efd7a51..a371272af65 100644 --- a/test/misc/bundle-information.js +++ b/test/misc/bundle-information.js @@ -37,8 +37,8 @@ describe('The bundle object', () => { sortedOutput.map(chunk => chunk.code), [ 'console.log("shared");\n', - 'import \'./generated-chunk-dc742c8f.js\';\n\nconsole.log("input1");const out = true;\n\nexport { out };\n', - 'import \'./generated-chunk-dc742c8f.js\';\n\nconsole.log("input2");\n' + `import './generated-chunk-dc742c8f.js';\n\nconsole.log("input1");const out = true;\n\nexport { out };\n`, + `import './generated-chunk-dc742c8f.js';\n\nconsole.log("input2");\n` ], 'code' ); @@ -184,7 +184,7 @@ describe('The bundle object', () => { plugins: [ loader({ input: - 'Promise.all([import("dynamic1"), import("dynamic2")]).then(([{dynamic1}, {dynamic2}]) => console.log(dynamic1, dynamic2));', + `Promise.all([import('dynamic1'), import('dynamic2')]).then(([{dynamic1}, {dynamic2}]) => console.log(dynamic1, dynamic2));`, dynamic1: 'export const dynamic1 = "dynamic1"', dynamic2: 'export const dynamic2 = "dynamic2"' }) @@ -213,7 +213,7 @@ describe('The bundle object', () => { [ 'const dynamic1 = "dynamic1";\n\nexport { dynamic1 };\n', 'const dynamic2 = "dynamic2";\n\nexport { dynamic2 };\n', - 'Promise.all([import("./dynamic1.js"), import("./generated-chunk.js")]).then(([{dynamic1}, {dynamic2}]) => console.log(dynamic1, dynamic2));\n' + `Promise.all([import('./dynamic1.js'), import('./generated-chunk.js')]).then(([{dynamic1}, {dynamic2}]) => console.log(dynamic1, dynamic2));\n` ], 'code' ); @@ -239,7 +239,7 @@ describe('The bundle object', () => { plugins: [ loader({ input: - 'import {other} from "other";console.log(other);Promise.all([import("dynamic1"), import("dynamic2")]).then(([{dynamic1}, {dynamic2}]) => console.log(dynamic1, dynamic2));', + `import {other} from "other";console.log(other);Promise.all([import('dynamic1'), import('dynamic2')]).then(([{dynamic1}, {dynamic2}]) => console.log(dynamic1, dynamic2));`, dynamic1: 'export const dynamic1 = "dynamic1"', dynamic2: 'export const dynamic2 = "dynamic2"', other: 'export const other = "other"' @@ -269,7 +269,9 @@ describe('The bundle object', () => { [ 'const dynamic1 = "dynamic1";\n\nexport { dynamic1 };\n', 'const dynamic2 = "dynamic2";\n\nexport { dynamic2 };\n', - 'import { other } from \'./other\';\n\nconsole.log(other);Promise.all([import("./dynamic1"), import("./dynamic2")]).then(([{dynamic1}, {dynamic2}]) => console.log(dynamic1, dynamic2));\n', + `import { other } from './other'; + +console.log(other);Promise.all([import('./dynamic1'), import('./dynamic2')]).then(([{dynamic1}, {dynamic2}]) => console.log(dynamic1, dynamic2));\n`, 'const other = "other";\n\nexport { other };\n' ], 'code' From 022fd6fbc4efe2fc9d685758f21efe3ae5201b38 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Tue, 27 Nov 2018 08:44:04 +0100 Subject: [PATCH 13/23] Test we provide the right chunk information for dynamic facades --- .../samples/dynamic-import-facade/_config.js | 1 - test/misc/bundle-information.js | 49 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/test/chunking-form/samples/dynamic-import-facade/_config.js b/test/chunking-form/samples/dynamic-import-facade/_config.js index a39a4962dc4..62db88c24ef 100644 --- a/test/chunking-form/samples/dynamic-import-facade/_config.js +++ b/test/chunking-form/samples/dynamic-import-facade/_config.js @@ -4,4 +4,3 @@ module.exports = { input: ['main1.js', 'main2.js'] } }; -// TODO Lukas also test this has the right bundle information diff --git a/test/misc/bundle-information.js b/test/misc/bundle-information.js index a371272af65..51305247e18 100644 --- a/test/misc/bundle-information.js +++ b/test/misc/bundle-information.js @@ -230,6 +230,55 @@ describe('The bundle object', () => { }); }); + it('handles dynamic entry facades as dynamic entries but not the facaded chunk', () => { + return rollup + .rollup({ + input: ['input1', 'input2'], + experimentalCodeSplitting: true, + plugins: [ + loader({ + input1: `import('dynamic').then(({dynamic}) => console.log(dynamic));`, + input2: `import {dep} from 'dep'; import {dynamic} from 'dynamic'; console.log(dep, dynamic);`, + dynamic: `import {dep} from 'dep'; console.log(dep); export const dynamic = 'dynamic';`, + dep: `export const dep = 'dep';` + }) + ] + }) + .then(bundle => + bundle.generate({ + format: 'esm', + dir: 'dist', + entryFileNames: '[name].js', + chunkFileNames: 'generated-[name].js' + }) + ) + .then(({ output }) => { + const sortedOutput = Object.keys(output) + .sort() + .map(key => output[key]); + assert.deepEqual( + sortedOutput.map(chunk => chunk.fileName), + ['generated-chunk.js', 'generated-chunk2.js', 'input1.js', 'input2.js'], + 'fileName' + ); + assert.deepEqual( + sortedOutput.map(chunk => Object.keys(chunk.modules)), + [['dep', 'dynamic'], [], ['input1'], ['input2']], + 'modules' + ); + assert.deepEqual( + sortedOutput.map(chunk => chunk.isDynamicEntry), + [false, true, false, false], + 'isDynamicEntry' + ); + assert.deepEqual( + sortedOutput.map(chunk => chunk.entryModuleId), + [null, 'dynamic', 'input1', 'input2'], + 'entryModuleId' + ); + }); + }); + it('adds correct flags to files when preserving modules', () => { return rollup .rollup({ From 1ae85d506193e7d7312d5b8e946fd8bf7bc4a60e Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Wed, 28 Nov 2018 06:49:03 +0100 Subject: [PATCH 14/23] Move facadeChunk property to modules --- src/Chunk.ts | 11 ++++++----- src/Graph.ts | 2 +- src/Module.ts | 1 + 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Chunk.ts b/src/Chunk.ts index c76e7dcfcb4..227b7a64b53 100644 --- a/src/Chunk.ts +++ b/src/Chunk.ts @@ -132,7 +132,6 @@ export default class Chunk { entryModule: Module = undefined; isEntryModuleFacade: boolean = false; isDynamicEntryFacade: boolean = false; - facadeChunk: Chunk | null = null; isEmpty: boolean; isManualChunk: boolean = false; @@ -205,7 +204,7 @@ export default class Chunk { turnIntoFacade(facadedModule: Module) { this.dependencies = [facadedModule.chunk]; this.entryModule = facadedModule; - facadedModule.chunk.facadeChunk = this; + facadedModule.facadeChunk = this; for (const exportName of facadedModule.getAllExports()) { const tracedVariable = facadedModule.traceExport(exportName); this.exports.set(tracedVariable, facadedModule); @@ -255,8 +254,10 @@ export default class Chunk { } } - // Note preserveModules implementation is not a comprehensive technique - // this will likely need to be reworked at some stage for edge cases + // TODO Lukas: + // * understand taint cases + // * separate in a way that we can work with multiple entry modules in a chunk + // * improve name so that it better matches the internal export generation? populateEntryExports(preserveModules: boolean) { const entryExportEntries = Array.from(this.entryModule.getAllExports().entries()); const tracedExports: { variable: Variable; module: Module | ExternalModule }[] = []; @@ -469,7 +470,7 @@ export default class Chunk { if (!resolution) continue; if (resolution instanceof Module) { - const resolutionChunk = resolution.chunk.facadeChunk || resolution.chunk; + const resolutionChunk = resolution.facadeChunk || resolution.chunk; if (resolutionChunk && resolutionChunk !== this && resolutionChunk.id) { let relPath = normalize(relative(dirname(this.id), resolutionChunk.id)); if (!relPath.startsWith('../')) relPath = './' + relPath; diff --git a/src/Graph.ts b/src/Graph.ts index a099fef6024..36d89e42886 100644 --- a/src/Graph.ts +++ b/src/Graph.ts @@ -479,7 +479,7 @@ export default class Graph { if ( entryModule.isDynamicEntryPoint && !entryModule.chunk.isDynamicEntryFacade && - !entryModule.chunk.facadeChunk + !entryModule.facadeChunk ) { const entryPointFacade = new Chunk(this, [], inlineDynamicImports); entryPointFacade.turnIntoFacade(entryModule); diff --git a/src/Module.ts b/src/Module.ts index a7e47622a7d..80f798a9d35 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -185,6 +185,7 @@ export default class Module { chunk: Chunk; exportAllModules: (Module | ExternalModule)[]; usesTopLevelAwait: boolean = false; + facadeChunk: Chunk | null = null; private ast: Program; private astContext: AstContext; From f7723f399463b874c0ec154ffcaa417acf5f6232 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Wed, 28 Nov 2018 08:50:24 +0100 Subject: [PATCH 15/23] Refactor entry export generation to prepare for multiple entry modules --- src/Chunk.ts | 79 ++++++++++++++++++++++++---------------------------- src/Graph.ts | 2 +- 2 files changed, 38 insertions(+), 43 deletions(-) diff --git a/src/Chunk.ts b/src/Chunk.ts index 227b7a64b53..4403f080ff6 100644 --- a/src/Chunk.ts +++ b/src/Chunk.ts @@ -255,61 +255,56 @@ export default class Chunk { } // TODO Lukas: - // * understand taint cases // * separate in a way that we can work with multiple entry modules in a chunk - // * improve name so that it better matches the internal export generation? - populateEntryExports(preserveModules: boolean) { - const entryExportEntries = Array.from(this.entryModule.getAllExports().entries()); - const tracedExports: { variable: Variable; module: Module | ExternalModule }[] = []; - for (const [index, exportName] of entryExportEntries) { - const traced = this.traceExport(exportName, this.entryModule); - if ( - !traced || - (traced.variable && !traced.variable.included && !traced.variable.isExternal) - ) { - continue; - } - tracedExports[index] = traced; - if (!traced.variable) { - continue; - } - if (traced.module.chunk) { - traced.module.chunk.exports.set(traced.variable, traced.module); - } - const existingExport = this.exportNames[exportName]; - // tainted entryModule boundary - if (existingExport && existingExport !== traced.variable) { - this.isEntryModuleFacade = false; - this.isDynamicEntryFacade = false; - } - } - // tainted if we've already exposed something not corresponding to entry exports + generateEntryExportsOrMarkAsTainted(preserveModules: boolean) { + const tracedEntryExports = this.getExportVariableMapForModule(this.entryModule); for (const exposedVariable of Array.from(this.exports.keys())) { - if (tracedExports.every(({ variable }) => variable !== exposedVariable)) { + if (!tracedEntryExports.has(exposedVariable)) { this.isEntryModuleFacade = false; this.isDynamicEntryFacade = false; return; } } - if (preserveModules || this.isEntryModuleFacade || this.isDynamicEntryFacade) { - for (const [index, exportName] of entryExportEntries) { - const traced = tracedExports[index]; - if (!traced) { - continue; + for (const [variable, { exportNames, module }] of Array.from(tracedEntryExports.entries())) { + for (const exportName of exportNames) { + this.exports.set(variable, module); + this.exportNames[exportName] = variable; } - if (traced.variable) { - if (!traced.variable.included && !traced.variable.isExternal) { - continue; - } - this.exports.set(traced.variable, traced.module); - } - // can be undefined for star external exports (exportName[0] === '*') - this.exportNames[exportName] = traced.variable; } } } + private getExportVariableMapForModule(module: Module) { + const tracedEntryExports: Map< + Variable, + { exportNames: string[]; module: Module | ExternalModule } + > = new Map(); + for (const exportName of module.getAllExports()) { + const tracedExport = this.traceExport(exportName, module); + if ( + !tracedExport || + !tracedExport.variable || + !(tracedExport.variable.included || tracedExport.variable.isExternal) + ) { + continue; + } + const existingExport = tracedEntryExports.get(tracedExport.variable); + if (existingExport) { + existingExport.exportNames.push(exportName); + } else { + tracedEntryExports.set(tracedExport.variable, { + exportNames: [exportName], + module: tracedExport.module + }); + } + if (tracedExport.module.chunk && tracedExport.module.chunk !== this) { + tracedExport.module.chunk.exports.set(tracedExport.variable, tracedExport.module); + } + } + return tracedEntryExports; + } + private traceAndInitializeImport(exportName: string, module: Module | ExternalModule) { const traced = this.traceExport(exportName, module); diff --git a/src/Graph.ts b/src/Graph.ts index 36d89e42886..b9a293bceaa 100644 --- a/src/Graph.ts +++ b/src/Graph.ts @@ -460,7 +460,7 @@ export default class Graph { // then go over and ensure all entry chunks export their variables for (const chunk of chunks) { if (preserveModules || chunk.entryModule) { - chunk.populateEntryExports(preserveModules); + chunk.generateEntryExportsOrMarkAsTainted(preserveModules); } } From c819a4f1cf34cd71c72e7f5c793ae42822c1eac9 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Thu, 29 Nov 2018 07:34:49 +0100 Subject: [PATCH 16/23] Make entryModuleIds a Set on each module --- src/Chunk.ts | 36 ++++++++++++++++++-------------- src/Graph.ts | 4 ++-- src/rollup/index.ts | 25 ++++++++++++++-------- src/rollup/types.d.ts | 2 +- test/misc/bundle-information.js | 37 +++++++++++++++++---------------- 5 files changed, 58 insertions(+), 46 deletions(-) diff --git a/src/Chunk.ts b/src/Chunk.ts index 4403f080ff6..29cd34f9c42 100644 --- a/src/Chunk.ts +++ b/src/Chunk.ts @@ -129,7 +129,7 @@ export default class Chunk { private dependencies: (ExternalModule | Chunk)[] = undefined; // an entry module chunk is a chunk that exactly exports the exports of // an input entry point module - entryModule: Module = undefined; + entryModules: Set = new Set(); isEntryModuleFacade: boolean = false; isDynamicEntryFacade: boolean = false; isEmpty: boolean; @@ -160,25 +160,22 @@ export default class Chunk { this.isManualChunk = true; } module.chunk = this; - if (module.isEntryPoint && !this.entryModule) { - this.entryModule = module; + if (module.isEntryPoint) { + this.entryModules.add(module); this.isEntryModuleFacade = true; } if (module.isDynamicEntryPoint && !inlineDynamicImports) { + this.entryModules.add(module); this.isDynamicEntryFacade = true; - if (!this.entryModule) { - this.entryModule = module; - } } } - if (this.entryModule) + if (this.entryModules.size > 0) { + const entryModules = Array.from(this.entryModules); this.variableName = makeLegal( - basename( - this.entryModule.chunkAlias || this.orderedModules[0].chunkAlias || this.entryModule.id - ) + basename(entryModules.map(module => module.chunkAlias).find(Boolean) || entryModules[0].id) ); - else this.variableName = '__chunk_' + ++graph.curChunkIndex; + } else this.variableName = '__chunk_' + ++graph.curChunkIndex; } getImportIds(): string[] { @@ -203,7 +200,7 @@ export default class Chunk { turnIntoFacade(facadedModule: Module) { this.dependencies = [facadedModule.chunk]; - this.entryModule = facadedModule; + this.entryModules.add(facadedModule); facadedModule.facadeChunk = this; for (const exportName of facadedModule.getAllExports()) { const tracedVariable = facadedModule.traceExport(exportName); @@ -256,8 +253,10 @@ export default class Chunk { // TODO Lukas: // * separate in a way that we can work with multiple entry modules in a chunk + // * maybe each chunk has a Set of facaded modules. The type is determined by looking into the module + // TODO Lukas: fail if a name is used more than once generateEntryExportsOrMarkAsTainted(preserveModules: boolean) { - const tracedEntryExports = this.getExportVariableMapForModule(this.entryModule); + const tracedEntryExports = this.getExportVariableMapForModule(Array.from(this.entryModules)[0]); for (const exposedVariable of Array.from(this.exports.keys())) { if (!tracedEntryExports.has(exposedVariable)) { this.isEntryModuleFacade = false; @@ -357,6 +356,7 @@ export default class Chunk { // we follow reexports if they are not entry points in the hope // that we can get an entry point reexport to reduce the chance of // tainting an entryModule chunk by exposing other unnecessary exports + // TODO Lukas this should also stop for dynamic entries, test this if (module.isEntryPoint && !module.chunk.isEmpty) return { variable: module.traceExport(name), module }; return module.chunk.traceExport(name, module); @@ -1020,10 +1020,10 @@ export default class Chunk { preserveModulesRelativeDir: string, existingNames: Record ) { - const sanitizedId = this.entryModule.id.replace('\0', '_'); + const sanitizedId = this.orderedModules[0].id.replace('\0', '_'); this.id = makeUnique( normalize( - isAbsolute(this.entryModule.id) + isAbsolute(this.orderedModules[0].id) ? relative(preserveModulesRelativeDir, sanitizedId) : '_virtual/' + basename(sanitizedId) ), @@ -1058,7 +1058,11 @@ export default class Chunk { } private computeChunkName(): string { - if (this.entryModule && this.entryModule.chunkAlias) return this.entryModule.chunkAlias; + if (this.entryModules.size > 0) { + for (const entryModule of Array.from(this.entryModules)) { + if (entryModule.chunkAlias) return entryModule.chunkAlias; + } + } for (const module of this.orderedModules) { if (module.chunkAlias) return module.chunkAlias; } diff --git a/src/Graph.ts b/src/Graph.ts index b9a293bceaa..8f0e4ed4058 100644 --- a/src/Graph.ts +++ b/src/Graph.ts @@ -419,7 +419,7 @@ export default class Graph { if (preserveModules) { for (const module of orderedModules) { const chunk = new Chunk(this, [module], inlineDynamicImports); - if (module.isEntryPoint || !chunk.isEmpty) chunk.entryModule = module; + if (module.isEntryPoint || !chunk.isEmpty) chunk.entryModules.add(module); chunks.push(chunk); } } else { @@ -459,7 +459,7 @@ export default class Graph { // then go over and ensure all entry chunks export their variables for (const chunk of chunks) { - if (preserveModules || chunk.entryModule) { + if (preserveModules || chunk.entryModules.size > 0) { chunk.generateEntryExportsOrMarkAsTainted(preserveModules); } } diff --git a/src/rollup/index.ts b/src/rollup/index.ts index b67cbc62498..52219d7c26d 100644 --- a/src/rollup/index.ts +++ b/src/rollup/index.ts @@ -65,6 +65,18 @@ function checkOutputOptions(options: OutputOptions) { } } +function getAbsoluteEntryModulePaths(chunks: Chunk[]): string[] { + const absoluteEntryModulePaths: string[] = []; + for (const chunk of chunks) { + for (const entryModule of Array.from(chunk.entryModules)) { + if (isAbsolute(entryModule.id)) { + absoluteEntryModulePaths.push(entryModule.id); + } + } + } + return absoluteEntryModulePaths; +} + const throwAsyncGenerateError = { get() { throw new Error(`bundle.generate(...) now returns a Promise instead of a { code, map } object`); @@ -258,14 +270,9 @@ export default function rollup( timeStart('GENERATE', 1); - // populate asset files into output const assetFileNames = outputOptions.assetFileNames || 'assets/[name]-[hash][extname]'; const outputBundle: OutputBundle = graph.finaliseAssets(assetFileNames); - const inputBase = commondir( - chunks - .filter(chunk => chunk.entryModule && isAbsolute(chunk.entryModule.id)) - .map(chunk => chunk.entryModule.id) - ); + const inputBase = commondir(getAbsoluteEntryModulePaths(chunks)); return graph.pluginDriver .hookParallel('renderStart') @@ -294,10 +301,10 @@ export default function rollup( outputBundle[chunk.id] = { code: undefined, - entryModuleId: + entryModuleIds: chunk.isEntryModuleFacade || chunk.isDynamicEntryFacade - ? chunk.entryModule.id - : null, + ? Array.from(chunk.entryModules).map(module => module.id) + : [], exports: chunk.getExportNames(), fileName: chunk.id, imports: chunk.getImportIds(), diff --git a/src/rollup/types.d.ts b/src/rollup/types.d.ts index c63d62e2376..519d582f298 100644 --- a/src/rollup/types.d.ts +++ b/src/rollup/types.d.ts @@ -363,7 +363,7 @@ export interface RenderedModule { } export interface RenderedChunk { - entryModuleId: string | null; + entryModuleIds: string[]; exports: string[]; fileName: string; imports: string[]; diff --git a/test/misc/bundle-information.js b/test/misc/bundle-information.js index 51305247e18..07322a52c93 100644 --- a/test/misc/bundle-information.js +++ b/test/misc/bundle-information.js @@ -2,6 +2,7 @@ const assert = require('assert'); const rollup = require('../../dist/rollup'); const { loader } = require('../utils.js'); +// TODO Lukas test multiple entry module ids describe('The bundle object', () => { it('contains information about the generated chunks', () => { return rollup @@ -50,9 +51,9 @@ describe('The bundle object', () => { 'name' ); assert.deepEqual( - sortedOutput.map(chunk => chunk.entryModuleId), - [null, 'input1', 'input2'], - 'entryModuleId' + sortedOutput.map(chunk => chunk.entryModuleIds), + [[], ['input1'], ['input2']], + 'entryModuleIds' ); assert.deepEqual( sortedOutput.map(chunk => chunk.imports), @@ -130,9 +131,9 @@ describe('The bundle object', () => { ); assert.deepEqual(sortedOutput.map(chunk => chunk.isEntry), [false, true, true], 'isEntry'); assert.deepEqual( - sortedOutput.map(chunk => chunk.entryModuleId), - [null, 'input1', 'input2'], - 'entryModuleId' + sortedOutput.map(chunk => chunk.entryModuleIds), + [[], ['input1'], ['input2']], + 'entryModuleIds' ); }); }); @@ -169,9 +170,9 @@ describe('The bundle object', () => { 'fileName' ); assert.deepEqual( - sortedOutput.map(chunk => chunk.entryModuleId), - ['input1', 'input2', null], - 'entryModuleId' + sortedOutput.map(chunk => chunk.entryModuleIds), + [['input1'], ['input2'], []], + 'entryModuleIds' ); }); }); @@ -223,9 +224,9 @@ describe('The bundle object', () => { 'isDynamicEntry' ); assert.deepEqual( - sortedOutput.map(chunk => chunk.entryModuleId), - ['dynamic1', 'dynamic2', 'input'], - 'entryModuleId' + sortedOutput.map(chunk => chunk.entryModuleIds), + [['dynamic1'], ['dynamic2'], ['input']], + 'entryModuleIds' ); }); }); @@ -272,9 +273,9 @@ describe('The bundle object', () => { 'isDynamicEntry' ); assert.deepEqual( - sortedOutput.map(chunk => chunk.entryModuleId), - [null, 'dynamic', 'input1', 'input2'], - 'entryModuleId' + sortedOutput.map(chunk => chunk.entryModuleIds), + [[], ['dynamic'], ['input1'], ['input2']], + 'entryModuleIds' ); }); }); @@ -380,9 +381,9 @@ console.log(other);Promise.all([import('./dynamic1'), import('./dynamic2')]).the 'isDynamicEntry' ); assert.deepEqual( - sortedOutput.map(chunk => chunk.entryModuleId), - ['dynamic1', 'dynamic2', 'input', null], - 'entryModuleId' + sortedOutput.map(chunk => chunk.entryModuleIds), + [['dynamic1'], ['dynamic2'], ['input'], []], + 'entryModuleIds' ); }); }); From 7956bc7c8f7221aa569dccb556070d2961bde40c Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Fri, 30 Nov 2018 06:32:59 +0100 Subject: [PATCH 17/23] Support manual chunks with multiple facades --- src/Chunk.ts | 50 +++++++++++-------- src/Graph.ts | 14 ++---- src/chunk-optimization.ts | 4 +- src/rollup/index.ts | 13 +++-- src/utils/assignChunkIds.ts | 7 ++- src/utils/chunkColouring.ts | 19 ++----- src/utils/getExportMode.ts | 6 ++- .../manual-chunks-dynamic-facades/_config.js | 12 +++++ .../_expected/amd/generated-dynamic.js | 16 ++++++ .../_expected/amd/generated-dynamic2.js | 7 +++ .../_expected/amd/generated-dynamic3.js | 7 +++ .../_expected/amd/main.js | 7 +++ .../_expected/cjs/generated-dynamic.js | 14 ++++++ .../_expected/cjs/generated-dynamic2.js | 7 +++ .../_expected/cjs/generated-dynamic3.js | 7 +++ .../_expected/cjs/main.js | 7 +++ .../_expected/es/generated-dynamic.js | 9 ++++ .../_expected/es/generated-dynamic2.js | 1 + .../_expected/es/generated-dynamic3.js | 1 + .../_expected/es/main.js | 5 ++ .../_expected/system/generated-dynamic.js | 16 ++++++ .../_expected/system/generated-dynamic2.js | 13 +++++ .../_expected/system/generated-dynamic3.js | 13 +++++ .../_expected/system/main.js | 16 ++++++ .../manual-chunks-dynamic-facades/dep.js | 1 + .../manual-chunks-dynamic-facades/dynamic1.js | 4 ++ .../manual-chunks-dynamic-facades/dynamic2.js | 1 + .../manual-chunks-dynamic-facades/dynamic3.js | 1 + .../manual-chunks-dynamic-facades/main.js | 5 ++ .../samples/manual-chunks-dynamic/_config.js | 1 - .../_expected/amd/main.js | 2 +- .../_expected/cjs/main.js | 2 +- .../_expected/es/main.js | 2 +- .../_expected/system/main.js | 2 +- test/misc/bundle-information.js | 2 +- 35 files changed, 230 insertions(+), 64 deletions(-) create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-facades/_config.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/amd/generated-dynamic.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/amd/generated-dynamic2.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/amd/generated-dynamic3.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/amd/main.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/cjs/generated-dynamic.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/cjs/generated-dynamic2.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/cjs/generated-dynamic3.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/cjs/main.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/es/generated-dynamic.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/es/generated-dynamic2.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/es/generated-dynamic3.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/es/main.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/system/generated-dynamic.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/system/generated-dynamic2.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/system/generated-dynamic3.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/system/main.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-facades/dep.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-facades/dynamic1.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-facades/dynamic2.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-facades/dynamic3.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-facades/main.js diff --git a/src/Chunk.ts b/src/Chunk.ts index 29cd34f9c42..9c7b0337cd6 100644 --- a/src/Chunk.ts +++ b/src/Chunk.ts @@ -130,8 +130,6 @@ export default class Chunk { // an entry module chunk is a chunk that exactly exports the exports of // an input entry point module entryModules: Set = new Set(); - isEntryModuleFacade: boolean = false; - isDynamicEntryFacade: boolean = false; isEmpty: boolean; isManualChunk: boolean = false; @@ -160,13 +158,8 @@ export default class Chunk { this.isManualChunk = true; } module.chunk = this; - if (module.isEntryPoint) { + if (module.isEntryPoint || (module.isDynamicEntryPoint && !inlineDynamicImports)) { this.entryModules.add(module); - this.isEntryModuleFacade = true; - } - if (module.isDynamicEntryPoint && !inlineDynamicImports) { - this.entryModules.add(module); - this.isDynamicEntryFacade = true; } } @@ -252,20 +245,33 @@ export default class Chunk { } // TODO Lukas: - // * separate in a way that we can work with multiple entry modules in a chunk // * maybe each chunk has a Set of facaded modules. The type is determined by looking into the module // TODO Lukas: fail if a name is used more than once - generateEntryExportsOrMarkAsTainted(preserveModules: boolean) { - const tracedEntryExports = this.getExportVariableMapForModule(Array.from(this.entryModules)[0]); - for (const exposedVariable of Array.from(this.exports.keys())) { - if (!tracedEntryExports.has(exposedVariable)) { - this.isEntryModuleFacade = false; - this.isDynamicEntryFacade = false; - return; + // TODO Lukas can this be simplified to directly set the exports? + // TODO Lukas dynamic imports -> always named export mode! + // TODO Lukas multiple entry points -> always generate facade for more than one + generateEntryExportsOrMarkAsTainted() { + const exportVariableMaps = Array.from(this.entryModules).map(module => ({ + module, + map: this.getExportVariableMapForModule(module) + })); + const exposedVariables: Set = new Set(); + for (const { map } of exportVariableMaps) { + for (const exposedVariable of Array.from(map.keys())) { + exposedVariables.add(exposedVariable); } } - if (preserveModules || this.isEntryModuleFacade || this.isDynamicEntryFacade) { - for (const [variable, { exportNames, module }] of Array.from(tracedEntryExports.entries())) { + for (const exposedVariable of Array.from(this.exports.keys())) { + exposedVariables.add(exposedVariable); + } + checkNextEntryModule: for (const { map, module } of exportVariableMaps) { + for (const exposedVariable of Array.from(exposedVariables)) { + if (!map.has(exposedVariable)) { + this.entryModules.delete(module); + continue checkNextEntryModule; + } + } + for (const [variable, { exportNames, module }] of Array.from(map.entries())) { for (const exportName of exportNames) { this.exports.set(variable, module); this.exportNames[exportName] = variable; @@ -398,7 +404,7 @@ export default class Chunk { } generateInternalExports(options: OutputOptions) { - if (this.isEntryModuleFacade || this.isDynamicEntryFacade) return; + if (this.entryModules.size > 0) return; const mangle = options.format === 'system' || options.format === 'es' || options.compact; let i = 0, safeExportName: string; @@ -815,7 +821,7 @@ export default class Chunk { }; // if an entry point facade or dynamic entry point, inline the execution list to avoid loading latency - if (this.isEntryModuleFacade || this.isDynamicEntryFacade) { + if (this.entryModules.size > 0) { for (const dep of this.dependencies) { if (dep instanceof Chunk) this.inlineChunkDependencies(dep, true); } @@ -916,7 +922,7 @@ export default class Chunk { * A new facade will be added to chunkList if tainting exports of either as an entry point */ merge(chunk: Chunk, chunkList: Chunk[], options: OutputOptions, inputBase: string) { - if (this.isEntryModuleFacade || chunk.isEntryModuleFacade) + if (this.entryModules.size > 0 || chunk.entryModules.size > 0) throw new Error('Internal error: Code splitting chunk merges not supported for facades'); for (const module of chunk.orderedModules) { @@ -1133,7 +1139,7 @@ export default class Chunk { dependencies: this.renderedDeclarations.dependencies, exports: this.renderedDeclarations.exports, graph: this.graph, - isEntryModuleFacade: this.isEntryModuleFacade, + isEntryModuleFacade: !!Array.from(this.entryModules).find(module => module.isEntryPoint), usesTopLevelAwait }, options diff --git a/src/Graph.ts b/src/Graph.ts index 8f0e4ed4058..58f42f36040 100644 --- a/src/Graph.ts +++ b/src/Graph.ts @@ -450,27 +450,22 @@ export default class Graph { // filter out empty dependencies chunks = chunks.filter( - chunk => - !chunk.isEmpty || - chunk.isEntryModuleFacade || - chunk.isDynamicEntryFacade || - chunk.isManualChunk + chunk => !chunk.isEmpty || chunk.entryModules.size > 0 || chunk.isManualChunk ); // then go over and ensure all entry chunks export their variables for (const chunk of chunks) { if (preserveModules || chunk.entryModules.size > 0) { - chunk.generateEntryExportsOrMarkAsTainted(preserveModules); + chunk.generateEntryExportsOrMarkAsTainted(); } } // create entry point facades for entry module chunks that have tainted exports if (!preserveModules) { for (const entryModule of entryModules) { - if (!entryModule.chunk.isEntryModuleFacade) { + if (!entryModule.chunk.entryModules.has(entryModule)) { const entryPointFacade = new Chunk(this, [], inlineDynamicImports); entryPointFacade.turnIntoFacade(entryModule); - entryPointFacade.isEntryModuleFacade = true; chunks.push(entryPointFacade); } } @@ -478,12 +473,11 @@ export default class Graph { for (const entryModule of dynamicImports) { if ( entryModule.isDynamicEntryPoint && - !entryModule.chunk.isDynamicEntryFacade && + !entryModule.chunk.entryModules.has(entryModule) && !entryModule.facadeChunk ) { const entryPointFacade = new Chunk(this, [], inlineDynamicImports); entryPointFacade.turnIntoFacade(entryModule); - entryPointFacade.isDynamicEntryFacade = true; chunks.push(entryPointFacade); } } diff --git a/src/chunk-optimization.ts b/src/chunk-optimization.ts index 90274a3ffda..68debb60722 100644 --- a/src/chunk-optimization.ts +++ b/src/chunk-optimization.ts @@ -36,10 +36,10 @@ export function optimizeChunks( nextChunk = execGroup[1]; const isMergeCandidate = (chunk: Chunk) => { - if (chunk.isEntryModuleFacade || chunk.isManualChunk) { + if (chunk.entryModules.size > 0 || chunk.isManualChunk) { return false; } - if (!nextChunk || nextChunk.isEntryModuleFacade) { + if (!nextChunk || nextChunk.entryModules.size > 0) { return false; } if (chunk.getRenderedSourceLength() > CHUNK_GROUPING_SIZE) { diff --git a/src/rollup/index.ts b/src/rollup/index.ts index 52219d7c26d..c831e79c547 100644 --- a/src/rollup/index.ts +++ b/src/rollup/index.ts @@ -282,7 +282,7 @@ export default function rollup( for (const chunk of chunks) { if (!inputOptions.experimentalPreserveModules) chunk.generateInternalExports(outputOptions); - if (chunk.isEntryModuleFacade) + if (Array.from(chunk.entryModules).find(module => module.isEntryPoint)) chunk.exportMode = getExportMode(chunk, outputOptions); } for (const chunk of chunks) { @@ -301,15 +301,14 @@ export default function rollup( outputBundle[chunk.id] = { code: undefined, - entryModuleIds: - chunk.isEntryModuleFacade || chunk.isDynamicEntryFacade - ? Array.from(chunk.entryModules).map(module => module.id) - : [], + entryModuleIds: Array.from(chunk.entryModules).map(module => module.id), exports: chunk.getExportNames(), fileName: chunk.id, imports: chunk.getImportIds(), - isDynamicEntry: chunk.isDynamicEntryFacade, - isEntry: chunk.isEntryModuleFacade, + isDynamicEntry: !!Array.from(chunk.entryModules).find( + module => module.isDynamicEntryPoint + ), + isEntry: !!Array.from(chunk.entryModules).find(module => module.isEntryPoint), map: undefined, modules: chunk.renderedModules, get name() { diff --git a/src/utils/assignChunkIds.ts b/src/utils/assignChunkIds.ts index bf0f2dd7d0b..75b6c592fa1 100644 --- a/src/utils/assignChunkIds.ts +++ b/src/utils/assignChunkIds.ts @@ -14,7 +14,10 @@ export function assignChunkIds( const usedIds: Record = {}; const [entryChunks, otherChunks] = chunks.reduce( ([entryChunks, otherChunks], chunk) => { - (chunk.isEntryModuleFacade ? entryChunks : otherChunks).push(chunk); + (Array.from(chunk.entryModules).find(module => module.isEntryPoint) + ? entryChunks + : otherChunks + ).push(chunk); return [entryChunks, otherChunks]; }, [[], []] @@ -34,7 +37,7 @@ export function assignChunkIds( chunk.generateIdPreserveModules(inputBase, usedIds); } else { let pattern, patternName; - if (chunk.isEntryModuleFacade) { + if (Array.from(chunk.entryModules).find(module => module.isEntryPoint)) { pattern = outputOptions.entryFileNames || '[name].js'; patternName = 'output.entryFileNames'; } else { diff --git a/src/utils/chunkColouring.ts b/src/utils/chunkColouring.ts index 2abd8658de9..5a0918e9b15 100644 --- a/src/utils/chunkColouring.ts +++ b/src/utils/chunkColouring.ts @@ -11,7 +11,7 @@ export function assignChunkColouringHashes( let currentEntry: Module, currentEntryHash: Uint8Array; let modulesVisitedForCurrentEntry: { [id: string]: boolean }; const handledEntryPoints: { [id: string]: boolean } = {}; - const dynamicImports: Module[] = []; + const dynamicImports: Set = new Set(); const addCurrentEntryColourToModule = (module: Module) => { if (currentEntry.chunkAlias) { @@ -33,19 +33,10 @@ export function assignChunkColouringHashes( for (const dynamicModule of module.dynamicImportResolutions) { if ( dynamicModule.resolution instanceof Module && - dynamicModule.resolution.isDynamicEntryPoint + dynamicModule.resolution.isDynamicEntryPoint && + !dynamicModule.resolution.chunkAlias ) { - if (dynamicModule.resolution.chunkAlias) { - // We only assign separate colouring to a dynamic entry if it is not already - // part of the graph of a manual chunk - // TODO Lukas test this - dynamicModule.resolution.isDynamicEntryPoint = false; - } else { - dynamicModule.resolution.isDynamicEntryPoint = true; - if (dynamicImports.indexOf(dynamicModule.resolution) === -1) { - dynamicImports.push(dynamicModule.resolution); - } - } + dynamicImports.add(dynamicModule.resolution); } } }; @@ -81,7 +72,7 @@ Try defining "${chunkName}" first in the manualChunks definitions of the Rollup addCurrentEntryColourToModule(currentEntry); } - for (currentEntry of dynamicImports) { + for (currentEntry of Array.from(dynamicImports)) { if (handledEntryPoints[currentEntry.id]) { continue; } diff --git a/src/utils/getExportMode.ts b/src/utils/getExportMode.ts index 3c63cba6d59..34d8dad23dc 100644 --- a/src/utils/getExportMode.ts +++ b/src/utils/getExportMode.ts @@ -31,7 +31,11 @@ export default function getExportMode( } else if (exportKeys.length === 1 && exportKeys[0] === 'default') { exportMode = 'default'; } else { - if (chunk.isEntryModuleFacade && format !== 'es' && exportKeys.indexOf('default') !== -1) { + if ( + Array.from(chunk.entryModules).find(module => module.isEntryPoint) && + format !== 'es' && + exportKeys.indexOf('default') !== -1 + ) { chunk.graph.warn({ code: 'MIXED_EXPORTS', message: `Using named and default exports together. Consumers of your bundle will have to use ${name || diff --git a/test/chunking-form/samples/manual-chunks-dynamic-facades/_config.js b/test/chunking-form/samples/manual-chunks-dynamic-facades/_config.js new file mode 100644 index 00000000000..3605f593949 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-facades/_config.js @@ -0,0 +1,12 @@ +module.exports = { + description: 'creates facades for dynamic manual chunks if necessary', + options: { + input: ['main.js'], + manualChunks: { + dynamic: ['dynamic1.js'] + }, + output: { + chunkFileNames: 'generated-[name].js' + } + } +}; diff --git a/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/amd/generated-dynamic.js b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/amd/generated-dynamic.js new file mode 100644 index 00000000000..467e384286b --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/amd/generated-dynamic.js @@ -0,0 +1,16 @@ +define(['exports'], function (exports) { 'use strict'; + + const DEP = 'DEP'; + + const DYNAMIC_2 = 'DYNAMIC_2'; + + const DYNAMIC_3 = 'DYNAMIC_3'; + + const DYNAMIC_1 = 'DYNAMIC_1'; + + exports.DYNAMIC_1 = DYNAMIC_1; + exports.DEP = DEP; + exports.DYNAMIC_2 = DYNAMIC_2; + exports.DYNAMIC_3 = DYNAMIC_3; + +}); diff --git a/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/amd/generated-dynamic2.js b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/amd/generated-dynamic2.js new file mode 100644 index 00000000000..d61d9fe71fc --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/amd/generated-dynamic2.js @@ -0,0 +1,7 @@ +define(['exports', './generated-dynamic.js'], function (exports, dynamic) { 'use strict'; + + + + exports.DYNAMIC_2 = dynamic.DYNAMIC_2; + +}); diff --git a/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/amd/generated-dynamic3.js b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/amd/generated-dynamic3.js new file mode 100644 index 00000000000..d8b85da29fc --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/amd/generated-dynamic3.js @@ -0,0 +1,7 @@ +define(['exports', './generated-dynamic.js'], function (exports, dynamic) { 'use strict'; + + + + exports.DYNAMIC_3 = dynamic.DYNAMIC_3; + +}); diff --git a/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/amd/main.js b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/amd/main.js new file mode 100644 index 00000000000..3c9d3dbf487 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/amd/main.js @@ -0,0 +1,7 @@ +define(['require', './generated-dynamic.js'], function (require, dynamic) { 'use strict'; + + Promise.all([new Promise(function (resolve, reject) { require(['./generated-dynamic.js'], resolve, reject) }), new Promise(function (resolve, reject) { require(['./generated-dynamic2.js'], resolve, reject) }), new Promise(function (resolve, reject) { require(['./generated-dynamic3.js'], resolve, reject) })]).then( + results => console.log(results, dynamic.DEP) + ); + +}); diff --git a/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/cjs/generated-dynamic.js b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/cjs/generated-dynamic.js new file mode 100644 index 00000000000..fe62d18446f --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/cjs/generated-dynamic.js @@ -0,0 +1,14 @@ +'use strict'; + +const DEP = 'DEP'; + +const DYNAMIC_2 = 'DYNAMIC_2'; + +const DYNAMIC_3 = 'DYNAMIC_3'; + +const DYNAMIC_1 = 'DYNAMIC_1'; + +exports.DYNAMIC_1 = DYNAMIC_1; +exports.DEP = DEP; +exports.DYNAMIC_2 = DYNAMIC_2; +exports.DYNAMIC_3 = DYNAMIC_3; diff --git a/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/cjs/generated-dynamic2.js b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/cjs/generated-dynamic2.js new file mode 100644 index 00000000000..cf43f7fbe57 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/cjs/generated-dynamic2.js @@ -0,0 +1,7 @@ +'use strict'; + +var dynamic = require('./generated-dynamic.js'); + + + +exports.DYNAMIC_2 = dynamic.DYNAMIC_2; diff --git a/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/cjs/generated-dynamic3.js b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/cjs/generated-dynamic3.js new file mode 100644 index 00000000000..4ed30dd39c3 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/cjs/generated-dynamic3.js @@ -0,0 +1,7 @@ +'use strict'; + +var dynamic = require('./generated-dynamic.js'); + + + +exports.DYNAMIC_3 = dynamic.DYNAMIC_3; diff --git a/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/cjs/main.js b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/cjs/main.js new file mode 100644 index 00000000000..529ca20e209 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/cjs/main.js @@ -0,0 +1,7 @@ +'use strict'; + +var dynamic = require('./generated-dynamic.js'); + +Promise.all([Promise.resolve(require('./generated-dynamic.js')), Promise.resolve(require('./generated-dynamic2.js')), Promise.resolve(require('./generated-dynamic3.js'))]).then( + results => console.log(results, dynamic.DEP) +); diff --git a/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/es/generated-dynamic.js b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/es/generated-dynamic.js new file mode 100644 index 00000000000..36b7ea16ba7 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/es/generated-dynamic.js @@ -0,0 +1,9 @@ +const DEP = 'DEP'; + +const DYNAMIC_2 = 'DYNAMIC_2'; + +const DYNAMIC_3 = 'DYNAMIC_3'; + +const DYNAMIC_1 = 'DYNAMIC_1'; + +export { DYNAMIC_1, DEP, DYNAMIC_2, DYNAMIC_3 }; diff --git a/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/es/generated-dynamic2.js b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/es/generated-dynamic2.js new file mode 100644 index 00000000000..73f483cb3eb --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/es/generated-dynamic2.js @@ -0,0 +1 @@ +export { DYNAMIC_2 } from './generated-dynamic.js'; diff --git a/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/es/generated-dynamic3.js b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/es/generated-dynamic3.js new file mode 100644 index 00000000000..44dcc838b09 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/es/generated-dynamic3.js @@ -0,0 +1 @@ +export { DYNAMIC_3 } from './generated-dynamic.js'; diff --git a/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/es/main.js b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/es/main.js new file mode 100644 index 00000000000..4ed1bade3c1 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/es/main.js @@ -0,0 +1,5 @@ +import { DEP } from './generated-dynamic.js'; + +Promise.all([import('./generated-dynamic.js'), import('./generated-dynamic2.js'), import('./generated-dynamic3.js')]).then( + results => console.log(results, DEP) +); diff --git a/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/system/generated-dynamic.js b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/system/generated-dynamic.js new file mode 100644 index 00000000000..297f23add80 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/system/generated-dynamic.js @@ -0,0 +1,16 @@ +System.register([], function (exports, module) { + 'use strict'; + return { + execute: function () { + + const DEP = exports('DEP', 'DEP'); + + const DYNAMIC_2 = exports('DYNAMIC_2', 'DYNAMIC_2'); + + const DYNAMIC_3 = exports('DYNAMIC_3', 'DYNAMIC_3'); + + const DYNAMIC_1 = exports('DYNAMIC_1', 'DYNAMIC_1'); + + } + }; +}); diff --git a/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/system/generated-dynamic2.js b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/system/generated-dynamic2.js new file mode 100644 index 00000000000..3ea6944246f --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/system/generated-dynamic2.js @@ -0,0 +1,13 @@ +System.register(['./generated-dynamic.js'], function (exports, module) { + 'use strict'; + return { + setters: [function (module) { + exports('DYNAMIC_2', module.DYNAMIC_2); + }], + execute: function () { + + + + } + }; +}); diff --git a/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/system/generated-dynamic3.js b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/system/generated-dynamic3.js new file mode 100644 index 00000000000..9cd1dbdf3ed --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/system/generated-dynamic3.js @@ -0,0 +1,13 @@ +System.register(['./generated-dynamic.js'], function (exports, module) { + 'use strict'; + return { + setters: [function (module) { + exports('DYNAMIC_3', module.DYNAMIC_3); + }], + execute: function () { + + + + } + }; +}); diff --git a/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/system/main.js b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/system/main.js new file mode 100644 index 00000000000..3b527719e90 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-facades/_expected/system/main.js @@ -0,0 +1,16 @@ +System.register(['./generated-dynamic.js'], function (exports, module) { + 'use strict'; + var DEP; + return { + setters: [function (module) { + DEP = module.DEP; + }], + execute: function () { + + Promise.all([module.import('./generated-dynamic.js'), module.import('./generated-dynamic2.js'), module.import('./generated-dynamic3.js')]).then( + results => console.log(results, DEP) + ); + + } + }; +}); diff --git a/test/chunking-form/samples/manual-chunks-dynamic-facades/dep.js b/test/chunking-form/samples/manual-chunks-dynamic-facades/dep.js new file mode 100644 index 00000000000..4be514fd761 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-facades/dep.js @@ -0,0 +1 @@ +export const DEP = 'DEP'; diff --git a/test/chunking-form/samples/manual-chunks-dynamic-facades/dynamic1.js b/test/chunking-form/samples/manual-chunks-dynamic-facades/dynamic1.js new file mode 100644 index 00000000000..1591826eaf0 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-facades/dynamic1.js @@ -0,0 +1,4 @@ +export * from './dep.js'; +export * from './dynamic2.js'; +export * from './dynamic3.js'; +export const DYNAMIC_1 = 'DYNAMIC_1'; diff --git a/test/chunking-form/samples/manual-chunks-dynamic-facades/dynamic2.js b/test/chunking-form/samples/manual-chunks-dynamic-facades/dynamic2.js new file mode 100644 index 00000000000..11eeeb42896 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-facades/dynamic2.js @@ -0,0 +1 @@ +export const DYNAMIC_2 = 'DYNAMIC_2'; diff --git a/test/chunking-form/samples/manual-chunks-dynamic-facades/dynamic3.js b/test/chunking-form/samples/manual-chunks-dynamic-facades/dynamic3.js new file mode 100644 index 00000000000..439fa36aab0 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-facades/dynamic3.js @@ -0,0 +1 @@ +export const DYNAMIC_3 = 'DYNAMIC_3'; diff --git a/test/chunking-form/samples/manual-chunks-dynamic-facades/main.js b/test/chunking-form/samples/manual-chunks-dynamic-facades/main.js new file mode 100644 index 00000000000..317e03b17c5 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-facades/main.js @@ -0,0 +1,5 @@ +import { DEP } from './dep'; + +Promise.all([import('./dynamic1.js'), import('./dynamic2.js'), import('./dynamic3.js')]).then( + results => console.log(results, DEP) +); diff --git a/test/chunking-form/samples/manual-chunks-dynamic/_config.js b/test/chunking-form/samples/manual-chunks-dynamic/_config.js index 14709021bd9..1a50241e392 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic/_config.js +++ b/test/chunking-form/samples/manual-chunks-dynamic/_config.js @@ -1,6 +1,5 @@ module.exports = { description: 'supports dynamic manual chunks', - skip: true, options: { input: ['main.js'], manualChunks: { diff --git a/test/chunking-form/samples/manual-chunks-dynamic/_expected/amd/main.js b/test/chunking-form/samples/manual-chunks-dynamic/_expected/amd/main.js index f8d3226c002..bf87287061c 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic/_expected/amd/main.js +++ b/test/chunking-form/samples/manual-chunks-dynamic/_expected/amd/main.js @@ -1,5 +1,5 @@ define(['require'], function (require) { 'use strict'; - new Promise(function (resolve, reject) { require(["./generated-dynamic.js"], resolve, reject) }).then(({DYNAMIC_USED_BY_A}) => console.log(DYNAMIC_USED_BY_A)); + new Promise(function (resolve, reject) { require(['./generated-dynamic.js'], resolve, reject) }).then(({DYNAMIC_USED_BY_A}) => console.log(DYNAMIC_USED_BY_A)); }); diff --git a/test/chunking-form/samples/manual-chunks-dynamic/_expected/cjs/main.js b/test/chunking-form/samples/manual-chunks-dynamic/_expected/cjs/main.js index 8c663eaa935..6dec24c5ece 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic/_expected/cjs/main.js +++ b/test/chunking-form/samples/manual-chunks-dynamic/_expected/cjs/main.js @@ -1,3 +1,3 @@ 'use strict'; -Promise.resolve(require("./generated-dynamic.js")).then(({DYNAMIC_USED_BY_A}) => console.log(DYNAMIC_USED_BY_A)); +Promise.resolve(require('./generated-dynamic.js')).then(({DYNAMIC_USED_BY_A}) => console.log(DYNAMIC_USED_BY_A)); diff --git a/test/chunking-form/samples/manual-chunks-dynamic/_expected/es/main.js b/test/chunking-form/samples/manual-chunks-dynamic/_expected/es/main.js index 346c6c18fb5..aefad148dc7 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic/_expected/es/main.js +++ b/test/chunking-form/samples/manual-chunks-dynamic/_expected/es/main.js @@ -1 +1 @@ -import("./generated-dynamic.js").then(({DYNAMIC_USED_BY_A}) => console.log(DYNAMIC_USED_BY_A)); +import('./generated-dynamic.js').then(({DYNAMIC_USED_BY_A}) => console.log(DYNAMIC_USED_BY_A)); diff --git a/test/chunking-form/samples/manual-chunks-dynamic/_expected/system/main.js b/test/chunking-form/samples/manual-chunks-dynamic/_expected/system/main.js index 86c7fd46537..5c1d9db7c1e 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic/_expected/system/main.js +++ b/test/chunking-form/samples/manual-chunks-dynamic/_expected/system/main.js @@ -3,7 +3,7 @@ System.register([], function (exports, module) { return { execute: function () { - module.import("./generated-dynamic.js").then(({DYNAMIC_USED_BY_A}) => console.log(DYNAMIC_USED_BY_A)); + module.import('./generated-dynamic.js').then(({DYNAMIC_USED_BY_A}) => console.log(DYNAMIC_USED_BY_A)); } }; diff --git a/test/misc/bundle-information.js b/test/misc/bundle-information.js index 07322a52c93..724b1d8bddc 100644 --- a/test/misc/bundle-information.js +++ b/test/misc/bundle-information.js @@ -382,7 +382,7 @@ console.log(other);Promise.all([import('./dynamic1'), import('./dynamic2')]).the ); assert.deepEqual( sortedOutput.map(chunk => chunk.entryModuleIds), - [['dynamic1'], ['dynamic2'], ['input'], []], + [['dynamic1'], ['dynamic2'], ['input'], ['other']], 'entryModuleIds' ); }); From e14d90f2b650b48a2e059ab3c98e95b468cb451e Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Fri, 30 Nov 2018 07:12:31 +0100 Subject: [PATCH 18/23] Handle name conflicts between dynamic entries in manual chunks --- src/Chunk.ts | 19 ++++++++++++++----- .../_config.js | 12 ++++++++++++ .../_expected/amd/generated-dynamic.js | 13 +++++++++++++ .../_expected/amd/generated-dynamic2.js | 8 ++++++++ .../_expected/amd/main.js | 6 ++++++ .../_expected/cjs/generated-dynamic.js | 11 +++++++++++ .../_expected/cjs/generated-dynamic2.js | 8 ++++++++ .../_expected/cjs/main.js | 4 ++++ .../_expected/es/generated-dynamic.js | 8 ++++++++ .../_expected/es/generated-dynamic2.js | 1 + .../_expected/es/main.js | 2 ++ .../_expected/system/generated-dynamic.js | 15 +++++++++++++++ .../_expected/system/generated-dynamic2.js | 16 ++++++++++++++++ .../_expected/system/main.js | 11 +++++++++++ .../dynamic1.js | 3 +++ .../dynamic2.js | 4 ++++ .../main.js | 2 ++ 17 files changed, 138 insertions(+), 5 deletions(-) create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_config.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/amd/generated-dynamic.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/amd/generated-dynamic2.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/amd/main.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/cjs/generated-dynamic.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/cjs/generated-dynamic2.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/cjs/main.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/es/generated-dynamic.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/es/generated-dynamic2.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/es/main.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/system/generated-dynamic.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/system/generated-dynamic2.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/system/main.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-name-conflict/dynamic1.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-name-conflict/dynamic2.js create mode 100644 test/chunking-form/samples/manual-chunks-dynamic-name-conflict/main.js diff --git a/src/Chunk.ts b/src/Chunk.ts index 9c7b0337cd6..8846054b231 100644 --- a/src/Chunk.ts +++ b/src/Chunk.ts @@ -244,21 +244,23 @@ export default class Chunk { } } - // TODO Lukas: - // * maybe each chunk has a Set of facaded modules. The type is determined by looking into the module - // TODO Lukas: fail if a name is used more than once // TODO Lukas can this be simplified to directly set the exports? // TODO Lukas dynamic imports -> always named export mode! // TODO Lukas multiple entry points -> always generate facade for more than one + // TODO Lukas handle circularly connected entries generateEntryExportsOrMarkAsTainted() { const exportVariableMaps = Array.from(this.entryModules).map(module => ({ module, map: this.getExportVariableMapForModule(module) })); const exposedVariables: Set = new Set(); + const variableByExportName: Map = new Map(); for (const { map } of exportVariableMaps) { for (const exposedVariable of Array.from(map.keys())) { exposedVariables.add(exposedVariable); + for (const exportName of map.get(exposedVariable).exportNames) { + variableByExportName.set(exportName, exposedVariable); + } } } for (const exposedVariable of Array.from(this.exports.keys())) { @@ -266,12 +268,19 @@ export default class Chunk { } checkNextEntryModule: for (const { map, module } of exportVariableMaps) { for (const exposedVariable of Array.from(exposedVariables)) { - if (!map.has(exposedVariable)) { + if ( + !map.has(exposedVariable) || + map + .get(exposedVariable) + .exportNames.some( + exportName => variableByExportName.get(exportName) !== exposedVariable + ) + ) { this.entryModules.delete(module); continue checkNextEntryModule; } } - for (const [variable, { exportNames, module }] of Array.from(map.entries())) { + for (const [variable, { exportNames, module }] of Array.from(map)) { for (const exportName of exportNames) { this.exports.set(variable, module); this.exportNames[exportName] = variable; diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_config.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_config.js new file mode 100644 index 00000000000..860658f4950 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_config.js @@ -0,0 +1,12 @@ +module.exports = { + description: 'handles name conflicts in manual chunks', + options: { + input: ['main.js'], + manualChunks: { + dynamic: ['dynamic1.js'] + }, + output: { + chunkFileNames: 'generated-[name].js' + } + } +}; diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/amd/generated-dynamic.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/amd/generated-dynamic.js new file mode 100644 index 00000000000..2e04f94135d --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/amd/generated-dynamic.js @@ -0,0 +1,13 @@ +define(['exports'], function (exports) { 'use strict'; + + console.log('dynamic2'); + + const DYNAMIC_A = 'DYNAMIC_A'; + const DYNAMIC_B = 'DYNAMIC_B'; + + console.log('dynamic1'); + + exports.DYNAMIC_B = DYNAMIC_A; + exports.DYNAMIC_A = DYNAMIC_B; + +}); diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/amd/generated-dynamic2.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/amd/generated-dynamic2.js new file mode 100644 index 00000000000..4d555970c86 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/amd/generated-dynamic2.js @@ -0,0 +1,8 @@ +define(['exports', './generated-dynamic.js'], function (exports, dynamic) { 'use strict'; + + + + exports.DYNAMIC_A = dynamic.DYNAMIC_B; + exports.DYNAMIC_B = dynamic.DYNAMIC_A; + +}); diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/amd/main.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/amd/main.js new file mode 100644 index 00000000000..f23b8bdba20 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/amd/main.js @@ -0,0 +1,6 @@ +define(['require'], function (require) { 'use strict'; + + new Promise(function (resolve, reject) { require(['./generated-dynamic.js'], resolve, reject) }).then(result => console.log(result)); + new Promise(function (resolve, reject) { require(['./generated-dynamic2.js'], resolve, reject) }).then(result => console.log(result)); + +}); diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/cjs/generated-dynamic.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/cjs/generated-dynamic.js new file mode 100644 index 00000000000..b7a92cd20a5 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/cjs/generated-dynamic.js @@ -0,0 +1,11 @@ +'use strict'; + +console.log('dynamic2'); + +const DYNAMIC_A = 'DYNAMIC_A'; +const DYNAMIC_B = 'DYNAMIC_B'; + +console.log('dynamic1'); + +exports.DYNAMIC_B = DYNAMIC_A; +exports.DYNAMIC_A = DYNAMIC_B; diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/cjs/generated-dynamic2.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/cjs/generated-dynamic2.js new file mode 100644 index 00000000000..836352671d2 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/cjs/generated-dynamic2.js @@ -0,0 +1,8 @@ +'use strict'; + +var dynamic = require('./generated-dynamic.js'); + + + +exports.DYNAMIC_A = dynamic.DYNAMIC_B; +exports.DYNAMIC_B = dynamic.DYNAMIC_A; diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/cjs/main.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/cjs/main.js new file mode 100644 index 00000000000..a23070ddb0b --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/cjs/main.js @@ -0,0 +1,4 @@ +'use strict'; + +Promise.resolve(require('./generated-dynamic.js')).then(result => console.log(result)); +Promise.resolve(require('./generated-dynamic2.js')).then(result => console.log(result)); diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/es/generated-dynamic.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/es/generated-dynamic.js new file mode 100644 index 00000000000..395087d22e1 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/es/generated-dynamic.js @@ -0,0 +1,8 @@ +console.log('dynamic2'); + +const DYNAMIC_A = 'DYNAMIC_A'; +const DYNAMIC_B = 'DYNAMIC_B'; + +console.log('dynamic1'); + +export { DYNAMIC_A as DYNAMIC_B, DYNAMIC_B as DYNAMIC_A }; diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/es/generated-dynamic2.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/es/generated-dynamic2.js new file mode 100644 index 00000000000..c1ec5610d56 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/es/generated-dynamic2.js @@ -0,0 +1 @@ +export { DYNAMIC_B as DYNAMIC_A, DYNAMIC_A as DYNAMIC_B } from './generated-dynamic.js'; diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/es/main.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/es/main.js new file mode 100644 index 00000000000..e3074e5b20f --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/es/main.js @@ -0,0 +1,2 @@ +import('./generated-dynamic.js').then(result => console.log(result)); +import('./generated-dynamic2.js').then(result => console.log(result)); diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/system/generated-dynamic.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/system/generated-dynamic.js new file mode 100644 index 00000000000..2f4e9da17e3 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/system/generated-dynamic.js @@ -0,0 +1,15 @@ +System.register([], function (exports, module) { + 'use strict'; + return { + execute: function () { + + console.log('dynamic2'); + + const DYNAMIC_A = exports('DYNAMIC_B', 'DYNAMIC_A'); + const DYNAMIC_B = exports('DYNAMIC_A', 'DYNAMIC_B'); + + console.log('dynamic1'); + + } + }; +}); diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/system/generated-dynamic2.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/system/generated-dynamic2.js new file mode 100644 index 00000000000..f4755fbc899 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/system/generated-dynamic2.js @@ -0,0 +1,16 @@ +System.register(['./generated-dynamic.js'], function (exports, module) { + 'use strict'; + return { + setters: [function (module) { + var _setter = {}; + _setter.DYNAMIC_A = module.DYNAMIC_B; + _setter.DYNAMIC_B = module.DYNAMIC_A; + exports(_setter); + }], + execute: function () { + + + + } + }; +}); diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/system/main.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/system/main.js new file mode 100644 index 00000000000..e9f22dd3854 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/system/main.js @@ -0,0 +1,11 @@ +System.register([], function (exports, module) { + 'use strict'; + return { + execute: function () { + + module.import('./generated-dynamic.js').then(result => console.log(result)); + module.import('./generated-dynamic2.js').then(result => console.log(result)); + + } + }; +}); diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/dynamic1.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/dynamic1.js new file mode 100644 index 00000000000..ee02308ddb4 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/dynamic1.js @@ -0,0 +1,3 @@ +console.log('dynamic1'); + +export { DYNAMIC_A as DYNAMIC_B, DYNAMIC_B as DYNAMIC_A } from './dynamic2'; diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/dynamic2.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/dynamic2.js new file mode 100644 index 00000000000..6d087c59d00 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/dynamic2.js @@ -0,0 +1,4 @@ +console.log('dynamic2'); + +export const DYNAMIC_A = 'DYNAMIC_A'; +export const DYNAMIC_B = 'DYNAMIC_B'; diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/main.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/main.js new file mode 100644 index 00000000000..9e2abfea069 --- /dev/null +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/main.js @@ -0,0 +1,2 @@ +import('./dynamic1.js').then(result => console.log(result)); +import('./dynamic2.js').then(result => console.log(result)); From dc675cde71643a0404fd7a390a38c0b429d9c8ef Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Fri, 30 Nov 2018 11:51:57 +0100 Subject: [PATCH 19/23] Simplify tracing --- src/Chunk.ts | 18 +++--------------- .../_expected/es/index-6a71658c.js | 4 +++- .../namespace-reexports/_expected/es/index.js | 2 +- .../namespace-reexports/_expected/es/main.js | 2 +- .../{index-8b381a8d.js => index-51f0f10d.js} | 3 ++- .../_expected/system/index.js | 4 ++-- .../_expected/system/main.js | 8 ++++---- 7 files changed, 16 insertions(+), 25 deletions(-) rename test/chunking-form/samples/namespace-reexports/_expected/system/{index-8b381a8d.js => index-51f0f10d.js} (85%) diff --git a/src/Chunk.ts b/src/Chunk.ts index 8846054b231..35eb0e8c1b6 100644 --- a/src/Chunk.ts +++ b/src/Chunk.ts @@ -244,7 +244,6 @@ export default class Chunk { } } - // TODO Lukas can this be simplified to directly set the exports? // TODO Lukas dynamic imports -> always named export mode! // TODO Lukas multiple entry points -> always generate facade for more than one // TODO Lukas handle circularly connected entries @@ -253,21 +252,17 @@ export default class Chunk { module, map: this.getExportVariableMapForModule(module) })); - const exposedVariables: Set = new Set(); const variableByExportName: Map = new Map(); for (const { map } of exportVariableMaps) { for (const exposedVariable of Array.from(map.keys())) { - exposedVariables.add(exposedVariable); + this.exports.set(exposedVariable, map.get(exposedVariable).module); for (const exportName of map.get(exposedVariable).exportNames) { variableByExportName.set(exportName, exposedVariable); } } } - for (const exposedVariable of Array.from(this.exports.keys())) { - exposedVariables.add(exposedVariable); - } checkNextEntryModule: for (const { map, module } of exportVariableMaps) { - for (const exposedVariable of Array.from(exposedVariables)) { + for (const exposedVariable of Array.from(this.exports.keys())) { if ( !map.has(exposedVariable) || map @@ -280,9 +275,8 @@ export default class Chunk { continue checkNextEntryModule; } } - for (const [variable, { exportNames, module }] of Array.from(map)) { + for (const [variable, { exportNames }] of Array.from(map)) { for (const exportName of exportNames) { - this.exports.set(variable, module); this.exportNames[exportName] = variable; } } @@ -368,12 +362,6 @@ export default class Chunk { } if (module.chunk !== this) { - // we follow reexports if they are not entry points in the hope - // that we can get an entry point reexport to reduce the chance of - // tainting an entryModule chunk by exposing other unnecessary exports - // TODO Lukas this should also stop for dynamic entries, test this - if (module.isEntryPoint && !module.chunk.isEmpty) - return { variable: module.traceExport(name), module }; return module.chunk.traceExport(name, module); } diff --git a/test/chunking-form/samples/namespace-reexports/_expected/es/index-6a71658c.js b/test/chunking-form/samples/namespace-reexports/_expected/es/index-6a71658c.js index 625de5eb307..3204374ec58 100644 --- a/test/chunking-form/samples/namespace-reexports/_expected/es/index-6a71658c.js +++ b/test/chunking-form/samples/namespace-reexports/_expected/es/index-6a71658c.js @@ -1,5 +1,7 @@ import hsl2hsv from './hsl2hsv.js'; +export { default as b } from './hsl2hsv.js'; + var hsl2hsv$1 = 'asdf'; console.log(hsl2hsv$1); @@ -8,4 +10,4 @@ var lib = /*#__PURE__*/Object.freeze({ hsl2hsv: hsl2hsv }); -export { hsl2hsv as a, lib as b }; +export { lib as a }; diff --git a/test/chunking-form/samples/namespace-reexports/_expected/es/index.js b/test/chunking-form/samples/namespace-reexports/_expected/es/index.js index 8956d87096a..9b940aa30ca 100644 --- a/test/chunking-form/samples/namespace-reexports/_expected/es/index.js +++ b/test/chunking-form/samples/namespace-reexports/_expected/es/index.js @@ -1,2 +1,2 @@ -export { a as hsl2hsv } from './index-6a71658c.js'; +export { b as hsl2hsv } from './index-6a71658c.js'; import './hsl2hsv.js'; diff --git a/test/chunking-form/samples/namespace-reexports/_expected/es/main.js b/test/chunking-form/samples/namespace-reexports/_expected/es/main.js index a4e5507ec23..8912d258a3f 100644 --- a/test/chunking-form/samples/namespace-reexports/_expected/es/main.js +++ b/test/chunking-form/samples/namespace-reexports/_expected/es/main.js @@ -1,5 +1,5 @@ import { p } from './hsl2hsv.js'; -import { a as hsl2hsv, b as lib } from './index-6a71658c.js'; +import { a as lib } from './index-6a71658c.js'; console.log(p); var main = new Map(Object.entries(lib)); diff --git a/test/chunking-form/samples/namespace-reexports/_expected/system/index-8b381a8d.js b/test/chunking-form/samples/namespace-reexports/_expected/system/index-51f0f10d.js similarity index 85% rename from test/chunking-form/samples/namespace-reexports/_expected/system/index-8b381a8d.js rename to test/chunking-form/samples/namespace-reexports/_expected/system/index-51f0f10d.js index c61c6d81d0f..d0a0491b975 100644 --- a/test/chunking-form/samples/namespace-reexports/_expected/system/index-8b381a8d.js +++ b/test/chunking-form/samples/namespace-reexports/_expected/system/index-51f0f10d.js @@ -4,6 +4,7 @@ System.register(['./hsl2hsv.js'], function (exports, module) { return { setters: [function (module) { hsl2hsv = module.default; + exports('b', module.default); }], execute: function () { @@ -14,7 +15,7 @@ System.register(['./hsl2hsv.js'], function (exports, module) { var lib = /*#__PURE__*/Object.freeze({ hsl2hsv: hsl2hsv }); - exports('b', lib); + exports('a', lib); } }; diff --git a/test/chunking-form/samples/namespace-reexports/_expected/system/index.js b/test/chunking-form/samples/namespace-reexports/_expected/system/index.js index 6e1ba58f88e..0a81f1b3234 100644 --- a/test/chunking-form/samples/namespace-reexports/_expected/system/index.js +++ b/test/chunking-form/samples/namespace-reexports/_expected/system/index.js @@ -1,8 +1,8 @@ -System.register(['./index-8b381a8d.js', './hsl2hsv.js'], function (exports, module) { +System.register(['./index-51f0f10d.js', './hsl2hsv.js'], function (exports, module) { 'use strict'; return { setters: [function (module) { - exports('hsl2hsv', module.a); + exports('hsl2hsv', module.b); }, function () {}], execute: function () { diff --git a/test/chunking-form/samples/namespace-reexports/_expected/system/main.js b/test/chunking-form/samples/namespace-reexports/_expected/system/main.js index 41bff92da97..a3b0fe5fe3e 100644 --- a/test/chunking-form/samples/namespace-reexports/_expected/system/main.js +++ b/test/chunking-form/samples/namespace-reexports/_expected/system/main.js @@ -1,12 +1,12 @@ -System.register(['./hsl2hsv.js', './index-8b381a8d.js'], function (exports, module) { +System.register(['./hsl2hsv.js', './index-51f0f10d.js'], function (exports, module) { 'use strict'; - var p, hsl2hsv, lib; + var hsl2hsv, p, lib; return { setters: [function (module) { + hsl2hsv = module.default; p = module.p; }, function (module) { - hsl2hsv = module.a; - lib = module.b; + lib = module.a; }], execute: function () { From 7ef2af526f03d8f135b34da5d2e7bceef3743e86 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sat, 1 Dec 2018 12:45:52 +0100 Subject: [PATCH 20/23] A chunk may only ever be facade for a single module to simplify the logic Also delete tests that have been skipped for years. Let's rather make a fresh start should the problem still persists and someone care to address it. --- src/Chunk.ts | 56 ++++++++----------- src/Graph.ts | 32 ++++------- src/chunk-optimization.ts | 4 +- src/rollup/index.ts | 13 ++--- src/rollup/types.d.ts | 2 +- src/utils/assignChunkIds.ts | 9 ++- src/utils/executionOrder.ts | 2 +- src/utils/getExportMode.ts | 3 +- .../_expected/amd/generated-dynamic.js | 4 +- .../_expected/amd/generated-dynamic2.js | 2 +- .../_expected/amd/main.js | 2 +- .../_expected/cjs/generated-dynamic.js | 4 +- .../_expected/cjs/generated-dynamic2.js | 2 +- .../_expected/cjs/main.js | 2 +- .../_expected/es/generated-dynamic.js | 2 +- .../_expected/es/generated-dynamic2.js | 2 +- .../_expected/es/main.js | 2 +- .../_expected/system/generated-dynamic.js | 4 +- .../_expected/system/generated-dynamic2.js | 2 +- .../_expected/system/main.js | 2 +- .../_expected/es/index-6a71658c.js | 1 - .../namespace-reexports/_expected/es/main.js | 2 +- .../function/samples/cycles-pathological/A.js | 11 ---- .../function/samples/cycles-pathological/B.js | 8 --- .../function/samples/cycles-pathological/C.js | 8 --- .../function/samples/cycles-pathological/D.js | 11 ---- .../samples/cycles-pathological/_config.js | 17 ------ .../samples/cycles-pathological/main.js | 12 ---- .../samples/iife-strong-dependencies/A.js | 15 ----- .../samples/iife-strong-dependencies/B.js | 11 ---- .../samples/iife-strong-dependencies/C.js | 11 ---- .../samples/iife-strong-dependencies/D.js | 15 ----- .../iife-strong-dependencies/_config.js | 16 ------ .../samples/iife-strong-dependencies/main.js | 14 ----- test/misc/bundle-information.js | 37 ++++++------ 35 files changed, 84 insertions(+), 256 deletions(-) delete mode 100644 test/function/samples/cycles-pathological/A.js delete mode 100644 test/function/samples/cycles-pathological/B.js delete mode 100644 test/function/samples/cycles-pathological/C.js delete mode 100644 test/function/samples/cycles-pathological/D.js delete mode 100644 test/function/samples/cycles-pathological/_config.js delete mode 100644 test/function/samples/cycles-pathological/main.js delete mode 100644 test/function/samples/iife-strong-dependencies/A.js delete mode 100644 test/function/samples/iife-strong-dependencies/B.js delete mode 100644 test/function/samples/iife-strong-dependencies/C.js delete mode 100644 test/function/samples/iife-strong-dependencies/D.js delete mode 100644 test/function/samples/iife-strong-dependencies/_config.js delete mode 100644 test/function/samples/iife-strong-dependencies/main.js diff --git a/src/Chunk.ts b/src/Chunk.ts index 35eb0e8c1b6..a86eb34ea51 100644 --- a/src/Chunk.ts +++ b/src/Chunk.ts @@ -127,9 +127,8 @@ export default class Chunk { private exportNames: { [name: string]: Variable } = Object.create(null); private dependencies: (ExternalModule | Chunk)[] = undefined; - // an entry module chunk is a chunk that exactly exports the exports of - // an input entry point module - entryModules: Set = new Set(); + entryModules: Module[] = []; + facadeModule: Module | null = null; isEmpty: boolean; isManualChunk: boolean = false; @@ -159,14 +158,16 @@ export default class Chunk { } module.chunk = this; if (module.isEntryPoint || (module.isDynamicEntryPoint && !inlineDynamicImports)) { - this.entryModules.add(module); + this.entryModules.push(module); } } - if (this.entryModules.size > 0) { - const entryModules = Array.from(this.entryModules); + if (this.entryModules.length > 0) { this.variableName = makeLegal( - basename(entryModules.map(module => module.chunkAlias).find(Boolean) || entryModules[0].id) + basename( + this.entryModules.map(module => module.chunkAlias).find(Boolean) || + this.entryModules[0].id + ) ); } else this.variableName = '__chunk_' + ++graph.curChunkIndex; } @@ -193,7 +194,7 @@ export default class Chunk { turnIntoFacade(facadedModule: Module) { this.dependencies = [facadedModule.chunk]; - this.entryModules.add(facadedModule); + this.facadeModule = facadedModule; facadedModule.facadeChunk = this; for (const exportName of facadedModule.getAllExports()) { const tracedVariable = facadedModule.traceExport(exportName); @@ -244,42 +245,29 @@ export default class Chunk { } } - // TODO Lukas dynamic imports -> always named export mode! - // TODO Lukas multiple entry points -> always generate facade for more than one - // TODO Lukas handle circularly connected entries generateEntryExportsOrMarkAsTainted() { - const exportVariableMaps = Array.from(this.entryModules).map(module => ({ + const exportVariableMaps = this.entryModules.map(module => ({ module, map: this.getExportVariableMapForModule(module) })); - const variableByExportName: Map = new Map(); for (const { map } of exportVariableMaps) { for (const exposedVariable of Array.from(map.keys())) { this.exports.set(exposedVariable, map.get(exposedVariable).module); - for (const exportName of map.get(exposedVariable).exportNames) { - variableByExportName.set(exportName, exposedVariable); - } } } checkNextEntryModule: for (const { map, module } of exportVariableMaps) { for (const exposedVariable of Array.from(this.exports.keys())) { - if ( - !map.has(exposedVariable) || - map - .get(exposedVariable) - .exportNames.some( - exportName => variableByExportName.get(exportName) !== exposedVariable - ) - ) { - this.entryModules.delete(module); + if (!map.has(exposedVariable)) { continue checkNextEntryModule; } } + this.facadeModule = module; for (const [variable, { exportNames }] of Array.from(map)) { for (const exportName of exportNames) { this.exportNames[exportName] = variable; } } + return; } } @@ -333,7 +321,9 @@ export default class Chunk { this.traceAndInitializeImport(importName, traced.variable.module); } else { const externalVariable = traced.variable.module.traceExport(importName); - if (externalVariable.included) this.imports.set(original, traced.variable.module); + if (externalVariable.included) { + this.imports.set(original, traced.variable.module); + } } } } @@ -401,7 +391,7 @@ export default class Chunk { } generateInternalExports(options: OutputOptions) { - if (this.entryModules.size > 0) return; + if (this.facadeModule !== null) return; const mangle = options.format === 'system' || options.format === 'es' || options.compact; let i = 0, safeExportName: string; @@ -818,7 +808,7 @@ export default class Chunk { }; // if an entry point facade or dynamic entry point, inline the execution list to avoid loading latency - if (this.entryModules.size > 0) { + if (this.facadeModule !== null) { for (const dep of this.dependencies) { if (dep instanceof Chunk) this.inlineChunkDependencies(dep, true); } @@ -919,7 +909,7 @@ export default class Chunk { * A new facade will be added to chunkList if tainting exports of either as an entry point */ merge(chunk: Chunk, chunkList: Chunk[], options: OutputOptions, inputBase: string) { - if (this.entryModules.size > 0 || chunk.entryModules.size > 0) + if (this.facadeModule !== null || chunk.facadeModule !== null) throw new Error('Internal error: Code splitting chunk merges not supported for facades'); for (const module of chunk.orderedModules) { @@ -1061,10 +1051,8 @@ export default class Chunk { } private computeChunkName(): string { - if (this.entryModules.size > 0) { - for (const entryModule of Array.from(this.entryModules)) { - if (entryModule.chunkAlias) return entryModule.chunkAlias; - } + if (this.facadeModule !== null && this.facadeModule.chunkAlias) { + return this.facadeModule.chunkAlias; } for (const module of this.orderedModules) { if (module.chunkAlias) return module.chunkAlias; @@ -1136,7 +1124,7 @@ export default class Chunk { dependencies: this.renderedDeclarations.dependencies, exports: this.renderedDeclarations.exports, graph: this.graph, - isEntryModuleFacade: !!Array.from(this.entryModules).find(module => module.isEntryPoint), + isEntryModuleFacade: this.facadeModule !== null && this.facadeModule.isEntryPoint, usesTopLevelAwait }, options diff --git a/src/Graph.ts b/src/Graph.ts index 58f42f36040..f98b5c1264d 100644 --- a/src/Graph.ts +++ b/src/Graph.ts @@ -369,7 +369,7 @@ export default class Graph { this.link(); - const { orderedModules, cyclePaths, dynamicImports } = analyseModuleExecution(entryModules); + const { orderedModules, cyclePaths } = analyseModuleExecution(entryModules); for (const cyclePath of cyclePaths) { this.warn({ code: 'CIRCULAR_DEPENDENCY', @@ -419,7 +419,9 @@ export default class Graph { if (preserveModules) { for (const module of orderedModules) { const chunk = new Chunk(this, [module], inlineDynamicImports); - if (module.isEntryPoint || !chunk.isEmpty) chunk.entryModules.add(module); + if (module.isEntryPoint || !chunk.isEmpty) { + chunk.entryModules = [module]; + } chunks.push(chunk); } } else { @@ -450,35 +452,25 @@ export default class Graph { // filter out empty dependencies chunks = chunks.filter( - chunk => !chunk.isEmpty || chunk.entryModules.size > 0 || chunk.isManualChunk + chunk => !chunk.isEmpty || chunk.entryModules.length > 0 || chunk.isManualChunk ); // then go over and ensure all entry chunks export their variables for (const chunk of chunks) { - if (preserveModules || chunk.entryModules.size > 0) { + if (preserveModules || chunk.entryModules.length > 0) { chunk.generateEntryExportsOrMarkAsTainted(); } } // create entry point facades for entry module chunks that have tainted exports + const facades = []; if (!preserveModules) { - for (const entryModule of entryModules) { - if (!entryModule.chunk.entryModules.has(entryModule)) { - const entryPointFacade = new Chunk(this, [], inlineDynamicImports); - entryPointFacade.turnIntoFacade(entryModule); - chunks.push(entryPointFacade); - } - } - if (!inlineDynamicImports) { - for (const entryModule of dynamicImports) { - if ( - entryModule.isDynamicEntryPoint && - !entryModule.chunk.entryModules.has(entryModule) && - !entryModule.facadeChunk - ) { + for (const chunk of chunks) { + for (const entryModule of chunk.entryModules) { + if (chunk.facadeModule !== entryModule) { const entryPointFacade = new Chunk(this, [], inlineDynamicImports); entryPointFacade.turnIntoFacade(entryModule); - chunks.push(entryPointFacade); + facades.push(entryPointFacade); } } } @@ -487,7 +479,7 @@ export default class Graph { timeEnd('generate chunks', 2); this.finished = true; - return chunks; + return chunks.concat(facades); } ); } diff --git a/src/chunk-optimization.ts b/src/chunk-optimization.ts index 68debb60722..5c706f60fc7 100644 --- a/src/chunk-optimization.ts +++ b/src/chunk-optimization.ts @@ -36,10 +36,10 @@ export function optimizeChunks( nextChunk = execGroup[1]; const isMergeCandidate = (chunk: Chunk) => { - if (chunk.entryModules.size > 0 || chunk.isManualChunk) { + if (chunk.facadeModule !== null || chunk.isManualChunk) { return false; } - if (!nextChunk || nextChunk.entryModules.size > 0) { + if (!nextChunk || nextChunk.facadeModule !== null) { return false; } if (chunk.getRenderedSourceLength() > CHUNK_GROUPING_SIZE) { diff --git a/src/rollup/index.ts b/src/rollup/index.ts index c831e79c547..f1763e8fd69 100644 --- a/src/rollup/index.ts +++ b/src/rollup/index.ts @@ -68,7 +68,7 @@ function checkOutputOptions(options: OutputOptions) { function getAbsoluteEntryModulePaths(chunks: Chunk[]): string[] { const absoluteEntryModulePaths: string[] = []; for (const chunk of chunks) { - for (const entryModule of Array.from(chunk.entryModules)) { + for (const entryModule of chunk.entryModules) { if (isAbsolute(entryModule.id)) { absoluteEntryModulePaths.push(entryModule.id); } @@ -282,7 +282,7 @@ export default function rollup( for (const chunk of chunks) { if (!inputOptions.experimentalPreserveModules) chunk.generateInternalExports(outputOptions); - if (Array.from(chunk.entryModules).find(module => module.isEntryPoint)) + if (chunk.facadeModule && chunk.facadeModule.isEntryPoint) chunk.exportMode = getExportMode(chunk, outputOptions); } for (const chunk of chunks) { @@ -298,17 +298,16 @@ export default function rollup( // assign to outputBundle for (let i = 0; i < chunks.length; i++) { const chunk = chunks[i]; + const facadeModule = chunk.facadeModule; outputBundle[chunk.id] = { code: undefined, - entryModuleIds: Array.from(chunk.entryModules).map(module => module.id), + facadeModuleId: facadeModule && facadeModule.id, exports: chunk.getExportNames(), fileName: chunk.id, imports: chunk.getImportIds(), - isDynamicEntry: !!Array.from(chunk.entryModules).find( - module => module.isDynamicEntryPoint - ), - isEntry: !!Array.from(chunk.entryModules).find(module => module.isEntryPoint), + isDynamicEntry: facadeModule !== null && facadeModule.isDynamicEntryPoint, + isEntry: facadeModule !== null && facadeModule.isEntryPoint, map: undefined, modules: chunk.renderedModules, get name() { diff --git a/src/rollup/types.d.ts b/src/rollup/types.d.ts index 519d582f298..3265f35c621 100644 --- a/src/rollup/types.d.ts +++ b/src/rollup/types.d.ts @@ -363,8 +363,8 @@ export interface RenderedModule { } export interface RenderedChunk { - entryModuleIds: string[]; exports: string[]; + facadeModuleId: string | null; fileName: string; imports: string[]; isDynamicEntry: boolean; diff --git a/src/utils/assignChunkIds.ts b/src/utils/assignChunkIds.ts index 75b6c592fa1..bd5fbcb667a 100644 --- a/src/utils/assignChunkIds.ts +++ b/src/utils/assignChunkIds.ts @@ -14,10 +14,9 @@ export function assignChunkIds( const usedIds: Record = {}; const [entryChunks, otherChunks] = chunks.reduce( ([entryChunks, otherChunks], chunk) => { - (Array.from(chunk.entryModules).find(module => module.isEntryPoint) - ? entryChunks - : otherChunks - ).push(chunk); + (chunk.facadeModule && chunk.facadeModule.isEntryPoint ? entryChunks : otherChunks).push( + chunk + ); return [entryChunks, otherChunks]; }, [[], []] @@ -37,7 +36,7 @@ export function assignChunkIds( chunk.generateIdPreserveModules(inputBase, usedIds); } else { let pattern, patternName; - if (Array.from(chunk.entryModules).find(module => module.isEntryPoint)) { + if (chunk.facadeModule && chunk.facadeModule.isEntryPoint) { pattern = outputOptions.entryFileNames || '[name].js'; patternName = 'output.entryFileNames'; } else { diff --git a/src/utils/executionOrder.ts b/src/utils/executionOrder.ts index 929f1958ba6..8cc2d12d9a9 100644 --- a/src/utils/executionOrder.ts +++ b/src/utils/executionOrder.ts @@ -75,7 +75,7 @@ export function analyseModuleExecution(entryModules: Module[]) { } } - return { orderedModules, dynamicImports, cyclePaths }; + return { orderedModules, cyclePaths }; } function getCyclePath(id: string, parentId: string, parents: { [id: string]: string | null }) { diff --git a/src/utils/getExportMode.ts b/src/utils/getExportMode.ts index 34d8dad23dc..174719b7a27 100644 --- a/src/utils/getExportMode.ts +++ b/src/utils/getExportMode.ts @@ -32,7 +32,8 @@ export default function getExportMode( exportMode = 'default'; } else { if ( - Array.from(chunk.entryModules).find(module => module.isEntryPoint) && + chunk.facadeModule !== null && + chunk.facadeModule.isEntryPoint && format !== 'es' && exportKeys.indexOf('default') !== -1 ) { diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/amd/generated-dynamic.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/amd/generated-dynamic.js index 2e04f94135d..1c1ce78581c 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/amd/generated-dynamic.js +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/amd/generated-dynamic.js @@ -7,7 +7,7 @@ define(['exports'], function (exports) { 'use strict'; console.log('dynamic1'); - exports.DYNAMIC_B = DYNAMIC_A; - exports.DYNAMIC_A = DYNAMIC_B; + exports.DYNAMIC_A = DYNAMIC_A; + exports.DYNAMIC_B = DYNAMIC_B; }); diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/amd/generated-dynamic2.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/amd/generated-dynamic2.js index 4d555970c86..3fc5bfad3d6 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/amd/generated-dynamic2.js +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/amd/generated-dynamic2.js @@ -2,7 +2,7 @@ define(['exports', './generated-dynamic.js'], function (exports, dynamic) { 'use - exports.DYNAMIC_A = dynamic.DYNAMIC_B; exports.DYNAMIC_B = dynamic.DYNAMIC_A; + exports.DYNAMIC_A = dynamic.DYNAMIC_B; }); diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/amd/main.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/amd/main.js index f23b8bdba20..0e20039a5ed 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/amd/main.js +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/amd/main.js @@ -1,6 +1,6 @@ define(['require'], function (require) { 'use strict'; - new Promise(function (resolve, reject) { require(['./generated-dynamic.js'], resolve, reject) }).then(result => console.log(result)); new Promise(function (resolve, reject) { require(['./generated-dynamic2.js'], resolve, reject) }).then(result => console.log(result)); + new Promise(function (resolve, reject) { require(['./generated-dynamic.js'], resolve, reject) }).then(result => console.log(result)); }); diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/cjs/generated-dynamic.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/cjs/generated-dynamic.js index b7a92cd20a5..19dd5e249f1 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/cjs/generated-dynamic.js +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/cjs/generated-dynamic.js @@ -7,5 +7,5 @@ const DYNAMIC_B = 'DYNAMIC_B'; console.log('dynamic1'); -exports.DYNAMIC_B = DYNAMIC_A; -exports.DYNAMIC_A = DYNAMIC_B; +exports.DYNAMIC_A = DYNAMIC_A; +exports.DYNAMIC_B = DYNAMIC_B; diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/cjs/generated-dynamic2.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/cjs/generated-dynamic2.js index 836352671d2..e053e77b359 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/cjs/generated-dynamic2.js +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/cjs/generated-dynamic2.js @@ -4,5 +4,5 @@ var dynamic = require('./generated-dynamic.js'); -exports.DYNAMIC_A = dynamic.DYNAMIC_B; exports.DYNAMIC_B = dynamic.DYNAMIC_A; +exports.DYNAMIC_A = dynamic.DYNAMIC_B; diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/cjs/main.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/cjs/main.js index a23070ddb0b..0a28239769b 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/cjs/main.js +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/cjs/main.js @@ -1,4 +1,4 @@ 'use strict'; -Promise.resolve(require('./generated-dynamic.js')).then(result => console.log(result)); Promise.resolve(require('./generated-dynamic2.js')).then(result => console.log(result)); +Promise.resolve(require('./generated-dynamic.js')).then(result => console.log(result)); diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/es/generated-dynamic.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/es/generated-dynamic.js index 395087d22e1..a819dae41d1 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/es/generated-dynamic.js +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/es/generated-dynamic.js @@ -5,4 +5,4 @@ const DYNAMIC_B = 'DYNAMIC_B'; console.log('dynamic1'); -export { DYNAMIC_A as DYNAMIC_B, DYNAMIC_B as DYNAMIC_A }; +export { DYNAMIC_A, DYNAMIC_B }; diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/es/generated-dynamic2.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/es/generated-dynamic2.js index c1ec5610d56..c994f0671ad 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/es/generated-dynamic2.js +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/es/generated-dynamic2.js @@ -1 +1 @@ -export { DYNAMIC_B as DYNAMIC_A, DYNAMIC_A as DYNAMIC_B } from './generated-dynamic.js'; +export { DYNAMIC_A as DYNAMIC_B, DYNAMIC_B as DYNAMIC_A } from './generated-dynamic.js'; diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/es/main.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/es/main.js index e3074e5b20f..d191126a7d3 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/es/main.js +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/es/main.js @@ -1,2 +1,2 @@ -import('./generated-dynamic.js').then(result => console.log(result)); import('./generated-dynamic2.js').then(result => console.log(result)); +import('./generated-dynamic.js').then(result => console.log(result)); diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/system/generated-dynamic.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/system/generated-dynamic.js index 2f4e9da17e3..213666c17ca 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/system/generated-dynamic.js +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/system/generated-dynamic.js @@ -5,8 +5,8 @@ System.register([], function (exports, module) { console.log('dynamic2'); - const DYNAMIC_A = exports('DYNAMIC_B', 'DYNAMIC_A'); - const DYNAMIC_B = exports('DYNAMIC_A', 'DYNAMIC_B'); + const DYNAMIC_A = exports('DYNAMIC_A', 'DYNAMIC_A'); + const DYNAMIC_B = exports('DYNAMIC_B', 'DYNAMIC_B'); console.log('dynamic1'); diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/system/generated-dynamic2.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/system/generated-dynamic2.js index f4755fbc899..27e6e17fb12 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/system/generated-dynamic2.js +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/system/generated-dynamic2.js @@ -3,8 +3,8 @@ System.register(['./generated-dynamic.js'], function (exports, module) { return { setters: [function (module) { var _setter = {}; - _setter.DYNAMIC_A = module.DYNAMIC_B; _setter.DYNAMIC_B = module.DYNAMIC_A; + _setter.DYNAMIC_A = module.DYNAMIC_B; exports(_setter); }], execute: function () { diff --git a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/system/main.js b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/system/main.js index e9f22dd3854..fa189fe4b60 100644 --- a/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/system/main.js +++ b/test/chunking-form/samples/manual-chunks-dynamic-name-conflict/_expected/system/main.js @@ -3,8 +3,8 @@ System.register([], function (exports, module) { return { execute: function () { - module.import('./generated-dynamic.js').then(result => console.log(result)); module.import('./generated-dynamic2.js').then(result => console.log(result)); + module.import('./generated-dynamic.js').then(result => console.log(result)); } }; diff --git a/test/chunking-form/samples/namespace-reexports/_expected/es/index-6a71658c.js b/test/chunking-form/samples/namespace-reexports/_expected/es/index-6a71658c.js index 3204374ec58..3ac4915370c 100644 --- a/test/chunking-form/samples/namespace-reexports/_expected/es/index-6a71658c.js +++ b/test/chunking-form/samples/namespace-reexports/_expected/es/index-6a71658c.js @@ -1,5 +1,4 @@ import hsl2hsv from './hsl2hsv.js'; - export { default as b } from './hsl2hsv.js'; var hsl2hsv$1 = 'asdf'; diff --git a/test/chunking-form/samples/namespace-reexports/_expected/es/main.js b/test/chunking-form/samples/namespace-reexports/_expected/es/main.js index 8912d258a3f..82c8974ca04 100644 --- a/test/chunking-form/samples/namespace-reexports/_expected/es/main.js +++ b/test/chunking-form/samples/namespace-reexports/_expected/es/main.js @@ -1,4 +1,4 @@ -import { p } from './hsl2hsv.js'; +import hsl2hsv, { p } from './hsl2hsv.js'; import { a as lib } from './index-6a71658c.js'; console.log(p); diff --git a/test/function/samples/cycles-pathological/A.js b/test/function/samples/cycles-pathological/A.js deleted file mode 100644 index 9e0fd2e72cc..00000000000 --- a/test/function/samples/cycles-pathological/A.js +++ /dev/null @@ -1,11 +0,0 @@ -import B from './B'; - -export default class A { - constructor () { - this.isA = true; - } - - b () { - return new B(); - } -} diff --git a/test/function/samples/cycles-pathological/B.js b/test/function/samples/cycles-pathological/B.js deleted file mode 100644 index 1c8e9b4b3e5..00000000000 --- a/test/function/samples/cycles-pathological/B.js +++ /dev/null @@ -1,8 +0,0 @@ -import A from './A'; - -export default class B extends A { - constructor () { - super(); - this.isB = true; - } -} diff --git a/test/function/samples/cycles-pathological/C.js b/test/function/samples/cycles-pathological/C.js deleted file mode 100644 index 313bba7af02..00000000000 --- a/test/function/samples/cycles-pathological/C.js +++ /dev/null @@ -1,8 +0,0 @@ -import D from './D'; - -export default class C extends D { - constructor () { - super(); - this.isC = true; - } -} diff --git a/test/function/samples/cycles-pathological/D.js b/test/function/samples/cycles-pathological/D.js deleted file mode 100644 index 2d8a405328d..00000000000 --- a/test/function/samples/cycles-pathological/D.js +++ /dev/null @@ -1,11 +0,0 @@ -import C from './C'; - -export default class D { - constructor () { - this.isD = true; - } - - c () { - return new C(); - } -} diff --git a/test/function/samples/cycles-pathological/_config.js b/test/function/samples/cycles-pathological/_config.js deleted file mode 100644 index c400adbf775..00000000000 --- a/test/function/samples/cycles-pathological/_config.js +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - skip: true, - description: 'resolves pathological cyclical dependencies gracefully', - buble: true, - warnings: [ - { - code: 'CIRCULAR_DEPENDENCY', - importer: 'A.js', - message: 'Circular dependency: A.js -> B.js -> A.js' - }, - { - code: 'CIRCULAR_DEPENDENCY', - importer: 'C.js', - message: 'Circular dependency: C.js -> D.js -> C.js' - } - ] -}; diff --git a/test/function/samples/cycles-pathological/main.js b/test/function/samples/cycles-pathological/main.js deleted file mode 100644 index f4c19dbcddb..00000000000 --- a/test/function/samples/cycles-pathological/main.js +++ /dev/null @@ -1,12 +0,0 @@ -import A from './A'; -import B from './B'; - -import C from './C'; -import D from './D'; - -export const a = new A(); -export const b1 = a.b(); -export const b2 = new B(); -export const c1 = new C(); -export const d = new D(); -export const c2 = d.c(); diff --git a/test/function/samples/iife-strong-dependencies/A.js b/test/function/samples/iife-strong-dependencies/A.js deleted file mode 100644 index 2c51ca572ab..00000000000 --- a/test/function/samples/iife-strong-dependencies/A.js +++ /dev/null @@ -1,15 +0,0 @@ -import { B } from './B'; - -export var A = function () { - this.isA = true; -}; - -A.prototype = { - b: function () { - var Constructor = B; - - return function () { - return new Constructor(); - }; - }() -}; diff --git a/test/function/samples/iife-strong-dependencies/B.js b/test/function/samples/iife-strong-dependencies/B.js deleted file mode 100644 index f06d45d100e..00000000000 --- a/test/function/samples/iife-strong-dependencies/B.js +++ /dev/null @@ -1,11 +0,0 @@ -import { A } from './A'; - -export var B = function () { - this.isB = true; -}; - -B.prototype = { - a: function () { - return new A(); - } -}; diff --git a/test/function/samples/iife-strong-dependencies/C.js b/test/function/samples/iife-strong-dependencies/C.js deleted file mode 100644 index 9da83316bec..00000000000 --- a/test/function/samples/iife-strong-dependencies/C.js +++ /dev/null @@ -1,11 +0,0 @@ -import { D } from './D'; - -export var C = function () { - this.isC = true; -}; - -C.prototype = { - d: function () { - return new D(); - } -}; diff --git a/test/function/samples/iife-strong-dependencies/D.js b/test/function/samples/iife-strong-dependencies/D.js deleted file mode 100644 index ad3afa0b7e3..00000000000 --- a/test/function/samples/iife-strong-dependencies/D.js +++ /dev/null @@ -1,15 +0,0 @@ -import { C } from './C'; - -export var D = function () { - this.isD = true; -}; - -D.prototype = { - c: function () { - var Constructor = C; - - return function () { - return new Constructor(); - }; - }() -}; diff --git a/test/function/samples/iife-strong-dependencies/_config.js b/test/function/samples/iife-strong-dependencies/_config.js deleted file mode 100644 index f1e515689ab..00000000000 --- a/test/function/samples/iife-strong-dependencies/_config.js +++ /dev/null @@ -1,16 +0,0 @@ -module.exports = { - skip: true, - description: 'does not treat references inside IIFEs as weak dependencies', // edge case encountered in THREE.js codebase - warnings: [ - { - code: 'CIRCULAR_DEPENDENCY', - importer: 'A.js', - message: 'Circular dependency: A.js -> B.js -> A.js' - }, - { - code: 'CIRCULAR_DEPENDENCY', - importer: 'C.js', - message: 'Circular dependency: C.js -> D.js -> C.js' - } - ] -}; diff --git a/test/function/samples/iife-strong-dependencies/main.js b/test/function/samples/iife-strong-dependencies/main.js deleted file mode 100644 index 1eaa49de80e..00000000000 --- a/test/function/samples/iife-strong-dependencies/main.js +++ /dev/null @@ -1,14 +0,0 @@ -import { A } from './A'; -import { B } from './B'; -import { C } from './C'; -import { D } from './D'; - -export var a1 = new A(); -export var b1 = new B(); -export var c1 = new C(); -export var d1 = new D(); - -export var a2 = b1.a(); -export var b2 = a1.b(); -export var c2 = d1.c(); -export var d2 = c1.d(); diff --git a/test/misc/bundle-information.js b/test/misc/bundle-information.js index 724b1d8bddc..bfeb5ffcc95 100644 --- a/test/misc/bundle-information.js +++ b/test/misc/bundle-information.js @@ -2,7 +2,6 @@ const assert = require('assert'); const rollup = require('../../dist/rollup'); const { loader } = require('../utils.js'); -// TODO Lukas test multiple entry module ids describe('The bundle object', () => { it('contains information about the generated chunks', () => { return rollup @@ -51,9 +50,9 @@ describe('The bundle object', () => { 'name' ); assert.deepEqual( - sortedOutput.map(chunk => chunk.entryModuleIds), - [[], ['input1'], ['input2']], - 'entryModuleIds' + sortedOutput.map(chunk => chunk.facadeModuleId), + [null, 'input1', 'input2'], + 'facadeModuleId' ); assert.deepEqual( sortedOutput.map(chunk => chunk.imports), @@ -131,9 +130,9 @@ describe('The bundle object', () => { ); assert.deepEqual(sortedOutput.map(chunk => chunk.isEntry), [false, true, true], 'isEntry'); assert.deepEqual( - sortedOutput.map(chunk => chunk.entryModuleIds), - [[], ['input1'], ['input2']], - 'entryModuleIds' + sortedOutput.map(chunk => chunk.facadeModuleId), + [null, 'input1', 'input2'], + 'facadeModuleId' ); }); }); @@ -170,9 +169,9 @@ describe('The bundle object', () => { 'fileName' ); assert.deepEqual( - sortedOutput.map(chunk => chunk.entryModuleIds), - [['input1'], ['input2'], []], - 'entryModuleIds' + sortedOutput.map(chunk => chunk.facadeModuleId), + ['input1', 'input2', null], + 'facadeModuleId' ); }); }); @@ -224,9 +223,9 @@ describe('The bundle object', () => { 'isDynamicEntry' ); assert.deepEqual( - sortedOutput.map(chunk => chunk.entryModuleIds), - [['dynamic1'], ['dynamic2'], ['input']], - 'entryModuleIds' + sortedOutput.map(chunk => chunk.facadeModuleId), + ['dynamic1', 'dynamic2', 'input'], + 'facadeModuleId' ); }); }); @@ -273,9 +272,9 @@ describe('The bundle object', () => { 'isDynamicEntry' ); assert.deepEqual( - sortedOutput.map(chunk => chunk.entryModuleIds), - [[], ['dynamic'], ['input1'], ['input2']], - 'entryModuleIds' + sortedOutput.map(chunk => chunk.facadeModuleId), + [null, 'dynamic', 'input1', 'input2'], + 'facadeModuleId' ); }); }); @@ -381,9 +380,9 @@ console.log(other);Promise.all([import('./dynamic1'), import('./dynamic2')]).the 'isDynamicEntry' ); assert.deepEqual( - sortedOutput.map(chunk => chunk.entryModuleIds), - [['dynamic1'], ['dynamic2'], ['input'], ['other']], - 'entryModuleIds' + sortedOutput.map(chunk => chunk.facadeModuleId), + ['dynamic1', 'dynamic2', 'input', 'other'], + 'facadeModuleId' ); }); }); From 27c4d045f328fb9f3f5101afd6c222d61dfb4bb5 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sun, 2 Dec 2018 20:10:56 +0100 Subject: [PATCH 21/23] Add information about dynamically imported chunks to bundle --- src/Chunk.ts | 47 +++++++++--------- src/Graph.ts | 70 ++++++++++++-------------- src/Module.ts | 88 +++++++++++++-------------------- src/ast/nodes/Import.ts | 8 +-- src/rollup/index.ts | 3 +- src/rollup/types.d.ts | 1 + src/utils/chunkColouring.ts | 10 ++-- src/utils/executionOrder.ts | 9 ++-- test/misc/bundle-information.js | 56 ++++++++++++++++----- 9 files changed, 145 insertions(+), 147 deletions(-) diff --git a/src/Chunk.ts b/src/Chunk.ts index a86eb34ea51..6fb382d3280 100644 --- a/src/Chunk.ts +++ b/src/Chunk.ts @@ -127,6 +127,7 @@ export default class Chunk { private exportNames: { [name: string]: Variable } = Object.create(null); private dependencies: (ExternalModule | Chunk)[] = undefined; + private dynamicDependencies: (ExternalModule | Chunk)[] = undefined; entryModules: Module[] = []; facadeModule: Module | null = null; isEmpty: boolean; @@ -173,7 +174,11 @@ export default class Chunk { } getImportIds(): string[] { - return this.dependencies.map(module => module.id); + return this.dependencies.map(chunk => chunk.id); + } + + getDynamicImportIds(): string[] { + return this.dynamicDependencies.map(chunk => chunk.id); } getExportNames(): string[] { @@ -194,6 +199,7 @@ export default class Chunk { turnIntoFacade(facadedModule: Module) { this.dependencies = [facadedModule.chunk]; + this.dynamicDependencies = []; this.facadeModule = facadedModule; facadedModule.facadeChunk = this; for (const exportName of facadedModule.getAllExports()) { @@ -204,16 +210,23 @@ export default class Chunk { } link() { - this.dependencies = []; + const dependencies: Set = new Set(); + const dynamicDependencies: Set = new Set(); for (const module of this.orderedModules) { - this.addModuleDependenciesToChunk(module); + this.addChunksFromDependencies(module.dependencies, dependencies); + this.addChunksFromDependencies(module.dynamicDependencies, dynamicDependencies); this.setUpModuleImports(module); } + this.dependencies = Array.from(dependencies); + this.dynamicDependencies = Array.from(dynamicDependencies); sortByExecutionOrder(this.dependencies); } - private addModuleDependenciesToChunk(module: Module) { - for (const depModule of module.dependencies) { + private addChunksFromDependencies( + moduleDependencies: (Module | ExternalModule)[], + chunkDependencies: Set + ) { + for (const depModule of moduleDependencies) { if (depModule.chunk === this) { continue; } @@ -221,15 +234,12 @@ export default class Chunk { if (depModule instanceof Module) { dependency = depModule.chunk; } else { - // unused pure external modules can be skipped if (!depModule.used && this.graph.isPureExternalModule(depModule.id)) { continue; } dependency = depModule; } - if (this.dependencies.indexOf(dependency) === -1) { - this.dependencies.push(dependency); - } + chunkDependencies.add(dependency); } } @@ -238,7 +248,7 @@ export default class Chunk { const declaration = module.imports[importName]; this.traceAndInitializeImport(declaration.name, declaration.module); } - for (const { resolution } of module.dynamicImportResolutions) { + for (const { resolution } of module.dynamicImports) { this.hasDynamicImport = true; if (resolution instanceof Module && resolution.chunk === this) resolution.getOrCreateNamespace().include(); @@ -421,26 +431,17 @@ export default class Chunk { private prepareDynamicImports() { for (const module of this.orderedModules) { - for (let i = 0; i < module.dynamicImportResolutions.length; i++) { - const node = module.dynamicImports[i]; - const resolution = module.dynamicImportResolutions[i].resolution; - + for (const { node, resolution } of module.dynamicImports) { if (!resolution) continue; - if (resolution instanceof Module) { - // if we have the module in the chunk, inline as Promise.resolve(namespace) - // ensuring that we create a namespace import of it as well if (resolution.chunk === this) { const namespace = resolution.getOrCreateNamespace(); node.setResolution(false, namespace.getName()); - // for the module in another chunk, import that other chunk directly } else { node.setResolution(false); } - // external dynamic import resolution } else if (resolution instanceof ExternalModule) { node.setResolution(true); - // AST Node -> source replacement } else { node.setResolution(false); } @@ -452,10 +453,7 @@ export default class Chunk { for (let i = 0; i < this.orderedModules.length; i++) { const module = this.orderedModules[i]; const code = this.renderedModuleSources[i]; - for (let j = 0; j < module.dynamicImportResolutions.length; j++) { - const node = module.dynamicImports[j]; - const resolution = module.dynamicImportResolutions[j].resolution; - + for (const { node, resolution } of module.dynamicImports) { if (!resolution) continue; if (resolution instanceof Module) { const resolutionChunk = resolution.facadeChunk || resolution.chunk; @@ -466,7 +464,6 @@ export default class Chunk { } } else if (resolution instanceof ExternalModule) { node.renderFinalResolution(code, `'${resolution.id}'`); - // AST Node -> source replacement } else { node.renderFinalResolution(code, resolution); } diff --git a/src/Graph.ts b/src/Graph.ts index f98b5c1264d..7a3d89e5b28 100644 --- a/src/Graph.ts +++ b/src/Graph.ts @@ -587,47 +587,41 @@ export default class Graph { } private fetchAllDependencies(module: Module) { - // resolve and fetch dynamic imports where possible const fetchDynamicImportsPromise = Promise.all( - module.getDynamicImportExpressions().map((dynamicImportExpression, index) => { - return Promise.resolve( - this.pluginDriver.hookFirst('resolveDynamicImport', [dynamicImportExpression, module.id]) - ).then(replacement => { - if (!replacement) { - module.dynamicImportResolutions[index] = { - alias: undefined, - resolution: undefined - }; - return; - } - const alias = getAliasName( - replacement, - typeof dynamicImportExpression === 'string' ? dynamicImportExpression : undefined - ); - if (typeof dynamicImportExpression !== 'string') { - module.dynamicImportResolutions[index] = { alias, resolution: replacement }; - } else if (this.isExternal(replacement, module.id, true)) { - let externalModule; - if (!this.moduleById.has(replacement)) { - externalModule = new ExternalModule({ - graph: this, - id: replacement - }); - this.externalModules.push(externalModule); - this.moduleById.set(replacement, module); + module.getDynamicImportExpressions().map((dynamicImportExpression, index) => + this.pluginDriver + .hookFirst('resolveDynamicImport', [dynamicImportExpression, module.id]) + .then(replacement => { + if (!replacement) return; + const dynamicImport = module.dynamicImports[index]; + dynamicImport.alias = getAliasName( + replacement, + typeof dynamicImportExpression === 'string' ? dynamicImportExpression : undefined + ); + if (typeof dynamicImportExpression !== 'string') { + dynamicImport.resolution = replacement; + } else if (this.isExternal(replacement, module.id, true)) { + let externalModule; + if (!this.moduleById.has(replacement)) { + externalModule = new ExternalModule({ + graph: this, + id: replacement + }); + this.externalModules.push(externalModule); + this.moduleById.set(replacement, module); + } else { + externalModule = this.moduleById.get(replacement); + } + dynamicImport.resolution = externalModule; + externalModule.exportsNamespace = true; } else { - externalModule = this.moduleById.get(replacement); + return this.fetchModule(replacement, module.id).then(depModule => { + dynamicImport.resolution = depModule; + }); } - module.dynamicImportResolutions[index] = { alias, resolution: externalModule }; - externalModule.exportsNamespace = true; - } else { - return this.fetchModule(replacement, module.id).then(depModule => { - module.dynamicImportResolutions[index] = { alias, resolution: depModule }; - }); - } - }); - }) - ).then(() => {}); + }) + ) + ); fetchDynamicImportsPromise.catch(() => {}); return Promise.all( diff --git a/src/Module.ts b/src/Module.ts index 80f798a9d35..3d1d5624099 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -149,81 +149,57 @@ function handleMissingExport( export default class Module { type: 'Module'; - private graph: Graph; + chunk: Chunk; + chunkAlias: string = undefined; code: string; - comments: CommentDescription[]; - dependencies: (Module | ExternalModule)[]; + comments: CommentDescription[] = []; + customTransformCache: boolean; + dependencies: (Module | ExternalModule)[] = []; + dynamicDependencies: (Module | ExternalModule)[] = []; + dynamicImports: { + node: Import; + alias: string | null; + resolution: Module | ExternalModule | string | void; + }[] = []; + entryPointsHash: Uint8Array = new Uint8Array(10); + exportAllModules: (Module | ExternalModule)[] = null; excludeFromSourcemap: boolean; - exports: { [name: string]: ExportDescription }; - exportsAll: { [name: string]: string }; - exportAllSources: string[]; + execIndex: number = Infinity; + exports: { [name: string]: ExportDescription } = Object.create(null); + exportsAll: { [name: string]: string } = Object.create(null); + exportAllSources: string[] = []; + facadeChunk: Chunk | null = null; id: string; - imports: { [name: string]: ImportDescription }; + importMetas: MetaProperty[] = []; + imports: { [name: string]: ImportDescription } = Object.create(null); + isDynamicEntryPoint: boolean = false; + isEntryPoint: boolean = false; isExecuted: boolean = false; isExternal: false; originalCode: string; originalSourcemap: RawSourceMap | void; - reexports: { [name: string]: ReexportDescription }; + reexports: { [name: string]: ReexportDescription } = Object.create(null); resolvedIds: IdMap; scope: ModuleScope; sourcemapChain: RawSourceMap[]; - sources: string[]; - dynamicImports: Import[]; - importMetas: MetaProperty[]; - dynamicImportResolutions: { - alias: string; - resolution: Module | ExternalModule | string | void; - }[]; + sources: string[] = []; transformAssets: Asset[]; - customTransformCache: boolean; - - execIndex: number; - isEntryPoint: boolean; - isDynamicEntryPoint: boolean; - chunkAlias: string; - entryPointsHash: Uint8Array; - chunk: Chunk; - exportAllModules: (Module | ExternalModule)[]; usesTopLevelAwait: boolean = false; - facadeChunk: Chunk | null = null; private ast: Program; private astContext: AstContext; private context: string; - private namespaceVariable: NamespaceVariable = undefined; private esTreeAst: ESTree.Program; + private graph: Graph; private magicString: MagicString; + private namespaceVariable: NamespaceVariable = undefined; private transformDependencies: string[]; constructor(graph: Graph, id: string) { this.id = id; - this.chunkAlias = undefined; this.graph = graph; - this.comments = []; - - this.dynamicImports = []; - this.importMetas = []; - this.dynamicImportResolutions = []; - this.isEntryPoint = false; - this.isDynamicEntryPoint = false; - this.execIndex = Infinity; - this.entryPointsHash = new Uint8Array(10); - this.excludeFromSourcemap = /\0/.test(id); this.context = graph.getModuleContext(id); - - // all dependencies - this.sources = []; - this.dependencies = []; - - // imports and exports, indexed by local name - this.imports = Object.create(null); - this.exports = Object.create(null); - this.exportsAll = Object.create(null); - this.reexports = Object.create(null); - - this.exportAllSources = []; - this.exportAllModules = null; } setSource({ @@ -437,7 +413,7 @@ export default class Module { } private addDynamicImport(node: Import) { - this.dynamicImports.push(node); + this.dynamicImports.push({ node, alias: undefined, resolution: undefined }); } private addImportMeta(node: MetaProperty) { @@ -497,6 +473,11 @@ export default class Module { this.dependencies.push(module); } } + for (const { resolution } of this.dynamicImports) { + if (resolution instanceof Module || resolution instanceof ExternalModule) { + this.dynamicDependencies.push(resolution); + } + } const resolveSpecifiers = (specifiers: { [name: string]: ImportDescription | ReexportDescription; @@ -523,7 +504,7 @@ export default class Module { } getDynamicImportExpressions(): (string | Node)[] { - return this.dynamicImports.map(node => { + return this.dynamicImports.map(({ node }) => { const importArgument = node.parent.arguments[0]; if (isTemplateLiteral(importArgument)) { if (importArgument.expressions.length === 0 && importArgument.quasis.length === 1) { @@ -634,7 +615,8 @@ export default class Module { } private includeDynamicImport(node: Import) { - const resolution = this.dynamicImportResolutions[this.dynamicImports.indexOf(node)].resolution; + const resolution = this.dynamicImports.find(dynamicImport => dynamicImport.node === node) + .resolution; if (resolution instanceof Module) { resolution.isDynamicEntryPoint = true; resolution.includeAllExports(); diff --git a/src/ast/nodes/Import.ts b/src/ast/nodes/Import.ts index 9b032f43ef6..37164af3578 100644 --- a/src/ast/nodes/Import.ts +++ b/src/ast/nodes/Import.ts @@ -47,7 +47,6 @@ export default class Import extends NodeBase { private resolutionNamespace: string; private resolutionInterop: boolean; - private rendered: boolean; include() { this.included = true; @@ -58,18 +57,16 @@ export default class Import extends NodeBase { this.included = false; this.resolutionNamespace = undefined; this.resolutionInterop = false; - this.rendered = false; this.context.addDynamicImport(this); } renderFinalResolution(code: MagicString, resolution: string) { - // avoid unnecessary writes when tree-shaken - if (this.rendered) + if (this.included) { code.overwrite(this.parent.arguments[0].start, this.parent.arguments[0].end, resolution); + } } render(code: MagicString, options: RenderOptions) { - this.rendered = true; if (this.resolutionNamespace) { const _ = options.compact ? '' : ' '; const s = options.compact ? '' : ';'; @@ -94,7 +91,6 @@ export default class Import extends NodeBase { } setResolution(interop: boolean, namespace: string = undefined): void { - this.rendered = false; this.resolutionInterop = interop; this.resolutionNamespace = namespace; } diff --git a/src/rollup/index.ts b/src/rollup/index.ts index f1763e8fd69..4ca5e2f8c3a 100644 --- a/src/rollup/index.ts +++ b/src/rollup/index.ts @@ -302,8 +302,9 @@ export default function rollup( outputBundle[chunk.id] = { code: undefined, - facadeModuleId: facadeModule && facadeModule.id, + dynamicImports: chunk.getDynamicImportIds(), exports: chunk.getExportNames(), + facadeModuleId: facadeModule && facadeModule.id, fileName: chunk.id, imports: chunk.getImportIds(), isDynamicEntry: facadeModule !== null && facadeModule.isDynamicEntryPoint, diff --git a/src/rollup/types.d.ts b/src/rollup/types.d.ts index 3265f35c621..905ca54796c 100644 --- a/src/rollup/types.d.ts +++ b/src/rollup/types.d.ts @@ -363,6 +363,7 @@ export interface RenderedModule { } export interface RenderedChunk { + dynamicImports: string[]; exports: string[]; facadeModuleId: string | null; fileName: string; diff --git a/src/utils/chunkColouring.ts b/src/utils/chunkColouring.ts index 5a0918e9b15..973f26ee708 100644 --- a/src/utils/chunkColouring.ts +++ b/src/utils/chunkColouring.ts @@ -30,13 +30,13 @@ export function assignChunkColouringHashes( addCurrentEntryColourToModule(dependency); } - for (const dynamicModule of module.dynamicImportResolutions) { + for (const { resolution } of module.dynamicImports) { if ( - dynamicModule.resolution instanceof Module && - dynamicModule.resolution.isDynamicEntryPoint && - !dynamicModule.resolution.chunkAlias + resolution instanceof Module && + resolution.isDynamicEntryPoint && + !resolution.chunkAlias ) { - dynamicImports.add(dynamicModule.resolution); + dynamicImports.add(resolution); } } }; diff --git a/src/utils/executionOrder.ts b/src/utils/executionOrder.ts index 8cc2d12d9a9..29f685abb78 100644 --- a/src/utils/executionOrder.ts +++ b/src/utils/executionOrder.ts @@ -45,12 +45,9 @@ export function analyseModuleExecution(entryModules: Module[]) { analyseModule(dependency); } - for (const dynamicModule of module.dynamicImportResolutions) { - if ( - dynamicModule.resolution instanceof Module && - dynamicImports.indexOf(dynamicModule.resolution) === -1 - ) { - dynamicImports.push(dynamicModule.resolution); + for (const { resolution } of module.dynamicImports) { + if (resolution instanceof Module && dynamicImports.indexOf(resolution) === -1) { + dynamicImports.push(resolution); } } diff --git a/test/misc/bundle-information.js b/test/misc/bundle-information.js index bfeb5ffcc95..f332600bc9c 100644 --- a/test/misc/bundle-information.js +++ b/test/misc/bundle-information.js @@ -11,7 +11,7 @@ describe('The bundle object', () => { plugins: [ loader({ input1: 'import "shared";console.log("input1");export const out = true;', - input2: 'import "shared";console.log("input2");', + input2: 'import "shared";console.log("input2");export default 42', shared: 'console.log("shared");export const unused = null;' }) ] @@ -30,7 +30,7 @@ describe('The bundle object', () => { .map(key => output[key]); assert.deepEqual( sortedOutput.map(chunk => chunk.fileName), - ['generated-chunk-dc742c8f.js', 'input1-00b2c9b1.js', 'input2-815cf3ef.js'], + ['generated-chunk-dc742c8f.js', 'input1-00b2c9b1.js', 'input2-e2618782.js'], 'fileName' ); assert.deepEqual( @@ -38,7 +38,7 @@ describe('The bundle object', () => { [ 'console.log("shared");\n', `import './generated-chunk-dc742c8f.js';\n\nconsole.log("input1");const out = true;\n\nexport { out };\n`, - `import './generated-chunk-dc742c8f.js';\n\nconsole.log("input2");\n` + `import './generated-chunk-dc742c8f.js';\n\nconsole.log("input2");var input2 = 42;\n\nexport default input2;\n` ], 'code' ); @@ -59,7 +59,16 @@ describe('The bundle object', () => { [[], ['generated-chunk-dc742c8f.js'], ['generated-chunk-dc742c8f.js']], 'imports' ); - assert.deepEqual(sortedOutput.map(chunk => chunk.exports), [[], ['out'], []], 'exports'); + assert.deepEqual( + sortedOutput.map(chunk => chunk.dynamicImports), + [[], [], []], + 'dynamicImports' + ); + assert.deepEqual( + sortedOutput.map(chunk => chunk.exports), + [[], ['out'], ['default']], + 'exports' + ); assert.deepEqual( sortedOutput.map(chunk => chunk.modules), [ @@ -81,10 +90,10 @@ describe('The bundle object', () => { }, { input2: { - originalLength: 38, + originalLength: 55, removedExports: [], - renderedExports: [], - renderedLength: 22 + renderedExports: ['default'], + renderedLength: 38 } } ], @@ -183,8 +192,7 @@ describe('The bundle object', () => { experimentalCodeSplitting: true, plugins: [ loader({ - input: - `Promise.all([import('dynamic1'), import('dynamic2')]).then(([{dynamic1}, {dynamic2}]) => console.log(dynamic1, dynamic2));`, + input: `Promise.all([import('dynamic1'), import('dynamic2')]).then(([{dynamic1}, {dynamic2}]) => console.log(dynamic1, dynamic2));`, dynamic1: 'export const dynamic1 = "dynamic1"', dynamic2: 'export const dynamic2 = "dynamic2"' }) @@ -227,6 +235,11 @@ describe('The bundle object', () => { ['dynamic1', 'dynamic2', 'input'], 'facadeModuleId' ); + assert.deepEqual( + sortedOutput.map(chunk => chunk.dynamicImports), + [[], [], ['dynamic1.js', 'generated-chunk.js']], + 'dynamicImports' + ); }); }); @@ -276,6 +289,11 @@ describe('The bundle object', () => { [null, 'dynamic', 'input1', 'input2'], 'facadeModuleId' ); + assert.deepEqual( + sortedOutput.map(chunk => chunk.dynamicImports), + [[], [], ['generated-chunk.js'], []], + 'dynamicImports' + ); }); }); @@ -287,8 +305,7 @@ describe('The bundle object', () => { experimentalPreserveModules: true, plugins: [ loader({ - input: - `import {other} from "other";console.log(other);Promise.all([import('dynamic1'), import('dynamic2')]).then(([{dynamic1}, {dynamic2}]) => console.log(dynamic1, dynamic2));`, + input: `import {other} from "other";console.log(other);Promise.all([import('dynamic1'), import('dynamic2')]).then(([{dynamic1}, {dynamic2}]) => console.log(dynamic1, dynamic2));`, dynamic1: 'export const dynamic1 = "dynamic1"', dynamic2: 'export const dynamic2 = "dynamic2"', other: 'export const other = "other"' @@ -312,7 +329,11 @@ describe('The bundle object', () => { ['_virtual/dynamic1', '_virtual/dynamic2', '_virtual/input', '_virtual/other'], 'fileName' ); - assert.deepEqual(sortedOutput.map(chunk => chunk.isEntry), [true, false, true, false], 'isEntry'); + assert.deepEqual( + sortedOutput.map(chunk => chunk.isEntry), + [true, false, true, false], + 'isEntry' + ); assert.deepEqual( sortedOutput.map(chunk => chunk.code), [ @@ -335,7 +356,16 @@ console.log(other);Promise.all([import('./dynamic1'), import('./dynamic2')]).the [[], [], ['_virtual/other'], []], 'imports' ); - assert.deepEqual(sortedOutput.map(chunk => chunk.exports), [['dynamic1'], ['dynamic2'], [], ['other']], 'exports'); + assert.deepEqual( + sortedOutput.map(chunk => chunk.exports), + [['dynamic1'], ['dynamic2'], [], ['other']], + 'exports' + ); + assert.deepEqual( + sortedOutput.map(chunk => chunk.dynamicImports), + [[], [], ['_virtual/dynamic1', '_virtual/dynamic2'], []], + 'dynamicImports' + ); assert.deepEqual( sortedOutput.map(chunk => chunk.modules), [ From a9290dab66aa5ac9f1e98b1260e2fa295d40e376 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sun, 2 Dec 2018 20:28:35 +0100 Subject: [PATCH 22/23] Make "optimizeImports" an experimental option to reflect that the logic is complicated and may not have been properly tested in all situations. --- src/rollup/index.ts | 16 +++++++++------- src/rollup/types.d.ts | 2 +- src/utils/mergeOptions.ts | 2 +- .../samples/grouping-multiple/_config.js | 2 +- .../samples/grouping-size/_config.js | 2 +- .../inline-imports-with-optimize/_config.js | 4 ++-- .../preserve-modules-with-optimize/_config.js | 4 ++-- test/misc/optionList.js | 4 ++-- 8 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/rollup/index.ts b/src/rollup/index.ts index 4ca5e2f8c3a..ca40b8cae7c 100644 --- a/src/rollup/index.ts +++ b/src/rollup/index.ts @@ -117,10 +117,11 @@ function getInputOptions(rawInputOptions: GenericConfigObject): any { code: 'INVALID_OPTION', message: '"manualChunks" option is only supported for experimentalCodeSplitting.' }); - if (inputOptions.optimizeChunks) + if (inputOptions.experimentalOptimizeChunks) error({ code: 'INVALID_OPTION', - message: '"optimizeChunks" option is only supported for experimentalCodeSplitting.' + message: + '"experimentalOptimizeChunks" option is only supported for experimentalCodeSplitting.' }); if (inputOptions.input instanceof Array || typeof inputOptions.input === 'object') error({ @@ -141,10 +142,10 @@ function getInputOptions(rawInputOptions: GenericConfigObject): any { message: '"manualChunks" option is not supported for inlineDynamicImports.' }); - if (inputOptions.optimizeChunks) + if (inputOptions.experimentalOptimizeChunks) error({ code: 'INVALID_OPTION', - message: '"optimizeChunks" option is not supported for inlineDynamicImports.' + message: '"experimentalOptimizeChunks" option is not supported for inlineDynamicImports.' }); if (inputOptions.input instanceof Array || typeof inputOptions.input === 'object') error({ @@ -157,10 +158,11 @@ function getInputOptions(rawInputOptions: GenericConfigObject): any { code: 'INVALID_OPTION', message: 'experimentalPreserveModules does not support the manualChunks option.' }); - if (inputOptions.optimizeChunks) + if (inputOptions.experimentalOptimizeChunks) error({ code: 'INVALID_OPTION', - message: 'experimentalPreserveModules does not support the optimizeChunks option.' + message: + 'experimentalPreserveModules does not support the experimentalOptimizeChunks option.' }); } @@ -288,7 +290,7 @@ export default function rollup( for (const chunk of chunks) { chunk.preRender(outputOptions, inputBase); } - if (!optimized && inputOptions.optimizeChunks) { + if (!optimized && inputOptions.experimentalOptimizeChunks) { optimizeChunks(chunks, outputOptions, inputOptions.chunkGroupingSize, inputBase); optimized = true; } diff --git a/src/rollup/types.d.ts b/src/rollup/types.d.ts index 905ca54796c..354dd8e631a 100644 --- a/src/rollup/types.d.ts +++ b/src/rollup/types.d.ts @@ -242,7 +242,7 @@ export interface InputOptions { inlineDynamicImports?: boolean; preserveSymlinks?: boolean; experimentalPreserveModules?: boolean; - optimizeChunks?: boolean; + experimentalOptimizeChunks?: boolean; chunkGroupingSize?: number; shimMissingExports?: boolean; diff --git a/src/utils/mergeOptions.ts b/src/utils/mergeOptions.ts index dba8c27d8eb..37e96b45fae 100644 --- a/src/utils/mergeOptions.ts +++ b/src/utils/mergeOptions.ts @@ -212,7 +212,7 @@ function getInputOptions( input: getOption('input'), manualChunks: getOption('manualChunks'), chunkGroupingSize: getOption('chunkGroupingSize', 5000), - optimizeChunks: getOption('optimizeChunks'), + experimentalOptimizeChunks: getOption('experimentalOptimizeChunks'), moduleContext: config.moduleContext, onwarn: getOnWarn(config, command, defaultOnWarnHandler), perf: getOption('perf', false), diff --git a/test/chunking-form/samples/grouping-multiple/_config.js b/test/chunking-form/samples/grouping-multiple/_config.js index 8fba5c3a4e4..e3084e471c8 100644 --- a/test/chunking-form/samples/grouping-multiple/_config.js +++ b/test/chunking-form/samples/grouping-multiple/_config.js @@ -1,7 +1,7 @@ module.exports = { description: 'chunk grouping multiple chunks', options: { - optimizeChunks: true, + experimentalOptimizeChunks: true, chunkGroupingSize: 5000, input: ['main1.js', 'main2.js', 'main3.js'] } diff --git a/test/chunking-form/samples/grouping-size/_config.js b/test/chunking-form/samples/grouping-size/_config.js index 514d29cab28..3a662b0a187 100644 --- a/test/chunking-form/samples/grouping-size/_config.js +++ b/test/chunking-form/samples/grouping-size/_config.js @@ -1,7 +1,7 @@ module.exports = { description: 'chunk grouping size threshold', options: { - optimizeChunks: true, + experimentalOptimizeChunks: true, chunkGroupingSize: 42, input: ['main1.js', 'main2.js', 'main3.js'] } diff --git a/test/function/samples/inline-imports-with-optimize/_config.js b/test/function/samples/inline-imports-with-optimize/_config.js index 59f6f5b0f33..13b6aa67ad5 100644 --- a/test/function/samples/inline-imports-with-optimize/_config.js +++ b/test/function/samples/inline-imports-with-optimize/_config.js @@ -4,10 +4,10 @@ module.exports = { input: ['main.js'], experimentalCodeSplitting: true, inlineDynamicImports: true, - optimizeChunks: true + experimentalOptimizeChunks: true }, error: { code: 'INVALID_OPTION', - message: '"optimizeChunks" option is not supported for inlineDynamicImports.' + message: '"experimentalOptimizeChunks" option is not supported for inlineDynamicImports.' } }; diff --git a/test/function/samples/preserve-modules-with-optimize/_config.js b/test/function/samples/preserve-modules-with-optimize/_config.js index 56bdbf8a956..f93fc307106 100644 --- a/test/function/samples/preserve-modules-with-optimize/_config.js +++ b/test/function/samples/preserve-modules-with-optimize/_config.js @@ -4,10 +4,10 @@ module.exports = { input: ['main.js'], experimentalCodeSplitting: true, experimentalPreserveModules: true, - optimizeChunks: true + experimentalOptimizeChunks: true }, error: { code: 'INVALID_OPTION', - message: 'experimentalPreserveModules does not support the optimizeChunks option.' + message: 'experimentalPreserveModules does not support the experimentalOptimizeChunks option.' } }; diff --git a/test/misc/optionList.js b/test/misc/optionList.js index ef786cb1d18..4d6298aab5b 100644 --- a/test/misc/optionList.js +++ b/test/misc/optionList.js @@ -1,3 +1,3 @@ -exports.input = 'acorn, acornInjectPlugins, cache, chunkGroupingSize, context, entry, experimentalCacheExpiry, experimentalCodeSplitting, experimentalPreserveModules, experimentalTopLevelAwait, external, inlineDynamicImports, input, manualChunks, moduleContext, onwarn, optimizeChunks, perf, plugins, preferConst, preserveSymlinks, shimMissingExports, treeshake, watch'; -exports.flags = 'acorn, acornInjectPlugins, amd, assetFileNames, banner, c, cache, chunkFileNames, chunkGroupingSize, compact, config, context, dir, e, entry, entryFileNames, environment, esModule, experimentalCacheExpiry, experimentalCodeSplitting, experimentalPreserveModules, experimentalTopLevelAwait, exports, extend, external, f, file, footer, format, freeze, g, globals, h, i, indent, inlineDynamicImports, input, interop, intro, m, manualChunks, moduleContext, n, name, namespaceToStringTag, noConflict, o, onwarn, optimizeChunks, outro, paths, perf, plugins, preferConst, preserveSymlinks, shimMissingExports, silent, sourcemap, sourcemapExcludeSources, sourcemapFile, strict, treeshake, v, w, watch'; +exports.input = 'acorn, acornInjectPlugins, cache, chunkGroupingSize, context, entry, experimentalCacheExpiry, experimentalCodeSplitting, experimentalOptimizeChunks, experimentalPreserveModules, experimentalTopLevelAwait, external, inlineDynamicImports, input, manualChunks, moduleContext, onwarn, perf, plugins, preferConst, preserveSymlinks, shimMissingExports, treeshake, watch'; +exports.flags = 'acorn, acornInjectPlugins, amd, assetFileNames, banner, c, cache, chunkFileNames, chunkGroupingSize, compact, config, context, dir, e, entry, entryFileNames, environment, esModule, experimentalCacheExpiry, experimentalCodeSplitting, experimentalOptimizeChunks, experimentalPreserveModules, experimentalTopLevelAwait, exports, extend, external, f, file, footer, format, freeze, g, globals, h, i, indent, inlineDynamicImports, input, interop, intro, m, manualChunks, moduleContext, n, name, namespaceToStringTag, noConflict, o, onwarn, outro, paths, perf, plugins, preferConst, preserveSymlinks, shimMissingExports, silent, sourcemap, sourcemapExcludeSources, sourcemapFile, strict, treeshake, v, w, watch'; exports.output = 'amd, assetFileNames, banner, dir, chunkFileNames, compact, entryFileNames, esModule, exports, extend, file, footer, format, freeze, globals, indent, interop, intro, name, namespaceToStringTag, noConflict, outro, paths, sourcemap, sourcemapExcludeSources, sourcemapFile, sourcemapPathTransform, strict'; From ae2d4247f69ee3892b31a7594d14b21d13e9b092 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Mon, 3 Dec 2018 06:30:27 +0100 Subject: [PATCH 23/23] Make sure tree-shaken dynamic imports do not lead to the creation of namespace objects when inlined --- src/Chunk.ts | 10 ++++++---- .../_expected/amd/entryB.js | 2 +- .../_expected/amd/main1.js | 2 +- .../form/samples/default-identifier-deshadowing/dep.js | 2 +- .../inlined-treeshaken-dynamic-import/_config.js | 6 ++++++ .../inlined-treeshaken-dynamic-import/_expected/amd.js | 5 +++++ .../inlined-treeshaken-dynamic-import/_expected/cjs.js | 3 +++ .../inlined-treeshaken-dynamic-import/_expected/es.js | 1 + .../_expected/iife.js | 6 ++++++ .../_expected/system.js | 10 ++++++++++ .../inlined-treeshaken-dynamic-import/_expected/umd.js | 9 +++++++++ .../inlined-treeshaken-dynamic-import/dynamic.js | 2 ++ .../samples/inlined-treeshaken-dynamic-import/main.js | 2 ++ 13 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 test/form/samples/inlined-treeshaken-dynamic-import/_config.js create mode 100644 test/form/samples/inlined-treeshaken-dynamic-import/_expected/amd.js create mode 100644 test/form/samples/inlined-treeshaken-dynamic-import/_expected/cjs.js create mode 100644 test/form/samples/inlined-treeshaken-dynamic-import/_expected/es.js create mode 100644 test/form/samples/inlined-treeshaken-dynamic-import/_expected/iife.js create mode 100644 test/form/samples/inlined-treeshaken-dynamic-import/_expected/system.js create mode 100644 test/form/samples/inlined-treeshaken-dynamic-import/_expected/umd.js create mode 100644 test/form/samples/inlined-treeshaken-dynamic-import/dynamic.js create mode 100644 test/form/samples/inlined-treeshaken-dynamic-import/main.js diff --git a/src/Chunk.ts b/src/Chunk.ts index 6fb382d3280..a1e52a87fa6 100644 --- a/src/Chunk.ts +++ b/src/Chunk.ts @@ -248,10 +248,12 @@ export default class Chunk { const declaration = module.imports[importName]; this.traceAndInitializeImport(declaration.name, declaration.module); } - for (const { resolution } of module.dynamicImports) { - this.hasDynamicImport = true; - if (resolution instanceof Module && resolution.chunk === this) - resolution.getOrCreateNamespace().include(); + for (const { node, resolution } of module.dynamicImports) { + if (node.included) { + this.hasDynamicImport = true; + if (resolution instanceof Module && resolution.chunk === this) + resolution.getOrCreateNamespace().include(); + } } } diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/amd/entryB.js b/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/amd/entryB.js index ece2de9a3ae..b58286ca58e 100644 --- a/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/amd/entryB.js +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-1/_expected/amd/entryB.js @@ -1,4 +1,4 @@ -define(['require'], function (require) { 'use strict'; +define(function () { 'use strict'; console.log('main2'); diff --git a/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/amd/main1.js b/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/amd/main1.js index a2d15717cea..34f4f818070 100644 --- a/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/amd/main1.js +++ b/test/chunking-form/samples/dynamic-import-tree-shaking-2/_expected/amd/main1.js @@ -1,4 +1,4 @@ -define(['require'], function (require) { 'use strict'; +define(function () { 'use strict'; console.log('main1'); diff --git a/test/form/samples/default-identifier-deshadowing/dep.js b/test/form/samples/default-identifier-deshadowing/dep.js index 8349860b51a..1e617709bd7 100644 --- a/test/form/samples/default-identifier-deshadowing/dep.js +++ b/test/form/samples/default-identifier-deshadowing/dep.js @@ -1,4 +1,4 @@ export default function a() { a = someGlobal; return a(); -} \ No newline at end of file +} diff --git a/test/form/samples/inlined-treeshaken-dynamic-import/_config.js b/test/form/samples/inlined-treeshaken-dynamic-import/_config.js new file mode 100644 index 00000000000..b5257d549c5 --- /dev/null +++ b/test/form/samples/inlined-treeshaken-dynamic-import/_config.js @@ -0,0 +1,6 @@ +module.exports = { + description: 'completely removes tree-shaken dynamic imports ', + options: { + inlineDynamicImports: true + } +}; diff --git a/test/form/samples/inlined-treeshaken-dynamic-import/_expected/amd.js b/test/form/samples/inlined-treeshaken-dynamic-import/_expected/amd.js new file mode 100644 index 00000000000..126aa22ee83 --- /dev/null +++ b/test/form/samples/inlined-treeshaken-dynamic-import/_expected/amd.js @@ -0,0 +1,5 @@ +define(function () { 'use strict'; + + console.log('main'); + +}); diff --git a/test/form/samples/inlined-treeshaken-dynamic-import/_expected/cjs.js b/test/form/samples/inlined-treeshaken-dynamic-import/_expected/cjs.js new file mode 100644 index 00000000000..d0ed06d8c90 --- /dev/null +++ b/test/form/samples/inlined-treeshaken-dynamic-import/_expected/cjs.js @@ -0,0 +1,3 @@ +'use strict'; + +console.log('main'); diff --git a/test/form/samples/inlined-treeshaken-dynamic-import/_expected/es.js b/test/form/samples/inlined-treeshaken-dynamic-import/_expected/es.js new file mode 100644 index 00000000000..c0b933d7b56 --- /dev/null +++ b/test/form/samples/inlined-treeshaken-dynamic-import/_expected/es.js @@ -0,0 +1 @@ +console.log('main'); diff --git a/test/form/samples/inlined-treeshaken-dynamic-import/_expected/iife.js b/test/form/samples/inlined-treeshaken-dynamic-import/_expected/iife.js new file mode 100644 index 00000000000..d283cbce8ba --- /dev/null +++ b/test/form/samples/inlined-treeshaken-dynamic-import/_expected/iife.js @@ -0,0 +1,6 @@ +(function () { + 'use strict'; + + console.log('main'); + +}()); diff --git a/test/form/samples/inlined-treeshaken-dynamic-import/_expected/system.js b/test/form/samples/inlined-treeshaken-dynamic-import/_expected/system.js new file mode 100644 index 00000000000..ba798b19101 --- /dev/null +++ b/test/form/samples/inlined-treeshaken-dynamic-import/_expected/system.js @@ -0,0 +1,10 @@ +System.register([], function (exports, module) { + 'use strict'; + return { + execute: function () { + + console.log('main'); + + } + }; +}); diff --git a/test/form/samples/inlined-treeshaken-dynamic-import/_expected/umd.js b/test/form/samples/inlined-treeshaken-dynamic-import/_expected/umd.js new file mode 100644 index 00000000000..41674034421 --- /dev/null +++ b/test/form/samples/inlined-treeshaken-dynamic-import/_expected/umd.js @@ -0,0 +1,9 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory() : + typeof define === 'function' && define.amd ? define(factory) : + (factory()); +}(this, (function () { 'use strict'; + + console.log('main'); + +}))); diff --git a/test/form/samples/inlined-treeshaken-dynamic-import/dynamic.js b/test/form/samples/inlined-treeshaken-dynamic-import/dynamic.js new file mode 100644 index 00000000000..1d7a1acc1b8 --- /dev/null +++ b/test/form/samples/inlined-treeshaken-dynamic-import/dynamic.js @@ -0,0 +1,2 @@ +console.log('dynamic'); +export var dynamic = 42; diff --git a/test/form/samples/inlined-treeshaken-dynamic-import/main.js b/test/form/samples/inlined-treeshaken-dynamic-import/main.js new file mode 100644 index 00000000000..9b0aad2c210 --- /dev/null +++ b/test/form/samples/inlined-treeshaken-dynamic-import/main.js @@ -0,0 +1,2 @@ +console.log('main'); +const getFoo = () => import('./dynamic.js');