@@ -88,7 +88,7 @@ async function buildDevArgs(
8888 "--signal" ,
8989 "SIGTERM" , // Use SIGTERM for graceful shutdown
9090 "--delay" ,
91- "500ms " , // Debounce rapid file changes
91+ "1000ms " , // Debounce rapid file changes (allow time for port release)
9292 "--watch" ,
9393 "src" ,
9494 "--ext" ,
@@ -203,24 +203,138 @@ const compileTypescript = async () => {
203203 printSuccess ( "Built successfully" , "compile-typescript" ) ;
204204} ;
205205
206+ /**
207+ * Transform path aliases to relative paths in compiled JavaScript files.
208+ * This runs after TypeScript compilation to ensure production builds work
209+ * without runtime path resolution.
210+ *
211+ * @param outDir - The output directory (e.g., "./dist")
212+ */
213+ const transformPathAliases = async ( outDir : string ) : Promise < void > => {
214+ const tsconfigPath = join ( process . cwd ( ) , "tsconfig.build.json" ) ;
215+
216+ if ( ! existsSync ( tsconfigPath ) ) {
217+ return ; // No tsconfig.build.json, skip transformation
218+ }
219+
220+ const tsconfig = JSON . parse ( readFileSync ( tsconfigPath , "utf-8" ) ) ;
221+ const paths = tsconfig . compilerOptions ?. paths ;
222+ const baseUrl = tsconfig . compilerOptions ?. baseUrl ;
223+
224+ if ( ! paths || ! baseUrl ) {
225+ return ; // No path aliases defined, skip
226+ }
227+
228+ // Build regex patterns for each alias
229+ const aliasPatterns : Array < {
230+ pattern : RegExp ;
231+ alias : string ;
232+ target : string ;
233+ } > = [ ] ;
234+
235+ for ( const [ alias , targets ] of Object . entries ( paths ) ) {
236+ if ( ! Array . isArray ( targets ) || targets . length === 0 ) continue ;
237+
238+ // Convert @alias /* to regex pattern
239+ // Matches: require("@alias/something") or require('@alias/something')
240+ const aliasBase = alias . replace ( "/*" , "" ) ;
241+ const targetBase = ( targets [ 0 ] as string ) . replace ( "/*" , "" ) ;
242+
243+ // Pattern to match require("@alias/...") or require('@alias/...')
244+ const pattern = new RegExp (
245+ `require\\(["']${ aliasBase . replace ( "@" , "\\@" ) } /([^"']+)["']\\)` ,
246+ "g" ,
247+ ) ;
248+
249+ aliasPatterns . push ( {
250+ pattern,
251+ alias : aliasBase ,
252+ target : targetBase ,
253+ } ) ;
254+ }
255+
256+ if ( aliasPatterns . length === 0 ) {
257+ return ;
258+ }
259+
260+ // Recursively find all .js files in outDir
261+ const findJsFiles = async ( dir : string ) : Promise < Array < string > > => {
262+ const files : Array < string > = [ ] ;
263+ const entries = await fs . readdir ( dir , { withFileTypes : true } ) ;
264+
265+ for ( const entry of entries ) {
266+ const fullPath = join ( dir , entry . name ) ;
267+ if ( entry . isDirectory ( ) ) {
268+ files . push ( ...( await findJsFiles ( fullPath ) ) ) ;
269+ } else if ( entry . name . endsWith ( ".js" ) ) {
270+ files . push ( fullPath ) ;
271+ }
272+ }
273+
274+ return files ;
275+ } ;
276+
277+ const jsFiles = await findJsFiles ( outDir ) ;
278+ let transformedCount = 0 ;
279+
280+ for ( const file of jsFiles ) {
281+ let content = await fs . readFile ( file , "utf-8" ) ;
282+ let modified = false ;
283+
284+ // Get the directory of the current file relative to outDir
285+ const fileDir = path . dirname ( file ) ;
286+
287+ for ( const { pattern, alias, target } of aliasPatterns ) {
288+ // Calculate the relative path from this file to the target
289+ const targetDir = join ( outDir , baseUrl . replace ( "./" , "" ) , target ) ;
290+ let relativePath = path . relative ( fileDir , targetDir ) ;
291+
292+ // Ensure it starts with ./ or ../
293+ if ( ! relativePath . startsWith ( "." ) ) {
294+ relativePath = "./" + relativePath ;
295+ }
296+
297+ // Replace Windows backslashes with forward slashes
298+ relativePath = relativePath . replace ( / \\ / g, "/" ) ;
299+
300+ // Replace the alias with the relative path
301+ const newContent = content . replace ( pattern , ( match , subPath ) => {
302+ modified = true ;
303+ return `require("${ relativePath } /${ subPath } ")` ;
304+ } ) ;
305+
306+ if ( newContent !== content ) {
307+ content = newContent ;
308+ }
309+ }
310+
311+ if ( modified ) {
312+ await fs . writeFile ( file , content , "utf-8" ) ;
313+ transformedCount ++ ;
314+ }
315+ }
316+
317+ if ( transformedCount > 0 ) {
318+ printSuccess (
319+ `Path aliases resolved in ${ transformedCount } files` ,
320+ "transform-paths" ,
321+ ) ;
322+ }
323+ } ;
324+
206325/**
207326 * Helper function to copy files to the dist directory
208327 */
209328const copyFiles = async ( outDir : string ) => {
210- const { opinionated } = await Compiler . loadConfig ( ) ;
211- let filesToCopy : Array < string > = [ ] ;
212- if ( opinionated ) {
213- filesToCopy = [
214- "./register-path.js" ,
215- "tsconfig.build.json" ,
216- "package.json" ,
217- ] ;
218- } else {
219- filesToCopy = [ "tsconfig.json" , "package.json" ] ;
329+ // Only copy package.json - path aliases are resolved at build time
330+ // No need for tsconfig files or register-path.js in production
331+ const filesToCopy = [ "package.json" ] ;
332+
333+ for ( const file of filesToCopy ) {
334+ if ( existsSync ( file ) ) {
335+ await fs . copyFile ( file , join ( outDir , path . basename ( file ) ) ) ;
336+ }
220337 }
221- filesToCopy . forEach ( ( file ) => {
222- fs . copyFile ( file , join ( outDir , path . basename ( file ) ) ) ;
223- } ) ;
224338} ;
225339
226340/**
@@ -269,6 +383,10 @@ export const runCommand = async ({
269383 }
270384 await cleanDist ( outDir ) ;
271385 await compileTypescript ( ) ;
386+ // Transform path aliases to relative paths for production
387+ if ( opinionated ) {
388+ await transformPathAliases ( outDir ) ;
389+ }
272390 await copyFiles ( outDir ) ;
273391 break ;
274392 case "prod" : {
@@ -281,12 +399,11 @@ export const runCommand = async ({
281399 }
282400
283401 let config : Array < string > = [ ] ;
402+
403+ // ✅ NEW: Simplified - no more register-path.js
404+ // Path resolution is now built-in to @expressots/core
284405 if ( opinionated ) {
285- config = [
286- "-r" ,
287- `./${ outDir } /register-path.js` ,
288- `./${ outDir } /src/${ entryPoint } .js` ,
289- ] ;
406+ config = [ `./${ outDir } /src/${ entryPoint } .js` ] ;
290407 } else {
291408 config = [ `./${ outDir } /${ entryPoint } .js` ] ;
292409 }
0 commit comments