egoist / esbuild-register

Transpile JSX, TypeScript and esnext features on the fly with esbuild
MIT License
984 stars 52 forks source link

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

Open daniloab opened 2 years ago

daniloab commented 2 years ago

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 commented 1 year ago

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)

/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


"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",
}