11const webpack = require ( 'webpack' ) ;
22const path = require ( 'path' ) ;
3+ const fs = require ( 'fs' ) ;
34const buildSingleVersion = process . env . BUILD_SINGLE_VERSION === 'true' ;
45
56exports . onCreateWebpackConfig = ( { actions, getConfig } ) => {
67 const config = getConfig ( ) ;
78
9+ // Custom resolver plugin to handle dynamic aliases for CSS imports
10+ // This hooks into webpack's resolver to catch all module resolutions including CSS
11+ class DynamicAliasResolverPlugin {
12+ apply ( resolver ) {
13+ // Hook into 'resolve' hook and run it with high priority (early in the chain)
14+ resolver . hooks . resolve . tapAsync ( {
15+ name : 'DynamicAliasResolverPlugin' ,
16+ stage : 1 , // Run early, before AliasPlugin (which runs at stage 10)
17+ } , ( request , resolveContext , callback ) => {
18+ // Handle ~hds-core imports (CSS/SCSS imports)
19+ if ( request && request . request && request . request . startsWith ( '~hds-core' ) ) {
20+ // Get context path - try multiple possible locations
21+ const contextPath = request . context ?. path ||
22+ request . path ||
23+ ( resolveContext && resolveContext . issuer ) ||
24+ '' ;
25+
26+ // Normalize path separators to handle Windows and POSIX paths uniformly
27+ const normalizedContextPath = contextPath . split ( path . sep ) . join ( '/' ) ;
28+
29+ // Extract version from context path
30+ // Use word boundary or path separator to ensure complete version matching
31+ const versionMatch = normalizedContextPath . match ( / (?: d o c s - r e l e a s e - | h e l s i n k i - d e s i g n - s y s t e m - | \. p r e v i o u s - v e r s i o n s \/ h e l s i n k i - d e s i g n - s y s t e m - ) ( \d + \. \d + \. \d + ) (?: \/ | $ ) / ) ;
32+ if ( versionMatch ) {
33+ const fullVersion = versionMatch [ 1 ] ;
34+ // Replace ~hds-core with hds-core-{version}
35+ const newRequest = request . request . replace ( '~hds-core' , `hds-core-${ fullVersion } ` ) ;
36+ const newRequestObj = {
37+ ...request ,
38+ request : newRequest
39+ } ;
40+ // Continue resolution with the modified request
41+ return resolver . doResolve ( resolver . hooks . resolve , newRequestObj , null , resolveContext , callback ) ;
42+ }
43+ }
44+ // Continue with normal resolution
45+ return callback ( ) ;
46+ } ) ;
47+ }
48+ }
49+
850 config . plugins . push (
951 new webpack . NormalModuleReplacementPlugin (
10- / h d s - c o r e | h d s - r e a c t / ,
52+ / ( ~ ? h d s - c o r e | h d s - r e a c t ) / ,
1153 resource => {
12- if ( resource . context . includes ( '.cache/gatsby-source-git/docs-release-2.' ) ) {
13- resource . request = resource . request . replace ( 'hds-core' , 'hds-2-core' ) ;
14- resource . request = resource . request . replace ( 'hds-react' , 'hds-2-react' ) ;
54+ // Skip if already versioned (prevent double replacement)
55+ // Check for pattern like hds-core-X.Y.Z or hds-react-X.Y.Z
56+ if ( resource . request . match ( / h d s - ( c o r e | r e a c t ) - \d + \. \d + \. \d + / ) ) {
57+ return ;
1558 }
16- if ( resource . context . includes ( '.cache/gatsby-source-git/docs-release-3.' ) ) {
17- resource . request = resource . request . replace ( 'hds-core' , 'hds-3-core' ) ;
18- resource . request = resource . request . replace ( 'hds-react' , 'hds-3-react' ) ;
59+
60+ // Dynamically extract full version from path
61+ // Match patterns like:
62+ // - docs-release-X.Y.Z (from sourceInstanceName)
63+ // - helsinki-design-system-X.Y.Z (from .previous-versions path)
64+ // - .previous-versions/helsinki-design-system-X.Y.Z (full path)
65+ // Normalize path separators to handle Windows and POSIX paths uniformly
66+ const normalizedContext = resource . context . split ( path . sep ) . join ( '/' ) ;
67+ // Use word boundary or path separator to ensure complete version matching
68+ const versionMatch = normalizedContext . match ( / (?: d o c s - r e l e a s e - | h e l s i n k i - d e s i g n - s y s t e m - | \. p r e v i o u s - v e r s i o n s \/ h e l s i n k i - d e s i g n - s y s t e m - ) ( \d + \. \d + \. \d + ) (?: \/ | $ ) / ) ;
69+ if ( versionMatch ) {
70+ const fullVersion = versionMatch [ 1 ] ;
71+
72+ // Replace ~hds-core with hds-core-{version} (remove ~)
73+ if ( resource . request . includes ( '~hds-core' ) ) {
74+ resource . request = resource . request . replace ( / ~ h d s - c o r e / g, `hds-core-${ fullVersion } ` ) ;
75+ }
76+ // Replace hds-core with hds-core-{version}
77+ else if ( resource . request . includes ( 'hds-core' ) ) {
78+ resource . request = resource . request . replace ( / h d s - c o r e (? ! - \d + \. \d + \. \d + ) / g, `hds-core-${ fullVersion } ` ) ;
79+ }
80+ // Replace hds-react with hds-react-{version}
81+ if ( resource . request . includes ( 'hds-react' ) ) {
82+ resource . request = resource . request . replace ( / h d s - r e a c t (? ! - \d + \. \d + \. \d + ) / g, `hds-react-${ fullVersion } ` ) ;
83+ }
1984 }
2085 }
2186 )
2287 ) ;
2388
89+
2490 actions . setWebpackConfig ( {
2591 plugins : [
2692 // We need to provide a polyfill for react-live library to make it work with the latest Gatsby: https://webpack.js.org/blog/2020-10-10-webpack-5-release/#automatic-nodejs-polyfills-removed
@@ -32,10 +98,13 @@ exports.onCreateWebpackConfig = ({ actions, getConfig }) => {
3298 resolve : {
3399 alias : {
34100 fs$ : path . resolve ( __dirname , 'src/fs.js' ) ,
35- '~hds-core' : 'hds-2-core' ,
36101 'hds-react' : 'hds-react/lib' ,
37102 stream : false ,
38103 } ,
104+ plugins : [
105+ new DynamicAliasResolverPlugin ( ) ,
106+ ...( config . resolve . plugins || [ ] ) ,
107+ ] ,
39108 fallback : {
40109 crypto : require . resolve ( 'crypto-browserify' ) ,
41110 } ,
@@ -91,10 +160,9 @@ exports.createPages = async ({ actions, graphql }) => {
91160 parent {
92161 ... on File {
93162 relativePath
163+ absolutePath
94164 ${ ! buildSingleVersion ?
95- ` gitRemote {
96- ref
97- }` : `` }
165+ ` sourceInstanceName` : `` }
98166 }
99167 }
100168 }
@@ -180,30 +248,78 @@ exports.createPages = async ({ actions, graphql }) => {
180248
181249 // Create pages dynamically
182250 result . data . allMdx . edges . forEach ( ( { node } ) => {
183- const gitRemote = node . parent ?. gitRemote ?. ref ;
184- const pathWithVersion = path . join ( '/' , gitRemote || '' , node . frontmatter . slug ) ;
251+ const sourceInstanceName = node . parent ?. sourceInstanceName ;
252+ // Extract version from sourceInstanceName (filesystem source)
253+ const versionFromSource = sourceInstanceName ?. startsWith ( 'docs-release-' )
254+ ? sourceInstanceName . replace ( 'docs-release-' , '' )
255+ : null ;
256+ const versionRef = versionFromSource ? `release-${ versionFromSource } ` : null ;
257+ const pathWithVersion = path . join ( '/' , versionRef || '' , node . frontmatter . slug ) ;
185258
186259 try {
187260 const pageTemplate = require . resolve ( './src/components/ContentLayoutWrapper.js' ) ;
188- const contentPath = './src/docs/' + node . parent . relativePath . replace ( 'site/src/docs/' , '' ) ;
261+ // Handle relativePath for both versioned sources and current docs
262+ const rawRelativePath = node . parent ?. relativePath || '' ;
263+ const normalizedRelativePath = rawRelativePath . replace ( / \\ / g, '/' ) ;
264+ const docsPrefix = 'site/src/docs/' ;
265+ const docsRelativePath = normalizedRelativePath . includes ( docsPrefix )
266+ ? normalizedRelativePath . substring ( normalizedRelativePath . indexOf ( docsPrefix ) + docsPrefix . length )
267+ : normalizedRelativePath ;
268+ const contentPath = path . posix . join ( './src/docs' , docsRelativePath ) ;
189269
190- console . log ( 'createPage() ' + ( gitRemote ? gitRemote : 'latest' ) + ' ' + contentPath ) ;
270+ console . log ( 'createPage() ' + ( versionRef ? versionRef : 'latest' ) + ' ' + contentPath ) ;
191271
192- const pageContent = gitRemote
193- ? require . resolve ( `./.cache/gatsby-source-git/docs-${ gitRemote } /${ node . parent . relativePath } ` )
272+ const pageContent = versionRef
273+ ? ( ( ) => {
274+ // For filesystem sources, use the absolutePath directly
275+ const absolutePath = node . parent ?. absolutePath ;
276+ if ( absolutePath && fs . existsSync ( absolutePath ) ) {
277+ try {
278+ return require . resolve ( absolutePath ) ;
279+ } catch ( e ) {
280+ console . warn ( `Could not resolve absolute path ${ absolutePath } : ${ e . message } ` ) ;
281+ }
282+ }
283+ // Fallback: construct path from version and docsRelativePath
284+ const version = versionRef . replace ( 'release-' , '' ) ;
285+ // Use the already-normalized docsRelativePath instead of node.parent.relativePath
286+ // to avoid double path segments
287+ const localPath = path . resolve ( __dirname , `.previous-versions/helsinki-design-system-${ version } /site/src/docs/${ docsRelativePath } ` ) ;
288+
289+ if ( fs . existsSync ( localPath ) ) {
290+ try {
291+ return require . resolve ( localPath ) ;
292+ } catch ( e ) {
293+ console . warn ( `Could not resolve local path ${ localPath } : ${ e . message } ` ) ;
294+ }
295+ }
296+ // Last resort: try contentPath (for latest docs)
297+ try {
298+ return require . resolve ( contentPath ) ;
299+ } catch ( e ) {
300+ console . warn ( `Could not resolve any path for ${ sourceInstanceName } /${ node . parent . relativePath } : ${ e . message } ` ) ;
301+ throw e ;
302+ }
303+ } ) ( )
194304 : require . resolve ( contentPath ) ;
195305
196306 // filter out duplicate slug entries.
197307 const allPages = Object . values (
198308 Object . fromEntries (
199309 mdxPageData
200- . filter ( ( { node } ) => node ?. parent ?. gitRemote ?. ref === gitRemote )
310+ . filter ( ( { node } ) => {
311+ const nodeSourceInstanceName = node ?. parent ?. sourceInstanceName ;
312+ const nodeVersionRef = nodeSourceInstanceName ?. startsWith ( 'docs-release-' )
313+ ? `release-${ nodeSourceInstanceName . replace ( 'docs-release-' , '' ) } `
314+ : null ;
315+ return nodeVersionRef === versionRef ;
316+ } )
201317 . filter ( ( { node } ) => node . frontmatter . slug && node . frontmatter . navTitle )
202318 . map ( ( { node } ) => [ node . frontmatter . slug , { ...node . frontmatter , ...node . fields } ] )
203319 ) ,
204320 ) ;
205321
206- const currentMenuItem = resolveCurrentMenuItem ( gitRemote , uiMenuLinks , node . frontmatter . slug ) ;
322+ const currentMenuItem = resolveCurrentMenuItem ( versionRef , uiMenuLinks , node . frontmatter . slug ) ;
207323 const uiSubMenuLinks = getUiSubMenuLinks ( allPages , uiMenuLinks , currentMenuItem ) ;
208324
209325 createPage ( {
0 commit comments