Skip to content

Commit

Permalink
Fix double tags when writing html entrypoint twice.
Browse files Browse the repository at this point in the history
  • Loading branch information
krisselden committed Apr 19, 2022
1 parent 1ad9334 commit 652087e
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 12 deletions.
70 changes: 59 additions & 11 deletions packages/webpack/src/ember-webpack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,44 @@ function equalAppInfo(left: AppInfo, right: AppInfo): boolean {
);
}

type BeginFn = (total: number) => void;
type IncrementFn = () => Promise<void>;

function createBarrier(): [BeginFn, IncrementFn] {
const barriers: Array<[() => void, (e: unknown) => void]> = [];
let done = true;
let limit = 0;
return [begin, increment];

function begin(newLimit: number) {
if (!done) flush(new Error('begin called before limit reached'));
done = false;
limit = newLimit;
}

async function increment() {
if (done) {
throw new Error('increment after limit reach');
}
const promise = new Promise<void>((resolve, reject) => {
barriers.push([resolve, reject]);
});
if (barriers.length === limit) {
flush();
}
await promise;
}

function flush(err?: Error) {
for (const [resolve, reject] of barriers) {
if (err) reject(err);
else resolve();
}
barriers.length = 0;
done = true;
}
}

// we want to ensure that not only does our instance conform to
// PackagerInstance, but our constructor conforms to Packager. So instead of
// just exporting our class directly, we export a const constructor of the
Expand All @@ -77,6 +115,8 @@ const Webpack: PackagerConstructor<Options> = class Webpack implements Packager
private extraCssLoaderOptions: object | undefined;
private extraStyleLoaderOptions: object | undefined;
private _bundleSummary: BundleSummary | undefined;
private beginBarrier: BeginFn;
private incrementBarrier: IncrementFn;

constructor(
pathToVanillaApp: string,
Expand All @@ -96,6 +136,7 @@ const Webpack: PackagerConstructor<Options> = class Webpack implements Packager
this.extraBabelLoaderOptions = options?.babelLoaderOptions;
this.extraCssLoaderOptions = options?.cssLoaderOptions;
this.extraStyleLoaderOptions = options?.styleLoaderOptions;
[this.beginBarrier, this.incrementBarrier] = createBarrier();
warmUp(this.extraThreadLoaderOptions);
}

Expand All @@ -113,6 +154,7 @@ const Webpack: PackagerConstructor<Options> = class Webpack implements Packager

async build(): Promise<void> {
this._bundleSummary = undefined;
this.beginBarrier(this.variants.length);
let appInfo = this.examineApp();
let webpack = this.getWebpack(appInfo);
await this.runWebpack(webpack);
Expand Down Expand Up @@ -162,7 +204,7 @@ const Webpack: PackagerConstructor<Options> = class Webpack implements Packager
compiler => {
compiler.hooks.done.tapPromise('EmbroiderPlugin', async stats => {
this.summarizeStats(stats, variant, variantIndex);
await this.writeFiles(this.bundleSummary, appInfo);
await this.writeFiles(this.bundleSummary, appInfo, variantIndex);
});
},
],
Expand Down Expand Up @@ -313,7 +355,7 @@ const Webpack: PackagerConstructor<Options> = class Webpack implements Packager
}
}

private async writeFiles(stats: BundleSummary, { entrypoints, otherAssets }: AppInfo) {
private async writeFiles(stats: BundleSummary, { entrypoints, otherAssets }: AppInfo, variantIndex: number) {
// we're doing this ourselves because I haven't seen a webpack 4 HTML plugin
// that handles multiple HTML entrypoints correctly.

Expand All @@ -325,13 +367,12 @@ const Webpack: PackagerConstructor<Options> = class Webpack implements Packager
await this.provideErrorContext('needed by %s', [entrypoint.filename], async () => {
for (let script of entrypoint.scripts) {
if (!stats.entrypoints.has(script)) {
const mapping = [] as string[];
try {
// zero here means we always attribute passthrough scripts to the
// first build variant
stats.entrypoints.set(
script,
new Map([[0, [await this.writeScript(script, written, this.variants[0])]]])
);
stats.entrypoints.set(script, new Map([[0, mapping]]));
mapping.push(await this.writeScript(script, written, this.variants[0]));
} catch (err) {
if (err.code === 'ENOENT' && err.path === join(this.pathToVanillaApp, script)) {
this.consoleWrite(
Expand All @@ -349,10 +390,12 @@ const Webpack: PackagerConstructor<Options> = class Webpack implements Packager
}
for (let style of entrypoint.styles) {
if (!stats.entrypoints.has(style)) {
const mapping = [] as string[];
try {
// zero here means we always attribute passthrough styles to the
// first build variant
stats.entrypoints.set(style, new Map([[0, [await this.writeStyle(style, written, this.variants[0])]]]));
stats.entrypoints.set(style, new Map([[0, mapping]]));
mapping.push(await this.writeStyle(style, written, this.variants[0]));
} catch (err) {
if (err.code === 'ENOENT' && err.path === join(this.pathToVanillaApp, style)) {
this.consoleWrite(
Expand All @@ -370,14 +413,19 @@ const Webpack: PackagerConstructor<Options> = class Webpack implements Packager
}
});
}

for (let entrypoint of entrypoints) {
outputFileSync(join(this.outputPath, entrypoint.filename), entrypoint.render(stats), 'utf8');
written.add(entrypoint.filename);
// we need to wait for both compilers before writing html entrypoint
await this.incrementBarrier();
// only the first variant should write it.
if (variantIndex === 0) {
for (let entrypoint of entrypoints) {
outputFileSync(join(this.outputPath, entrypoint.filename), entrypoint.render(stats), 'utf8');
written.add(entrypoint.filename);
}
}

for (let relativePath of otherAssets) {
if (!written.has(relativePath)) {
written.add(relativePath);
await this.provideErrorContext(`while copying app's assets`, [], async () => {
this.copyThrough(relativePath);
});
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"./tests/scenarios/**/*.ts"
],
"compilerOptions": {
"target": "es2017",
"target": "es2019",
"module": "commonjs",
"declaration": true,
"typeRoots": ["types", "node_modules/@types"],
Expand Down

0 comments on commit 652087e

Please sign in to comment.