Skip to content

Commit

Permalink
fix(dev): wait for both manifest plugins to emit files (#157)
Browse files Browse the repository at this point in the history
  • Loading branch information
ValeraS authored Oct 9, 2024
1 parent 9d95ba5 commit a87b9e5
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 19 deletions.
34 changes: 31 additions & 3 deletions src/commands/dev/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import * as fs from 'node:fs';
import webpack from 'webpack';
import WebpackDevServer from 'webpack-dev-server';
import {getCompilerHooks} from 'webpack-manifest-plugin';
import WebpackAssetsManifest from 'webpack-assets-manifest';
import {deferredPromise} from '../../common/utils';

import paths from '../../common/paths';
import {Logger} from '../../common/logger';
Expand All @@ -13,11 +15,16 @@ import type {NormalizedServiceConfig} from '../../common/models';

export async function watchClientCompilation(
config: NormalizedServiceConfig,
onCompilationEnd: () => void,
onManifestReady: () => void,
) {
const clientCompilation = await buildWebpackServer(config);
const {afterEmit} = getCompilerHooks(clientCompilation.compiler as webpack.Compiler);
afterEmit.tap('app-builder: afterEmit', onCompilationEnd);

const compiler = clientCompilation.compiler;
if ('compilers' in compiler) {
throw new Error('Unexpected multi compiler');
}
subscribeToManifestReadyEvent(compiler, onManifestReady);

return clientCompilation;
}

Expand Down Expand Up @@ -120,3 +127,24 @@ async function buildWebpackServer(config: NormalizedServiceConfig) {

return server;
}

function subscribeToManifestReadyEvent(compiler: webpack.Compiler, onManifestReady: () => void) {
const promises: Promise<unknown>[] = [];

const assetsManifestPlugin = compiler.options.plugins.find(
(plugin) => plugin instanceof WebpackAssetsManifest,
);

if (assetsManifestPlugin) {
const assetsManifestReady = deferredPromise();
promises.push(assetsManifestReady.promise);
assetsManifestPlugin.hooks.done.tap('app-builder', assetsManifestReady.resolve);
}

const manifestReady = deferredPromise();
promises.push(manifestReady.promise);
const {afterEmit} = getCompilerHooks(compiler);
afterEmit.tap('app-builder', manifestReady.resolve);

Promise.all(promises).then(() => onManifestReady());
}
11 changes: 11 additions & 0 deletions src/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,14 @@ export async function getPort({port}: {port: number}) {
const {default: getPortDefault, portNumbers} = await import('get-port');
return getPortDefault({port: portNumbers(port, port + 100)});
}

export function deferredPromise<T>() {
let resolve: (value?: T) => void;
let reject: (reason?: unknown) => void;
const promise = new Promise<T | undefined>((res, rej) => {
resolve = res;
reject = rej;
});
// @ts-expect-error Promise callback executes synchronously, so resolve and reject are initialized here
return {promise, resolve, reject};
}
29 changes: 13 additions & 16 deletions src/common/webpack/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,7 @@ function configurePlugins(options: HelperOptions): webpack.Configuration['plugin
const {isEnvDevelopment, isEnvProduction, config} = options;
const excludeFromClean = config.excludeFromClean || [];

const manifestFile = 'assets-manifest.json';
const plugins: webpack.Configuration['plugins'] = [
new CleanWebpackPlugin({
verbose: config.verbose,
Expand All @@ -616,6 +617,18 @@ function configurePlugins(options: HelperOptions): webpack.Configuration['plugin
writeToFileEmit: true,
publicPath: '',
}),
new WebpackAssetsManifest(
isEnvProduction
? {
entrypoints: true,
output: manifestFile,
}
: {
entrypoints: true,
writeToDisk: true,
output: path.resolve(paths.appBuild, manifestFile),
},
),
createMomentTimezoneDataPlugin(config.momentTz),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
Expand Down Expand Up @@ -757,22 +770,6 @@ function configurePlugins(options: HelperOptions): webpack.Configuration['plugin
}
}

const manifestFile = 'assets-manifest.json';
plugins.push(
new WebpackAssetsManifest(
isEnvProduction
? {
entrypoints: true,
output: manifestFile,
}
: {
entrypoints: true,
writeToDisk: true,
output: path.resolve(paths.appBuild, manifestFile),
},
),
);

if (config.cdn) {
let credentialsGlobal;
if (process.env.FRONTEND_S3_ACCESS_KEY_ID && process.env.FRONTEND_S3_SECRET_ACCESS_KEY) {
Expand Down

0 comments on commit a87b9e5

Please sign in to comment.