Path Aliases Register (register-paths.js)
Understand how Dinou reads tsconfig.json or jsconfig.json to register custom path aliases, allowing the server to resolve absolute imports like @/components.
Key File Location: ./dinou/core/register-paths.js💡 Overview
TypeScript and Javascript tools allow importing files using clean path aliases (e.g. import Button from "@/components/Button" instead of ../../components/Button). While compilers resolve these patterns at build time, executing raw Node.js script entrypoints (such as serving pages on-demand or launching revalidation daemons) will trigger MODULE_NOT_FOUND errors, as Node.js is unaware of the @/ alias.
The register-paths.js utility resolves this at startup by reading tsconfig.json or jsconfig.json and registering path aliases dynamically inside Node's module resolution pipeline.
📊 Bootstrapping Flow
The flowchart below traces the path alias registration sequence during server initialization:
⚡ Module Resolution Mapping
The registration script performs several key runtime checks:
- Config Auto-Detection: Looks for
tsconfig.jsonfirst (for TypeScript setups) and falls back tojsconfig.json(for plain JavaScript setups). - Safe Bypasses: If no configuration file exists or the compiler options do not define a
baseUrlandpathsregistry, it exits silently to prevent runtime crashes. - Module Interception: Registers resolution handlers with the
tsconfig-pathslibrary, intercepting standardrequire()calls and mapping alias paths to their physical disk locations.
💡 Node.js Resolution: Why both register-paths.js and babel-esm-loader.js?
Dinou runs as a hybrid server environment supporting both legacy CommonJS (using require()) and modern native ESM (using import):
- tsconfig-paths (register-paths.js): Hooks into Node's CommonJS module system (
Module._resolveFilename). It allows the parent Express web server and other ejected scripts utilizingrequire()to load alias-mapped files. - babel-esm-loader.js: Hooks into Node's native ESM loader pipeline. It intercepts native
importor dynamicimport()statements when transpiling React Server Components (RSC) on-the-fly.
Having only one loader would result in resolution crashes: tsconfig-paths cannot intercept ESM import calls, and babel-esm-loader cannot intercept CommonJS require() calls.
🎯 Integration & Calling Processes
In Dinou's dual-process architecture, Node.js runs two isolated processes. Since both require access to typescript path aliases (like @/) inside their CommonJS execution threads, register-paths.js is required by both entry files:
server.js(Parent Web Server): Loadsregister-paths.jsat startup to allow parsing aliases inside middleware, route handlers, and configuration modules run directly on the main thread.render-html.js(Child HTML Renderer): Runs in an isolated sub-process spawned to pre-render the pages. It importsregister-paths.jsto resolve absolute paths when constructing layout modules and page trees.
⚙️ Complete Code Walkthrough
Below is the full, complete code of register-paths.js:
const tsconfigPaths = require("tsconfig-paths");
const path = require("path");
const fs = require("fs");
function getConfigFileIfExists() {
const tsconfigPath = path.resolve(process.cwd(), "tsconfig.json");
const jsconfigPath = path.resolve(process.cwd(), "jsconfig.json");
if (fs.existsSync(tsconfigPath)) return tsconfigPath;
if (fs.existsSync(jsconfigPath)) return jsconfigPath;
return null;
}
const configFile = getConfigFileIfExists();
if (configFile) {
const config = require(configFile);
const { baseUrl, paths } = config.compilerOptions || {};
// 1. If baseUrl and custom paths configurations are declared, register them
if (baseUrl && paths) {
tsconfigPaths.register({
baseUrl: path.resolve(process.cwd(), baseUrl),
paths,
});
}
}