esbuild Overview & Configs
Explore the base configs and normalization utilities that initialize and control esbuild for dev and production.
Key Files Mapped:
• Dev Config:./dinou/esbuild/helpers-esbuild/get-config-esbuild.mjs
• Prod Config:./dinou/esbuild/helpers-esbuild/get-config-esbuild-prod.mjs
• Path Normalizer:./dinou/esbuild/helpers-esbuild/normalize-path.mjs
💡 Overview
Dinou chooses esbuild as its primary compilation engine during local development runs due to its speed. When compiling components, esbuild packages TSX, CSS, and asset files.
The configuration models are split into two baseline builders (Development and Production) located in helpers-esbuild/, mapping variables, optimization flags, and custom loader plugins.
📊 Dev vs Prod Configuration
The chart below compares the two configurations:
🛠️ Dev Config (get-config-esbuild.mjs)
Yields compiler options optimal for local runs. Note that write: false is set to keep outputs in-memory for HMR server pushes, avoiding disk write overhead:
import { TsconfigPathsPlugin } from "@esbuild-plugins/tsconfig-paths";
import reactClientManifestPlugin from "../plugins-esbuild/react-client-manifest-plugin.mjs";
import serverFunctionsPlugin from "../plugins-esbuild/server-functions-plugin.mjs";
import cssProcessorPlugin from "../plugins-esbuild/css-processor-plugin.mjs";
import esmHmrPlugin from "../react-refresh/esm-hmr-plugin.mjs";
import stableChunkNamesAndMapsPlugin from "../plugins-esbuild/stable-chunk-names-and-maps-plugin.mjs";
import assetsPlugin from "../plugins-esbuild/assets-plugin.mjs";
import skipMissingEntryPointsPlugin from "../plugins-esbuild/skip-missing-entry-points-plugin.mjs";
import copyStaticFiles from "esbuild-copy-static-files";
import { existsSync } from "node:fs";
export default function getConfigEsbuild({
entryPoints,
outdir = "public",
manifest = {},
changedIds,
hmrEngine,
}) {
let plugins = [
skipMissingEntryPointsPlugin(),
TsconfigPathsPlugin({}),
cssProcessorPlugin(),
reactClientManifestPlugin({ manifest }),
assetsPlugin(),
stableChunkNamesAndMapsPlugin(),
serverFunctionsPlugin(),
esmHmrPlugin({ entryNames: ["main", "error"], changedIds, hmrEngine }),
];
if (existsSync("favicons")) {
plugins = [
copyStaticFiles({
src: "favicons",
dest: outdir,
}),
...plugins,
];
}
return {
entryPoints,
outdir,
format: "esm",
bundle: true,
splitting: true,
sourcemap: true,
jsx: "automatic",
target: "es2022",
write: false, // Write is handled in-memory for HMR performance
conditions: ["style"],
metafile: true,
logLevel: "warning",
define: {
"process.env.NODE_ENV": JSON.stringify("development"),
},
external: [
"/__SERVER_FUNCTION_PROXY__",
"/serverFunctionProxy.js",
"/__hmr_client__.js",
"/react-refresh-entry.js",
],
plugins,
};
}🚀 Prod Config (get-config-esbuild-prod.mjs)
Extends the base setup for minified, optimized static builds. It enables hashes inside filenames, turns on minification, and attaches writePlugin() to commit memory buffers to files:
import { TsconfigPathsPlugin } from "@esbuild-plugins/tsconfig-paths";
import reactClientManifestPlugin from "../plugins-esbuild/react-client-manifest-plugin.mjs";
import serverFunctionsPlugin from "../plugins-esbuild/server-functions-plugin.mjs";
import cssProcessorPlugin from "../plugins-esbuild/css-processor-plugin.mjs";
import assetsPlugin from "../plugins-esbuild/assets-plugin.mjs";
import copyStaticFiles from "esbuild-copy-static-files";
import manifestGeneratorPlugin from "../plugins-esbuild/manifest-generator-plugin.mjs";
import writePlugin from "../plugins-esbuild/write-plugin.mjs";
import babelReactCompilerPlugin from "../plugins-esbuild/babel-react-compiler-plugin.mjs";
import { existsSync } from "node:fs";
const manifestData = {};
export default function getConfigEsbuildProd({
entryPoints,
outdir = "dist3",
manifest = {},
}) {
let plugins = [
babelReactCompilerPlugin(), // Injects Babel React 19 compiler optimizations
TsconfigPathsPlugin({}),
cssProcessorPlugin({ outdir }),
reactClientManifestPlugin({
manifest,
manifestPath: `react_client_manifest/react-client-manifest.json`,
}),
assetsPlugin(),
manifestGeneratorPlugin(manifestData),
serverFunctionsPlugin(manifestData),
writePlugin(), // Writes final files from memory buffers to disk
];
if (existsSync("favicons")) {
plugins = [
copyStaticFiles({
src: "favicons",
dest: outdir,
}),
...plugins,
];
}
return {
entryPoints,
outdir,
format: "esm",
bundle: true,
splitting: true,
sourcemap: false,
chunkNames: "[name]-[hash]",
entryNames: "[name]-[hash]",
jsx: "automatic",
target: "es2022",
write: false,
conditions: ["style"],
metafile: true,
logLevel: "warning",
minify: true,
define: {
"process.env.NODE_ENV": JSON.stringify("production"),
},
external: [
"/__SERVER_FUNCTION_PROXY__",
"/serverFunctionProxy.js",
"/__hmr_client__.js",
"/react-refresh-entry.js",
],
plugins,
};
}📂 Path Normalizer (normalize-path.mjs)
On Windows drives, absolute paths resolve with backslashes (\). If written directly into JSON chunk manifests, this casing leads to serialization mismatches on browser hydration.
The normalize-path.mjs utility standardizes all filepaths to POSIX format before compiling them:
export function normalizePath(filePath) {
if (typeof filePath !== "string") return filePath;
// Replace Windows backslashes (\) with standard POSIX forward slashes (/)
return filePath.replace(/\\/g, "/");
}