Skip to content

Commit

Permalink
fix(core): call onAfterBuild on every build (#1771)
Browse files Browse the repository at this point in the history
  • Loading branch information
xc2 authored Mar 9, 2024
1 parent 9e149b9 commit c168c21
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 51 deletions.
55 changes: 32 additions & 23 deletions packages/compat/webpack/src/core/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,23 @@ export const build = async (
bundlerConfigs = webpackConfigs;
}

let isFirstCompile = true;
await context.hooks.onBeforeBuild.call({
bundlerConfigs: bundlerConfigs as RspackConfig[],
});

const onDone = async (stats: Stats | MultiStats) => {
const p = context.hooks.onAfterBuild.call({ isFirstCompile, stats });
isFirstCompile = false;
await p;
};

try {
(compiler as Rspack.Compiler).hooks.done.tapPromise('rsbuild:done', onDone);
} catch {
(compiler as Rspack.MultiCompiler).hooks.done.tap('rsbuild:done', onDone);
}

if (watch) {
compiler.watch({}, (err) => {
if (err) {
Expand All @@ -51,28 +64,24 @@ export const build = async (
return;
}

const { stats } = await new Promise<{ stats: Stats | MultiStats }>(
(resolve, reject) => {
compiler.run((err, stats) => {
if (err || stats?.hasErrors()) {
const buildError = err || new Error('Webpack build failed!');
reject(buildError);
}
// If there is a compilation error, the close method should not be called.
// Otherwise bundler may generate an invalid cache.
else {
// When using run or watch, call close and wait for it to finish before calling run or watch again.
// Concurrent compilations will corrupt the output files.
compiler.close((closeErr) => {
closeErr && logger.error(closeErr);

// Assert type of stats must align to compiler.
resolve({ stats: stats as any });
});
}
});
},
);
await new Promise<{ stats: Stats | MultiStats }>((resolve, reject) => {
compiler.run((err, stats) => {
if (err || stats?.hasErrors()) {
const buildError = err || new Error('Webpack build failed!');
reject(buildError);
}
// If there is a compilation error, the close method should not be called.
// Otherwise bundler may generate an invalid cache.
else {
// When using run or watch, call close and wait for it to finish before calling run or watch again.
// Concurrent compilations will corrupt the output files.
compiler.close((closeErr) => {
closeErr && logger.error(closeErr);

await context.hooks.onAfterBuild.call({ stats });
// Assert type of stats must align to compiler.
resolve({ stats: stats as any });
});
}
});
});
};
53 changes: 31 additions & 22 deletions packages/core/src/provider/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,23 @@ export const build = async (
bundlerConfigs = rspackConfigs;
}

let isFirstCompile = true;
await context.hooks.onBeforeBuild.call({
bundlerConfigs,
});

const onDone = async (stats: Stats | MultiStats) => {
const p = context.hooks.onAfterBuild.call({ isFirstCompile, stats });
isFirstCompile = false;
await p;
};

try {
(compiler as RspackCompiler).hooks.done.tapPromise('rsbuild:done', onDone);
} catch {
(compiler as RspackMultiCompiler).hooks.done.tap('rsbuild:done', onDone);
}

if (watch) {
compiler.watch({}, (err) => {
if (err) {
Expand All @@ -47,26 +60,22 @@ export const build = async (
return;
}

const { stats } = await new Promise<{ stats?: Stats | MultiStats }>(
(resolve, reject) => {
compiler.run((err: any, stats?: Stats | MultiStats) => {
if (err || stats?.hasErrors()) {
const buildError = err || new Error('Rspack build failed!');
reject(buildError);
}
// If there is a compilation error, the close method should not be called.
// Otherwise the bundler may generate an invalid cache.
else {
// When using run or watch, call close and wait for it to finish before calling run or watch again.
// Concurrent compilations will corrupt the output files.
compiler.close(() => {
// Assert type of stats must align to compiler.
resolve({ stats });
});
}
});
},
);

await context.hooks.onAfterBuild.call({ stats });
await new Promise<{ stats?: Stats | MultiStats }>((resolve, reject) => {
compiler.run((err: any, stats?: Stats | MultiStats) => {
if (err || stats?.hasErrors()) {
const buildError = err || new Error('Rspack build failed!');
reject(buildError);
}
// If there is a compilation error, the close method should not be called.
// Otherwise the bundler may generate an invalid cache.
else {
// When using run or watch, call close and wait for it to finish before calling run or watch again.
// Concurrent compilations will corrupt the output files.
compiler.close(() => {
// Assert type of stats must align to compiler.
resolve({ stats });
});
}
});
});
};
4 changes: 2 additions & 2 deletions packages/document/docs/en/plugins/dev/hooks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -357,8 +357,8 @@ import OnAfterBuild from '@en/shared/onAfterBuild.md';
```ts
const myPlugin = () => ({
setup: (api) => {
api.onAfterBuild(({ stats }) => {
console.log(stats?.toJson());
api.onAfterBuild(({ isFirstCompile, stats }) => {
console.log(stats?.toJson(), isFirstCompile);
});
},
});
Expand Down
4 changes: 3 additions & 1 deletion packages/document/docs/en/shared/onAfterBuild.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
- If the current bundler is Rspack, you will get Rspack Stats.
- If the current bundler is webpack, you will get webpack Stats.

Moreover, you can use `isFirstCompile` to determine whether it is the first build on watch mode.

- **Type:**

```ts
function OnAfterBuild(
callback: (params: { stats?: Stats | MultiStats }) => Promise<void> | void,
callback: (params: { isFirstCompile: boolean, stats?: Stats | MultiStats }) => Promise<void> | void,
): void;
```
4 changes: 2 additions & 2 deletions packages/document/docs/zh/plugins/dev/hooks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -359,8 +359,8 @@ import OnAfterBuild from '@zh/shared/onAfterBuild.md';
```ts
const myPlugin = () => ({
setup: (api) => {
api.onAfterBuild(({ stats }) => {
console.log(stats?.toJson());
api.onAfterBuild(({ isFirstCompile, stats }) => {
console.log(stats?.toJson(), isFirstCompile);
});
},
});
Expand Down
4 changes: 3 additions & 1 deletion packages/document/docs/zh/shared/onAfterBuild.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
- 如果当前打包工具为 Rspack,则获取到的是 Rspack Stats。
- 如果当前打包工具为 webpack,则获取到的是 webpack Stats。

另外,在 watch 模式下你可以通过 `isFirstCompile` 来判断是否为首次构建。

- **类型:**

```ts
function OnAfterBuild(
callback: (params: { stats?: Stats | MultiStats }) => Promise<void> | void,
callback: (params: { isFirstCompile: boolean, stats?: Stats | MultiStats }) => Promise<void> | void,
): void;
```
1 change: 1 addition & 0 deletions packages/shared/src/types/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export type OnBeforeBuildFn<B = 'rspack'> = (params: {
}) => PromiseOrNot<void>;

export type OnAfterBuildFn = (params: {
isFirstCompile: boolean;
stats?: Stats | MultiStats;
}) => PromiseOrNot<void>;

Expand Down

0 comments on commit c168c21

Please sign in to comment.