DEV Community

Cover image for How to build An Electron App by esbuild with hot reload functionality?
sprout2000
sprout2000

Posted on Edited on

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

Top comments (1)

Collapse
 
naucode profile image
Al - Naucode

Hey, that was a nice read, you got my follow, keep writing 😉