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

how can I have live reload with esbuild-register? #72

Open
daniloab opened this issue May 21, 2022 · 1 comment
Open

how can I have live reload with esbuild-register? #72

daniloab opened this issue May 21, 2022 · 1 comment

Comments

@daniloab
Copy link

I want to know how can I have a live reload using esbuild-register to build a nodejs server.

Today, I'm using nodemon. Is this enough?

Does anyone have an example of how it builds a nodejs server + esbuild + live reload?

@lancetipton
Copy link

lancetipton commented Dec 1, 2022

Here's a script that I've been using. It doesn't use esbuild-register directly, only esbuild and nodemon
I put everything in a configs directory at <project-root-dir>/configs

/configs/build.config.js

const path = require('path')
const { build } = require('esbuild')
const { spawn } = require('child_process')
const aliasPlugin = require('esbuild-plugin-path-alias')

let __server

const devEnvs = [
  `development`,
  `develop`,
  `local`,
]

const nodeEnv = process.env.NODE_ENV || `local`
const isDev = devEnvs.includes(nodeEnv)

const rootDir = path.join(__dirname, `../`)
const distDir = path.join(rootDir, `dist`)
const outFile = path.join(distDir, `index.js`)
const entryFile = path.join(rootDir, `index.ts`)
const tsConfig = require(path.join(rootDir, `tsconfig.json`))

const aliases = Object.entries(tsConfig.compilerOptions.paths)
  .reduce((acc, [name, arr]) => {
    arr.length && (acc[name] = arr[0])

    return acc
  }, {})

/**
 * Helper to start the dev server after bundling the app
 */
const devServer = async () => {
  if (!isDev) return

  __server = spawn('nodemon', [`--config`, `configs/nodemon.config.json`], {
    cwd: rootDir,
    env: { ...process.env },
    stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
  })

  __server.stdout.on('data', (data) => process.stdout.write(data))
  __server.stderr.on('data', (data) => process.stderr.write(data))
  process.on(`exit`, () => __server && __server.pid && process.kill(__server.pid))
}

/**
 * Build the code, then run the devServer
 * ESBuild config object
 * [See here for more info](https://esbuild.github.io/api/#build-api)
 */
build({
  outfile: outFile,
  bundle: true,
  minify: false,
  sourcemap: true,
  target: 'es2017',
  platform: 'node',
  assetNames: '[name]',
  allowOverwrite: true,
  entryPoints: [entryFile],
  watch: isDev && {
    onRebuild(error, result) {
      if (error) console.error(`Error rebuilding app`, error)
      else console.log(`Rebuilt app successfully`, result)
      __server && __server.send('restart')
    },
  },
  plugins: [
    aliasPlugin(aliases),
    /**
     * Custom plugin to filter out node_modules
     * See more info [here](https://github.com/evanw/esbuild/issues/619#issuecomment-751995294)
     */
    {
      name: 'external-node-modules',
      setup(build) {
        // Must not start with "/" or "./" or "../" which means it's a node_modules
        // eslint-disable-next-line no-useless-escape
        const filter = /^[^.\/]|^\.[^.\/]|^\.\.[^\/]/
        build.onResolve({ filter }, (args) => ({
          path: args.path,
          external: true,
        }))
      },
    },
  ],
}).then(devServer)
  • Next create a nodemon config

/configs/nodemon.config.json

{
  "exec": "node -r esbuild-register dist/index.js",
  "ext": "none",
  "verbose": true,
  "watch": [""],
  "ignore": ["../"],
  "watchOptions": {
    "interval": 0,
    "usePolling": false,
    "persistent": false,
    "useFsEvents": false,
    "disableGlobbing": true
  }
}

IMPORTANT

  • Make sure the exec points the the correct build output. In my case that's <project-root-dir>/dist/index.js
  • Make sure the ignore array ignores your entire project folder. It took me a bit to get to right and it's project specific
  • In this case nodemon is for restarting the server only. It's not used as a file watcher. ESBuild does that

  • Next update the <project-root-dir>/package.json scripts section and ensure you have all the dependencies installed
"scripts": {
  "build": "NODE_ENV=production node configs/build.config.js",
  "dev": "NODE_ENV=local node configs/build.config.js",
},
"devDependencies": {
  "esbuild": "0.15.16",
  "esbuild-plugin-path-alias": "1.0.7",
  "esbuild-register": "3.4.1",
  "nodemon": "2.0.19",
}

  • Finally run yarn dev to start a dev server
  • Use yarn build for a production build

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

No branches or pull requests

2 participants