Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugins' onEnd callback isn't triggerred in serve mode #1384

Closed
fa93hws opened this issue Jun 19, 2021 · 4 comments · Fixed by #2816
Closed

Plugins' onEnd callback isn't triggerred in serve mode #1384

fa93hws opened this issue Jun 19, 2021 · 4 comments · Fixed by #2816

Comments

@fa93hws
Copy link

fa93hws commented Jun 19, 2021

I have

      build.onStart(() => {
        console.log('build end')
      })
      build.onStart(() => {
        console.log('build started')
      })

in build and everything works as expected. Both build started and build end are printed properly.

However,if I use serve with

  esbuildServe(serveOptions, esbuildOptions).then(server => {
    console.log(green(`hosted on http://${server.host}:${server.port}`));
    registerCleanup(() => server.stop());
  }).catch(e => {
    console.error(e);
    process.exit(1);
  })

I got hosted on http://0.0.0.0:8000 and multiple build started only. I am suspecting the onEnd callback isn't called properly called in serve mode?

@evanw
Copy link
Owner

evanw commented Jun 25, 2021

Thanks for the report. I have confirmed that this bug exists. However, the reason for this is due to how the JS API is implemented by calling the Go API, and fixing this isn't that straightforward. So it may not be fixed immediately.

Some notes for me: JS onEnd callbacks aren't implemented using the Go OnEnd callback because that would involve serializing the build result from Go over to JS twice. That would not only be inefficient, but it would also not be correct because any mutations to the result made by JS plugins wouldn't end up in the final result if the final result is re-serialized. So instead, JS onEnd callbacks are manually invoked right before returning the final result. However, the serve API doesn't have final result, so this means JS onEnd callbacks are never invoked from anywhere. I will have to change the internals so that the final result is serialized from Go to JS by a plugin when serving but not when building.

@adamchipperfield
Copy link

Are there plans to solve this or get around it? Relying on serve but I need a way to tell Browsersync when a bundle has changed.

@hyrious
Copy link

hyrious commented Dec 28, 2021

@adamchipperfield Did you mean a file watcher? Serve mode is different from build({ watch: true }). The former does not watch file, instead it rebuilds the file everytime when a request to it comes in.

You can rely on a real file watcher like chokidar or other and use plugins to refresh the watched file list.

One may also use build-watch to implement the watcher if don't care the overhead of building twice. (and, that's what I got!: https://github.com/hyrious/esbuild-repl/blob/63cc74842a9343b945d51fca28dfe42a012d6171/scripts/dev.ts)

@clshortfuse
Copy link

clshortfuse commented Jan 11, 2023

For posterity, you can serve and build from the same script:

let server;
if (serve) {
  /** @type {esbuild.ServeOptions} */
  const serveOptions = {
    port: 5500,
    servedir: './',
    onRequest(args) {
      const localPath = path.join(serveOptions.servedir, args.path);
      if (localPath === buildOptions.outfile) {
        console.log('accessed outfile');
      }
    },
  };

  server = await esbuild.serve(serveOptions, { entryPoints: [] });
  console.log('esbuild server is listening on port', serveOptions.port);
}

await Promise.all([
  server?.wait,
  esbuild.build(buildOptions),
]);

Just supply an empty buildOptions to .serve(). Your normal buildOptions can continue to use build.onEnd. Using a file watcher doesn't work because .serve() doesn't write to the file system. And if you're interesting in making sure it writes to the file system, then you can just .build() like normal.


For those using command line arguments instead of JS-based cli, this might help:

const cliArgs = new Set(process.argv.slice(2));

const isProduction = (process.env.NODE_ENV === 'production') || cliArgs.has('--production');
const minifyAll = cliArgs.has('--minify');
const minifyWhitespace = cliArgs.has('--minify-whitespace');
const minifyIdentifiers = cliArgs.has('--minify-identifiers');
const minifySyntax = cliArgs.has('--minify-syntax');
const watch = cliArgs.has('--watch');
const serve = cliArgs.has('--serve');

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants