Skip to content

Commit

Permalink
Refactor use async control flow (#3053)
Browse files Browse the repository at this point in the history
* Minor refactoring: Remove one try-catch

* Use async control flow in place of .then() chain

* Restore some .then()s to fix the tests

* Pass err from 'buildStart' hook to 'buildEnd'

* Convert another promise chain into async try/catch

* Convert another promise chain to async control flow
  • Loading branch information
KSXGitHub authored and lukastaegert committed Aug 15, 2019
1 parent 5979144 commit f0b429c
Showing 1 changed file with 140 additions and 150 deletions.
290 changes: 140 additions & 150 deletions src/rollup/index.ts
Expand Up @@ -188,162 +188,152 @@ export default async function rollup(rawInputOptions: GenericConfigObject): Prom

timeStart('BUILD', 1);

return graph.pluginDriver
.hookParallel('buildStart', [inputOptions])
.then(() =>
graph.build(
inputOptions.input as string | string[] | Record<string, string>,
inputOptions.manualChunks,
inputOptions.inlineDynamicImports as boolean
)
)
.then(
chunks => graph.pluginDriver.hookParallel('buildEnd', []).then(() => chunks),
err =>
graph.pluginDriver.hookParallel('buildEnd', [err]).then(() => {
throw err;
})
)
.then(chunks => {
timeEnd('BUILD', 1);

// ensure we only do one optimization pass per build
let optimized = false;

function getOutputOptions(rawOutputOptions: GenericConfigObject) {
return normalizeOutputOptions(
inputOptions as GenericConfigObject,
rawOutputOptions,
chunks.length > 1,
graph.pluginDriver
);
}
let chunks: Chunk[];

try {
await graph.pluginDriver.hookParallel('buildStart', [inputOptions]);
chunks = await graph.build(
inputOptions.input as string | string[] | Record<string, string>,
inputOptions.manualChunks,
inputOptions.inlineDynamicImports as boolean
);
} catch (err) {
await graph.pluginDriver.hookParallel('buildEnd', [err]);
throw err;
}

async function generate(
outputOptions: OutputOptions,
isWrite: boolean
): Promise<OutputBundle> {
timeStart('GENERATE', 1);

const assetFileNames = outputOptions.assetFileNames || 'assets/[name]-[hash][extname]';
const outputBundleWithPlaceholders: OutputBundleWithPlaceholders = Object.create(null);
let outputBundle;
const inputBase = commondir(getAbsoluteEntryModulePaths(chunks));
graph.pluginDriver.startOutput(outputBundleWithPlaceholders, assetFileNames);

try {
await graph.pluginDriver.hookParallel('renderStart', []);
const addons = await createAddons(graph, outputOptions);
for (const chunk of chunks) {
if (!inputOptions.preserveModules) chunk.generateInternalExports(outputOptions);
if (chunk.facadeModule && chunk.facadeModule.isEntryPoint)
chunk.exportMode = getExportMode(chunk, outputOptions);
}
for (const chunk of chunks) {
chunk.preRender(outputOptions, inputBase);
}
if (!optimized && inputOptions.experimentalOptimizeChunks) {
optimizeChunks(
chunks,
outputOptions,
inputOptions.chunkGroupingSize as number,
inputBase
);
optimized = true;
}
assignChunkIds(
chunks,
inputOptions,
outputOptions,
inputBase,
addons,
outputBundleWithPlaceholders
);
outputBundle = assignChunksToBundle(chunks, outputBundleWithPlaceholders);

await Promise.all(
chunks.map(chunk => {
const outputChunk = outputBundleWithPlaceholders[chunk.id as string] as OutputChunk;
return chunk.render(outputOptions, addons, outputChunk).then(rendered => {
outputChunk.code = rendered.code;
outputChunk.map = rendered.map;

return graph.pluginDriver.hookParallel('ongenerate', [
{ bundle: outputChunk, ...outputOptions },
outputChunk
]);
});
})
);
} catch (error) {
await graph.pluginDriver.hookParallel('renderError', [error]);
throw error;
}
await graph.pluginDriver.hookSeq('generateBundle', [outputOptions, outputBundle, isWrite]);
graph.pluginDriver.finaliseAssets();
await graph.pluginDriver.hookParallel('buildEnd', []);

timeEnd('BUILD', 1);

// ensure we only do one optimization pass per build
let optimized = false;

function getOutputOptions(rawOutputOptions: GenericConfigObject) {
return normalizeOutputOptions(
inputOptions as GenericConfigObject,
rawOutputOptions,
chunks.length > 1,
graph.pluginDriver
);
}

timeEnd('GENERATE', 1);
return outputBundle;
async function generate(outputOptions: OutputOptions, isWrite: boolean): Promise<OutputBundle> {
timeStart('GENERATE', 1);

const assetFileNames = outputOptions.assetFileNames || 'assets/[name]-[hash][extname]';
const outputBundleWithPlaceholders: OutputBundleWithPlaceholders = Object.create(null);
let outputBundle;
const inputBase = commondir(getAbsoluteEntryModulePaths(chunks));
graph.pluginDriver.startOutput(outputBundleWithPlaceholders, assetFileNames);

try {
await graph.pluginDriver.hookParallel('renderStart', []);
const addons = await createAddons(graph, outputOptions);
for (const chunk of chunks) {
if (!inputOptions.preserveModules) chunk.generateInternalExports(outputOptions);
if (chunk.facadeModule && chunk.facadeModule.isEntryPoint)
chunk.exportMode = getExportMode(chunk, outputOptions);
}
for (const chunk of chunks) {
chunk.preRender(outputOptions, inputBase);
}
if (!optimized && inputOptions.experimentalOptimizeChunks) {
optimizeChunks(chunks, outputOptions, inputOptions.chunkGroupingSize as number, inputBase);
optimized = true;
}
assignChunkIds(
chunks,
inputOptions,
outputOptions,
inputBase,
addons,
outputBundleWithPlaceholders
);
outputBundle = assignChunksToBundle(chunks, outputBundleWithPlaceholders);

await Promise.all(
chunks.map(chunk => {
const outputChunk = outputBundleWithPlaceholders[chunk.id as string] as OutputChunk;
return chunk.render(outputOptions, addons, outputChunk).then(rendered => {
outputChunk.code = rendered.code;
outputChunk.map = rendered.map;

return graph.pluginDriver.hookParallel('ongenerate', [
{ bundle: outputChunk, ...outputOptions },
outputChunk
]);
});
})
);
} catch (error) {
await graph.pluginDriver.hookParallel('renderError', [error]);
throw error;
}
await graph.pluginDriver.hookSeq('generateBundle', [outputOptions, outputBundle, isWrite]);
graph.pluginDriver.finaliseAssets();

timeEnd('GENERATE', 1);
return outputBundle;
}

const cache = useCache ? graph.getCache() : undefined;
const result: RollupBuild = {
cache: cache as RollupCache,
generate: ((rawOutputOptions: GenericConfigObject) => {
const promise = generate(getOutputOptions(rawOutputOptions), false).then(result =>
createOutput(result)
);
Object.defineProperty(promise, 'code', throwAsyncGenerateError);
Object.defineProperty(promise, 'map', throwAsyncGenerateError);
return promise;
}) as any,
watchFiles: Object.keys(graph.watchFiles),
write: ((rawOutputOptions: GenericConfigObject) => {
const outputOptions = getOutputOptions(rawOutputOptions);
if (!outputOptions.dir && !outputOptions.file) {
const cache = useCache ? graph.getCache() : undefined;
const result: RollupBuild = {
cache: cache as RollupCache,
generate: ((rawOutputOptions: GenericConfigObject) => {
const promise = generate(getOutputOptions(rawOutputOptions), false).then(result =>
createOutput(result)
);
Object.defineProperty(promise, 'code', throwAsyncGenerateError);
Object.defineProperty(promise, 'map', throwAsyncGenerateError);
return promise;
}) as any,
watchFiles: Object.keys(graph.watchFiles),
write: ((rawOutputOptions: GenericConfigObject) => {
const outputOptions = getOutputOptions(rawOutputOptions);
if (!outputOptions.dir && !outputOptions.file) {
error({
code: 'MISSING_OPTION',
message: 'You must specify "output.file" or "output.dir" for the build.'
});
}
return generate(outputOptions, true).then(async bundle => {
let chunkCnt = 0;
for (const fileName of Object.keys(bundle)) {
const file = bundle[fileName];
if ((file as OutputAsset).isAsset) continue;
chunkCnt++;
if (chunkCnt > 1) break;
}
if (chunkCnt > 1) {
if (outputOptions.sourcemapFile)
error({
code: 'MISSING_OPTION',
message: 'You must specify "output.file" or "output.dir" for the build.'
code: 'INVALID_OPTION',
message: '"output.sourcemapFile" is only supported for single-file builds.'
});
}
return generate(outputOptions, true).then(bundle => {
let chunkCnt = 0;
for (const fileName of Object.keys(bundle)) {
const file = bundle[fileName];
if ((file as OutputAsset).isAsset) continue;
chunkCnt++;
if (chunkCnt > 1) break;
}
if (chunkCnt > 1) {
if (outputOptions.sourcemapFile)
error({
code: 'INVALID_OPTION',
message: '"output.sourcemapFile" is only supported for single-file builds.'
});
if (typeof outputOptions.file === 'string')
error({
code: 'INVALID_OPTION',
message:
'When building multiple chunks, the "output.dir" option must be used, not "output.file".' +
(typeof inputOptions.input !== 'string' ||
inputOptions.inlineDynamicImports === true
? ''
: ' To inline dynamic imports, set the "inlineDynamicImports" option.')
});
}
return Promise.all(
Object.keys(bundle).map(chunkId =>
writeOutputFile(graph, result, bundle[chunkId], outputOptions)
)
)
.then(() => graph.pluginDriver.hookParallel('writeBundle', [bundle]))
.then(() => createOutput(bundle));
});
}) as any
};
if (inputOptions.perf === true) result.getTimings = getTimings;
return result;
});
if (typeof outputOptions.file === 'string')
error({
code: 'INVALID_OPTION',
message:
'When building multiple chunks, the "output.dir" option must be used, not "output.file".' +
(typeof inputOptions.input !== 'string' ||
inputOptions.inlineDynamicImports === true
? ''
: ' To inline dynamic imports, set the "inlineDynamicImports" option.')
});
}
await Promise.all(
Object.keys(bundle).map(chunkId =>
writeOutputFile(graph, result, bundle[chunkId], outputOptions)
)
);
await graph.pluginDriver.hookParallel('writeBundle', [bundle]);
return createOutput(bundle);
});
}) as any
};
if (inputOptions.perf === true) result.getTimings = getTimings;
return result;
}

enum SortingFileType {
Expand Down

0 comments on commit f0b429c

Please sign in to comment.