How to build An Electron App by esbuild with hot reload functionality?

sprout2000

sprout2000

Posted on January 30, 2023

How to build An Electron App by esbuild with hot reload functionality?

A script to run esbuild

  • esbuild.ts
import type { BuildOptions } from 'esbuild';

import { build, context } from 'esbuild';
import { htmlPlugin } from '@craftamap/esbuild-plugin-html';

/**
 * Process according to the value of
 * the NODE_ENV environment variable
 */
const isDev = process.env.NODE_ENV === 'development';

// Common settings for build or watch
const common: BuildOptions = {
  outdir: 'dist', // output destination
  bundle: true, // bundle, of course.
  minify: !isDev,
  sourcemap: isDev,
  define: {
    // Requires a type declaration file (later mention)
    DEBUG: isDev ? 'true' : 'false',
  },
};

// Configuration for main process
const main: BuildOptions = {
  // Import common settings
  ...common,
  // main process and preload script
  entryPoints: ['src/main.ts', 'src/preload.ts'],
  // Build for Node.js environment
  platform: 'node',
  // you will get run-time error without the following:
  external: ['electron'],
};

// Configuration for renderer process
const renderer: BuildOptions = {
  ...common,
  // Entry file for React app
  entryPoints: ['src/web/index.tsx'],
  // Build for Web
  platform: 'browser',
  // Required for htmlPlugin
  metafile: true,
  plugins: [
    htmlPlugin({
      files: [
        {
          entryPoints: ['src/web/index.tsx'],
          filename: 'index.html',
          htmlTemplate: 'src/web/index.html',
        },
      ],
    }),
  ],
};

// Function to execute during development
const watch = async () => {
  await (await context({ ...main })).watch();
  await (await context({ ...renderer })).watch();
};

// Function to execute during production build
const prod = async () => {
  build({ ...main });
  build({ ...renderer });
};

// Executing scripts
isDev ? watch() : prod();
Enter fullscreen mode Exit fullscreen mode

Create a type definition file

  • src/@types/Debug.d.ts
declare const DEBUG: boolean;
Enter fullscreen mode Exit fullscreen mode

Update your package.json

Use electronmon to restart the Electron app when the main process code changes, and reload WebView for the renderer process.

{
  // Specify the main process JavaScript file output by esbuild.
  "main": "dist/main.js",
  "scripts": {
    "dev": "rimraf dist && run-p dev:esbuild dev:electron",
    // Run `tsc` without output before build as esbuild does not type check.
    "build": "tsc && cross-env NODE_ENV=\"production\" ts-node ./esbuild.ts",
    "dev:esbuild": "cross-env NODE_ENV=\"development\" ts-node ./esbuild.ts",
    "dev:electron": "wait-on dist/main.js dist/index.html && electronmon ."
  }
}
Enter fullscreen mode Exit fullscreen mode

You will need to install rimraf, npm-run-all, cross-env and wait-on.

  • A sample for tsconfig.json
{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "Node",
    "esModuleInterop": true,
    "isolatedModules": true, // <-- required
    "resolveJsonModule": true,
    "lib": ["DOM", "ESNext"],
    "jsx": "react-jsx",
    "strict": true,
    "noEmit": true // <-- required
  },
  "include": ["src"],
  "ts-node": {
    "compilerOptions": {
      "module": "CommonJS"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Assumed directory structure

% tree
.
├── esbuild.ts
├── package.json
├── src
│   ├── @types
│   │   └── Debug.d.ts
│   ├── main.ts
│   ├── preload.ts
│   └── web
│       ├── App.css
│       ├── App.tsx
│       ├── index.html
│       └── index.tsx
└── tsconfig.json

4 directories, 10 files
Enter fullscreen mode Exit fullscreen mode
💖 💪 🙅 🚩
sprout2000
sprout2000

Posted on January 30, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related