@@ -24,6 +24,7 @@ import type { Compilation, Compiler, Module as WebpackModule } from "webpack";
2424import { sources } from "webpack" ;
2525import fs from "fs" ;
2626import path from "path" ;
27+ import { loadConfig } from "tsconfig-paths" ;
2728
2829interface Asset {
2930 name : string ;
@@ -108,51 +109,52 @@ export default class CodePressWebpackPlugin {
108109 }
109110 }
110111
111- // Always try to read @ alias from tsconfig.json if not already present
112- // resolve.alias usually has Next.js internals but not the @ path alias
113- if ( ! aliases . has ( "@" ) ) {
114- const tsconfigPath = path . join ( compiler . context , "tsconfig.json" ) ;
115-
112+ // Load path aliases from tsconfig.json using tsconfig-paths library
113+ // This properly handles:
114+ // - JSON with comments (TypeScript's JSON5-like syntax)
115+ // - The "extends" field to resolve inherited configurations
116+ // - Complex path patterns
117+ const tsconfigPath = path . join ( compiler . context , "tsconfig.json" ) ;
118+ if ( fs . existsSync ( tsconfigPath ) ) {
116119 try {
117- if ( fs . existsSync ( tsconfigPath ) ) {
118- const tsconfigContent = fs . readFileSync ( tsconfigPath , "utf8" ) ;
119-
120- // Extract paths directly using regex (avoids JSON parsing issues with comments/globs)
121- // Match: "paths": { "@/*": ["./src/*"] } or similar
122- const pathsMatch = tsconfigContent . match (
123- / " p a t h s " \s * : \s * \{ ( [ ^ } ] + ) \} /
124- ) ;
125-
126- if ( pathsMatch ) {
127- const pathsContent = pathsMatch [ 1 ] ;
128-
129- // Extract individual path mappings: "@/*": ["./src/*"]
130- const pathPattern = / " ( [ ^ " ] + ) " \s * : \s * \[ \s * " ( [ ^ " ] + ) " / g;
131- let match ;
132- while ( ( match = pathPattern . exec ( pathsContent ) ) !== null ) {
133- const aliasPattern = match [ 1 ] ; // "@/*"
134- const targetPattern = match [ 2 ] ; // "./src/*"
135-
136- // Convert "@/*" -> "@" and "./src/*" -> "src"
137- const alias = aliasPattern . replace ( / \/ \* $ / , "" ) ;
138- const targetPath = targetPattern
139- . replace ( / ^ \. \/ / , "" )
140- . replace ( / \/ \* $ / , "" ) ;
120+ const config = loadConfig ( compiler . context ) ;
121+
122+ if ( config . resultType === "success" && config . paths ) {
123+ for ( const [ pattern , targets ] of Object . entries ( config . paths ) ) {
124+ // Convert "@/*" -> "@" and "./src/*" -> "src"
125+ const alias = pattern . replace ( / \/ \* $ / , "" ) ;
126+
127+ // Skip if we already have this alias from webpack config
128+ if ( aliases . has ( alias ) ) continue ;
129+
130+ // Get the first target path
131+ const targetPattern = targets [ 0 ] ;
132+ if ( targetPattern ) {
133+ // Convert absolute or relative path to relative directory
134+ let targetPath = targetPattern
135+ . replace ( / \/ \* $ / , "" ) // Remove trailing /*
136+ . replace ( / ^ \. \/ / , "" ) ; // Remove leading ./
137+
138+ // If it's an absolute path, make it relative to project root
139+ if ( path . isAbsolute ( targetPath ) ) {
140+ targetPath = path . relative ( compiler . context , targetPath ) ;
141+ }
141142
142143 aliases . set ( alias , targetPath ) ;
143144 }
144145 }
145146 }
146147 } catch ( e ) {
147- console . warn ( "[CodePress] Error reading tsconfig.json:" , e ) ;
148+ console . warn ( "[CodePress] Error loading tsconfig.json paths :" , e ) ;
148149 }
150+ }
149151
150- // Fallback: Next.js convention is @/* -> ./src/*
151- if ( ! aliases . has ( "@" ) ) {
152- const srcDir = path . join ( compiler . context , "src" ) ;
153- if ( fs . existsSync ( srcDir ) ) {
154- aliases . set ( "@" , "src" ) ;
155- }
152+ // Fallback: Next.js convention is @/* -> ./src/*
153+ // Only applies if no @ alias was configured
154+ if ( ! aliases . has ( "@" ) ) {
155+ const srcDir = path . join ( compiler . context , "src" ) ;
156+ if ( fs . existsSync ( srcDir ) ) {
157+ aliases . set ( "@" , "src" ) ;
156158 }
157159 }
158160
0 commit comments