Get esbuild to watch for changes, rebuild, and restart express server

Viewed 508

I am trying to create a simple SSR powered project using express + react. To do this, I need to simultaneously watch frontend and backend scripts during development.

The goal here is to use express routes to point to react page components. Now, I have this working, but I am having problems with DX.

Here are my package scripts:

    "build:client": "esbuild src/index.js --bundle --outfile=public/bundle.js --loader:.js=jsx",
    "build:server": "esbuild src/server.jsx --bundle --outfile=public/server.js --platform=node",
    "build": "npm run build:client && npm run build:server",
    "start": "node ./public/server.js"

Now this works if I do npm run build && npm run start, but the problem is that it doesn't watch for changes and rebuild the frontend bundle or restart the backend server.

Now, if I add --watch to the 2 build scripts, it only starts watching the index.js file and does not execute the other scripts.

So if I add nodemon to my start script, it doesn't matter because esbuild won't get past the first script due to the watcher.

Is there a simpler way of doing what I am trying to do here? I also want to add tailwind to this project once I figure this out, so any tips around that would be helpful as well.

2 Answers

I would suggest using the JS interface to esbuild, i.e., write a small JS script that requires esbuild and runs it, and then use the functional version of https://esbuild.github.io/api/#watch. Something like this:

require('esbuild').build({
  entryPoints: ['app.js'],
  outfile: 'out.js',
  bundle: true,
  watch: {
    onRebuild(error, result) {
      if (error) console.error('watch build failed:', error)
      else { 
        console.log('watch build succeeded:', result)
        // HERE: somehow restart the server from here, e.g., by sending a signal that you trap and react to inside the server.
      }
    },
  },
}).then(result => {
  console.log('watching...')
})

@es-exec/esbuild-plugin-serve or @es-exec/esbuild-plugin-start are two esbuild plugins that can run your bundles or any command line script (similarly to nodemon) for you after building your project (supports watch mode for rebuilding and rerunning on file changes).

Doing this is as easy as:

import serve from '@es-exec/esbuild-plugin-serve';

/** @type import('@es-exec/esbuild-plugin-serve').ESServeOptions */
const options = {
  ... // Any options you want to provide.
};

export default {
    ..., // Other esbuild config options.
    plugins: [serve(options)],
};

The documentation can be found at the following:

Disclaimer: I am the author of these packages.

Related