Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Compact output mode #2151

Merged
merged 14 commits into from
May 22, 2018
31 changes: 21 additions & 10 deletions src/Chunk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ export default class Chunk {

generateInternalExports(options: OutputOptions) {
if (this.isEntryModuleFacade) return;
const mangle = options.format === 'system' || options.format === 'es';
const mangle = options.format === 'system' || options.format === 'es' || options.compact;
let i = 0,
safeExportName: string;
this.exportNames = Object.create(null);
Expand Down Expand Up @@ -726,13 +726,16 @@ export default class Chunk {
preRender(options: OutputOptions, inputBase: string) {
timeStart('render modules', 3);

let magicString = new MagicStringBundle({ separator: '\n\n' });
let magicString = new MagicStringBundle({ separator: options.compact ? '' : '\n\n' });
this.usedModules = [];
this.indentString = getIndentString(this.orderedModules, options);
this.indentString = options.compact ? '' : getIndentString(this.orderedModules, options);

const n = options.compact ? '' : '\n';

if (this.graph.dynamicImport) this.prepareDynamicImports();

const renderOptions: RenderOptions = {
compact: options.compact,
legacy: options.legacy,
freeze: options.freeze !== false,
namespaceToStringTag: options.namespaceToStringTag === true,
Expand Down Expand Up @@ -770,9 +773,11 @@ export default class Chunk {

this.renderedModuleSources = [];

for (const module of this.orderedModules) {
for (let i = 0; i < this.orderedModules.length; i++) {
const module = this.orderedModules[i];
const source = module.render(renderOptions);
source.trim();
if (options.compact && source.lastLine().indexOf('//') !== -1) source.append('\n');
this.renderedModuleSources.push(source);

const namespace = module.getOrCreateNamespace();
Expand All @@ -782,15 +787,20 @@ export default class Chunk {

if (namespace.needsNamespaceBlock) {
const rendered = namespace.renderBlock(renderOptions);
if (namespace.renderFirst()) hoistedSource += '\n' + rendered;
if (namespace.renderFirst()) hoistedSource += n + rendered;
else magicString.addSource(new MagicString(rendered));
}
}
}

if (hoistedSource) magicString.prepend(hoistedSource + '\n\n');
if (hoistedSource) magicString.prepend(hoistedSource + n + n);

if (options.compact) {
this.renderedSource = magicString;
} else {
this.renderedSource = magicString.trim();
}

this.renderedSource = magicString.trim();
this.renderedSourceLength = undefined;
this.renderedHash = undefined;

Expand Down Expand Up @@ -1020,8 +1030,8 @@ export default class Chunk {
},
options
);
if (addons.banner) magicString.prepend(addons.banner + '\n');
if (addons.footer) magicString.append('\n' + addons.footer);
if (addons.banner) magicString.prepend(addons.banner);
if (addons.footer) magicString.append(addons.footer);
const prevCode = magicString.toString();

timeEnd('render format', 3);
Expand Down Expand Up @@ -1060,7 +1070,8 @@ export default class Chunk {
timeEnd('sourcemap', 3);
}

if (code[code.length - 1] !== '\n') code += '\n';
if (options.compact !== true && code[code.length - 1] !== '\n') code += '\n';

return { code, map };
}
);
Expand Down
4 changes: 3 additions & 1 deletion src/Module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import ImportSpecifier from './ast/nodes/ImportSpecifier';
import Graph from './Graph';
import Variable from './ast/variables/Variable';
import Program from './ast/nodes/Program';
import { GenericEsTreeNode, Node, NodeBase } from './ast/nodes/shared/Node';
import { GenericEsTreeNode, Node, NodeBase, StatementNode } from './ast/nodes/shared/Node';
import ExportNamedDeclaration from './ast/nodes/ExportNamedDeclaration';
import ImportDeclaration from './ast/nodes/ImportDeclaration';
import Identifier from './ast/nodes/Identifier';
Expand All @@ -35,6 +35,8 @@ import { isLiteral } from './ast/nodes/Literal';
import Chunk from './Chunk';
import { RenderOptions } from './utils/renderHelpers';
import { getOriginalLocation } from './utils/getOriginalLocation';
import VariableDeclaration from './ast/nodes/VariableDeclaration';
import ExpressionStatement from './ast/nodes/ExpressionStatement';

export interface CommentDescription {
block: boolean;
Expand Down
8 changes: 7 additions & 1 deletion src/ast/nodes/ExportDefaultDeclaration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,14 @@ export default class ExportDefaultDeclaration extends NodeBase {
declarationStart,
`${this.context.varOrConst} ${this.variable.getName()} = ${systemBinding}`
);
const hasTrailingSemicolon = code.original.charCodeAt(this.end - 1) === 59; /*";"*/
if (systemBinding) {
code.appendLeft(code.original[this.end - 1] === ';' ? this.end - 1 : this.end, ')');
code.appendLeft(
hasTrailingSemicolon ? this.end - 1 : this.end,
')' + (hasTrailingSemicolon ? '' : ';')
);
} else if (!hasTrailingSemicolon) {
code.appendLeft(this.end, ';');
}
}
}
Expand Down
57 changes: 35 additions & 22 deletions src/ast/nodes/Import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,34 @@ interface DynamicImportMechanism {
interopRight?: string;
}

const dynamicImportMechanisms: Record<string, DynamicImportMechanism> = {
es: undefined,
cjs: {
left: 'Promise.resolve(require(',
right: '))',
interopLeft: 'Promise.resolve({ default: require(',
interopRight: ') })'
},
amd: {
left: 'new Promise(function (resolve, reject) { require([',
right: '], resolve, reject) })',
interopLeft: 'new Promise(function (resolve, reject) { require([',
interopRight: '], function (m) { resolve({ default: m }) }, reject) })'
},
system: {
left: 'module.import(',
right: ')'
},
umd: undefined,
iife: undefined
const getDynamicImportMechanism = (format: string, compact: boolean): DynamicImportMechanism => {
switch (format) {
case 'cjs': {
const _ = compact ? '' : ' ';
return {
left: 'Promise.resolve(require(',
right: '))',
interopLeft: `Promise.resolve({${_}default:${_}require(`,
interopRight: `)${_}})`
};
}
case 'amd': {
const _ = compact ? '' : ' ';
const resolve = compact ? 'c' : 'resolve';
const reject = compact ? 'e' : 'reject';
return {
left: `new Promise(function${_}(${resolve},${_}${reject})${_}{${_}require([`,
right: `],${_}${resolve},${_}${reject})${_}})`,
interopLeft: `new Promise(function${_}(${resolve},${_}${reject})${_}{${_}require([`,
interopRight: `],${_}function${_}(m)${_}{${_}${resolve}({${_}default:${_}m${_}})${_}},${_}${reject})${_}})`
};
}
case 'system':
return {
left: 'module.import(',
right: ')'
};
}
};

export default class Import extends NodeBase {
Expand All @@ -56,17 +64,22 @@ export default class Import extends NodeBase {
}

render(code: MagicString, options: RenderOptions) {
const _ = options.compact ? '' : ' ';
const s = options.compact ? '' : ';';

this.rendered = true;
if (this.resolutionNamespace) {
const _ = options.compact ? '' : ' ';
const s = options.compact ? '' : ';';
code.overwrite(
this.parent.start,
this.parent.end,
`Promise.resolve().then(function () { return ${this.resolutionNamespace}; })`
`Promise.resolve().then(function${_}()${_}{${_}return ${this.resolutionNamespace}${s}${_}})`
);
return;
}

const importMechanism = dynamicImportMechanisms[options.format];
const importMechanism = getDynamicImportMechanism(options.format, options.compact);
if (importMechanism) {
const leftMechanism =
(this.resolutionInterop && importMechanism.interopLeft) || importMechanism.left;
Expand Down
32 changes: 19 additions & 13 deletions src/ast/variables/NamespaceVariable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,41 +47,47 @@ export default class NamespaceVariable extends Variable {
}

renderBlock(options: RenderOptions) {
const _ = options.compact ? '' : ' ';
const n = options.compact ? '' : '\n';
const t = options.indent;

const members = Object.keys(this.originals).map(name => {
const original = this.originals[name];

if ((this.referencedEarly || original.isReassigned) && !options.legacy) {
return `${options.indent}get ${name} () { return ${original.getName()}; }`;
return `${t}get ${name}${_}()${_}{${_}return ${original.getName()}${
options.compact ? '' : ';'
}${_}}`;
}

if (options.legacy && reservedWords.indexOf(name) !== -1) name = `'${name}'`;
return `${options.indent}${name}: ${original.getName()}`;
return `${t}${name}: ${original.getName()}`;
});

const name = this.getName();

const callee = options.freeze
? `/*#__PURE__*/${options.legacy ? `(Object.freeze || Object)` : `Object.freeze`}`
? `/*#__PURE__*/${options.legacy ? `(Object.freeze${_}||${_}Object)` : `Object.freeze`}`
: '';

let output = `${this.context.varOrConst} ${name} = ${
options.namespaceToStringTag
? `{\n${members.join(',\n')}\n};`
: `${callee}({\n${members.join(',\n')}\n});`
? `{${n}${members.join(`,${n}`)}${n}};`
: `${callee}({${n}${members.join(`,${n}`)}${n}});`
}`;

if (options.namespaceToStringTag) {
output += `\nif (typeof Symbol !== 'undefined' && Symbol.toStringTag)
${options.indent}Object.defineProperty(${name}, Symbol.toStringTag, { value: 'Module' });
else
${
options.indent
}Object.defineProperty(${name}, 'toString', { value: function () { return '[object Module]' } });
${callee}(${name});`;
output += `${n}if${_}(typeof Symbol${_}!==${_}'undefined'${_}&&${_}Symbol.toStringTag)${n}`;
output += `${t}Object.defineProperty(${name},${_}Symbol.toStringTag,${_}{${_}value:${_}'Module'${_}});${n}`;
output += `else${n || ' '}`;
output += `${t}Object.defineProperty(${name},${_}'toString',${_}{${_}value:${_}function${_}()${_}{${_}return${_}'[object Module]'${
options.compact ? ';' : ''
}${_}}${_}});${n}`;
output += `${callee}(${name});`;
}

if (options.format === 'system' && this.exportName) {
output += `\nexports('${this.exportName}', ${name});`;
output += `${n}exports('${this.exportName}',${_}${name});`;
}

return output;
Expand Down
29 changes: 20 additions & 9 deletions src/finalisers/amd.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import getInteropBlock from './shared/getInteropBlock';
import getExportBlock from './shared/getExportBlock';
import esModuleExport from './shared/esModuleExport';
import { esModuleExport, compactEsModuleExport } from './shared/esModuleExport';
import warnOnBuiltins from './shared/warnOnBuiltins';
import { Bundle as MagicStringBundle } from 'magic-string';
import { OutputOptions } from '../rollup/types';
Expand All @@ -27,6 +27,8 @@ export default function amd(

const deps = dependencies.map(m => `'${m.id}'`);
const args = dependencies.map(m => m.name);
const n = options.compact ? '' : '\n';
const _ = options.compact ? '' : ' ';

if (namedExportsMode && hasExports) {
args.unshift(`exports`);
Expand All @@ -46,26 +48,35 @@ export default function amd(
const amdOptions = options.amd || {};

const params =
(amdOptions.id ? `'${amdOptions.id}', ` : ``) + (deps.length ? `[${deps.join(', ')}], ` : ``);
(amdOptions.id ? `'${amdOptions.id}',${_}` : ``) +
(deps.length ? `[${deps.join(`,${_}`)}],${_}` : ``);

const useStrict = options.strict !== false ? ` 'use strict';` : ``;
const useStrict = options.strict !== false ? `${_}'use strict';` : ``;
const define = amdOptions.define || 'define';
const wrapperStart = `${define}(${params}function (${args.join(', ')}) {${useStrict}\n\n`;
const wrapperStart = `${define}(${params}function${_}(${args.join(
`,${_}`
)})${_}{${useStrict}${n}${n}`;

// var foo__default = 'default' in foo ? foo['default'] : foo;
const interopBlock = getInteropBlock(dependencies, options, graph.varOrConst);
if (interopBlock) magicString.prepend(interopBlock + '\n\n');
if (interopBlock) magicString.prepend(interopBlock + n + n);

if (intro) magicString.prepend(intro);

const exportBlock = getExportBlock(exports, dependencies, namedExportsMode, options.interop);
if (exportBlock) magicString.append('\n\n' + exportBlock);
const exportBlock = getExportBlock(
exports,
dependencies,
namedExportsMode,
options.interop,
options.compact
);
if (exportBlock) magicString.append(n + n + exportBlock);
if (namedExportsMode && hasExports && options.legacy !== true && isEntryModuleFacade)
magicString.append(`\n\n${esModuleExport}`);
magicString.append(`${n}${n}${options.compact ? compactEsModuleExport : esModuleExport}`);
if (outro) magicString.append(outro);

return magicString
.indent(indentString)
.append('\n\n});')
.append(n + n + '});')
.prepend(wrapperStart);
}