Skip to content

Commit

Permalink
Support emitting files via manualChunks in output (#4761)
Browse files Browse the repository at this point in the history
  • Loading branch information
lukastaegert committed Dec 22, 2022
1 parent 7182a92 commit d750ef2
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 8 deletions.
43 changes: 35 additions & 8 deletions src/utils/FileEmitter.ts
Expand Up @@ -160,6 +160,7 @@ export class FileEmitter {
private readonly filesByReferenceId: Map<string, ConsumedFile>;
private nextIdBase = 1;
private output: FileEmitterOutput | null = null;
private outputFileEmitters: FileEmitter[] = [];

constructor(
private readonly graph: Graph,
Expand All @@ -169,6 +170,7 @@ export class FileEmitter {
this.filesByReferenceId = baseFileEmitter
? new Map(baseFileEmitter.filesByReferenceId)
: new Map();
baseFileEmitter?.addOutputFileEmitter(this);
}

public emitFile = (emittedFile: unknown): string => {
Expand Down Expand Up @@ -230,6 +232,9 @@ export class FileEmitter {
this.finalizeAsset(consumedFile, source, referenceId, this.output);
} else {
consumedFile.source = source;
for (const emitter of this.outputFileEmitters) {
emitter.finalizeAsset(consumedFile, source, referenceId, emitter.output!);
}
}
};

Expand All @@ -255,6 +260,10 @@ export class FileEmitter {
}
};

private addOutputFileEmitter(outputFileEmitter: FileEmitter) {
this.outputFileEmitters.push(outputFileEmitter);
}

private assignReferenceId(file: ConsumedFile, idBase: string): string {
let referenceId: string | undefined;

Expand All @@ -263,9 +272,14 @@ export class FileEmitter {
.update(referenceId || idBase)
.digest('hex')
.slice(0, 8);
} while (this.filesByReferenceId.has(referenceId));

} while (
this.filesByReferenceId.has(referenceId) ||
this.outputFileEmitters.some(({ filesByReferenceId }) => filesByReferenceId.has(referenceId!))
);
this.filesByReferenceId.set(referenceId, file);
for (const { filesByReferenceId } of this.outputFileEmitters) {
filesByReferenceId.set(referenceId, file);
}
return referenceId;
}

Expand All @@ -285,16 +299,29 @@ export class FileEmitter {
emittedAsset.fileName || emittedAsset.name || String(this.nextIdBase++)
);
if (this.output) {
if (emittedAsset.fileName) {
reserveFileNameInBundle(emittedAsset.fileName, this.output, this.options.onwarn);
}
if (source !== undefined) {
this.finalizeAsset(consumedAsset, source, referenceId, this.output);
this.emitAssetWithReferenceId(consumedAsset, referenceId, this.output);
} else {
for (const fileEmitter of this.outputFileEmitters) {
fileEmitter.emitAssetWithReferenceId(consumedAsset, referenceId, fileEmitter.output!);
}
}
return referenceId;
}

private emitAssetWithReferenceId(
consumedAsset: Readonly<ConsumedAsset>,
referenceId: string,
output: FileEmitterOutput
) {
const { fileName, source } = consumedAsset;
if (fileName) {
reserveFileNameInBundle(fileName, output, this.options.onwarn);
}
if (source !== undefined) {
this.finalizeAsset(consumedAsset, source, referenceId, output);
}
}

private emitChunk(emittedChunk: EmittedFile): string {
if (this.graph.phase > BuildPhase.LOAD_AND_PARSE) {
return error(errorInvalidRollupPhaseForChunkEmission());
Expand Down Expand Up @@ -324,7 +351,7 @@ export class FileEmitter {
}

private finalizeAsset(
consumedFile: ConsumedFile,
consumedFile: Readonly<ConsumedFile>,
source: string | Uint8Array,
referenceId: string,
{ bundle, fileNamesBySource, outputOptions }: FileEmitterOutput
Expand Down
27 changes: 27 additions & 0 deletions test/function/samples/emit-chunk-manual-asset-source/_config.js
@@ -0,0 +1,27 @@
const assert = require('node:assert');
let referenceId;

module.exports = {
description: 'supports setting asset sources as side effect of the manual chunks option',
options: {
output: {
manualChunks: { foo: ['manual.js'] },
assetFileNames: '[name]-[hash][extname]'
},
plugins: {
transform(code, id) {
if (id.endsWith('manual.js')) {
referenceId = this.emitFile({ type: 'asset', name: 'emitted.txt' });
}
},
moduleParsed({ id }) {
if (id.endsWith('manual.js')) {
this.setAssetSource(referenceId, 'emitted');
}
},
generateBundle() {
assert.strictEqual(this.getFileName(referenceId), 'emitted-f57bfbce.txt');
}
}
}
};
@@ -0,0 +1 @@
assert.ok(true);
@@ -0,0 +1 @@
import './main';
22 changes: 22 additions & 0 deletions test/function/samples/emit-chunk-manual/_config.js
@@ -0,0 +1,22 @@
const assert = require('node:assert');
let referenceId;

module.exports = {
description: 'supports emitting chunks as side effect of the manual chunks option',
options: {
output: {
manualChunks: { foo: ['manual.js'] },
assetFileNames: '[name]-[hash][extname]'
},
plugins: {
transform(code, id) {
if (id.endsWith('manual.js')) {
referenceId = this.emitFile({ type: 'asset', name: 'emitted.txt', source: 'emitted' });
}
},
generateBundle() {
assert.strictEqual(this.getFileName(referenceId), 'emitted-f57bfbce.txt');
}
}
}
};
1 change: 1 addition & 0 deletions test/function/samples/emit-chunk-manual/main.js
@@ -0,0 +1 @@
assert.ok(true);
1 change: 1 addition & 0 deletions test/function/samples/emit-chunk-manual/manual.js
@@ -0,0 +1 @@
import './main';

0 comments on commit d750ef2

Please sign in to comment.