unjs / unplugin

Unified plugin system for Vite, Rollup, Webpack, esbuild, Rolldown, and more
https://unplugin.unjs.io
MIT License
3.09k stars 114 forks source link

In webpack `writeBundle` isn't "awaited". #389

Closed yoannmoinet closed 4 months ago

yoannmoinet commented 4 months ago

Environment

Node 18.19.0 Unplugin 1.10.1 Yarn 1.22.19

Reproduction

Having a plugin with an async writeBundle hook.

{
    writeBundle: async () => {
        await new Promise((resolve) => {
            setTimeout(() => {
                console.log('End of write');
            }, 1000);
        });
    }
}

Describe the bug

It results in the plugin executing outside of webpack's "build process".

I noticed it while writing tests, and jest was constantly failing because it was trying to log outside of its process.

Additional context

I think I've confirmed it in the code:

https://github.com/unjs/unplugin/blob/1d7e13f06a605ced44b671acc2c25b7536b13c0e/src/webpack/index.ts#L218-L222

Should be:

if (plugin.writeBundle) {
-    compiler.hooks.afterEmit.tap(plugin.name, () => {
+    compiler.hooks.afterEmit.tapPromise(plugin.name, async () => {
-        plugin.writeBundle!()
+        await plugin.writeBundle!()
    })
}

Similarly to esbuild: https://github.com/unjs/unplugin/blob/1d7e13f06a605ced44b671acc2c25b7536b13c0e/src/esbuild/index.ts#L169-L170

I think the best fallback for now is to use buildEnd instead, but I'm not sure it is executed exactly at that moment for every bundlers 😞

I was able to fix it on my side with a yarn patch which resolved the issue.

Logs

No response

yoannmoinet commented 4 months ago

It seems to be the same problem in rspack too: https://github.com/unjs/unplugin/blob/1d7e13f06a605ced44b671acc2c25b7536b13c0e/src/rspack/index.ts#L106-L110

yoannmoinet commented 4 months ago

Tried my hand on a PR too: https://github.com/unjs/unplugin/pull/390