@@ -139,12 +139,15 @@ export async function scaffoldMonorepo(projectNameArg, options) {
139139 { title : 'Python (FastAPI)' , value : 'python' } ,
140140 { title : 'Go (Fiber-like)' , value : 'go' } ,
141141 { title : 'Java (Spring Boot)' , value : 'java' } ,
142- { title : 'Frontend (Next.js)' , value : 'frontend' }
142+ { title : 'Frontend (Next.js)' , value : 'frontend' } ,
143+ { title : 'Remix' , value : 'remix' } ,
144+ { title : 'Astro' , value : 'astro' } ,
145+ { title : 'SvelteKit' , value : 'sveltekit' }
143146 ] ;
144147 const templateMap = { java : 'spring-boot' } ;
145148 let services = [ ] ;
146149 const reservedNames = new Set ( [ 'scripts' , 'packages' , 'apps' , 'node_modules' , 'docker' , 'compose' , 'compose.yaml' ] ) ;
147- const defaultPorts = { frontend : 3000 , node : 3001 , go : 3002 , java : 3003 , python : 3004 } ;
150+ const defaultPorts = { frontend : 3000 , node : 3001 , go : 3002 , java : 3003 , python : 3004 , remix : 3005 , astro : 3006 , sveltekit : 3007 } ;
148151
149152 if ( options . services ) {
150153 const validValues = allServiceChoices . map ( c => c . value ) ;
@@ -330,29 +333,58 @@ export async function scaffoldMonorepo(projectNameArg, options) {
330333 console . log ( chalk . yellow ( `⚠️ create-next-app failed: ${ e . message } . Using template.` ) ) ;
331334 }
332335 }
336+ // Strict external generators for new frameworks: abort on failure (no internal fallback yet)
337+ if ( svcType === 'remix' ) {
338+ try {
339+ console . log ( chalk . cyan ( '⚙️ Running Remix generator (create-remix)...' ) ) ;
340+ await execa ( 'npx' , [ '--yes' , 'create-remix@latest' , '.' , '--template' , 'remix' ] , { cwd : dest , stdio : 'inherit' } ) ;
341+ usedGenerator = true ;
342+ } catch ( e ) {
343+ console . error ( chalk . red ( `❌ create-remix failed: ${ e . message } . Aborting scaffold for this service.` ) ) ;
344+ continue ; // skip creating this service
345+ }
346+ } else if ( svcType === 'astro' ) {
347+ try {
348+ console . log ( chalk . cyan ( '⚙️ Running Astro generator (create-astro)...' ) ) ;
349+ await execa ( 'npx' , [ '--yes' , 'create-astro@latest' , '--' , '--template' , 'minimal' ] , { cwd : dest , stdio : 'inherit' } ) ;
350+ usedGenerator = true ;
351+ } catch ( e ) {
352+ console . error ( chalk . red ( `❌ create-astro failed: ${ e . message } . Aborting scaffold for this service.` ) ) ;
353+ continue ;
354+ }
355+ } else if ( svcType === 'sveltekit' ) {
356+ try {
357+ console . log ( chalk . cyan ( '⚙️ Running SvelteKit generator (create-svelte)...' ) ) ;
358+ await execa ( 'npx' , [ '--yes' , 'create-svelte@latest' , '.' , '--template' , 'skeleton' ] , { cwd : dest , stdio : 'inherit' } ) ;
359+ usedGenerator = true ;
360+ } catch ( e ) {
361+ console . error ( chalk . red ( `❌ create-svelte failed: ${ e . message } . Aborting scaffold for this service.` ) ) ;
362+ continue ;
363+ }
364+ }
333365 if ( ! usedGenerator ) {
334- if ( await fs . pathExists ( src ) && ( await fs . readdir ( src ) ) . length > 0 ) {
335- await fs . copy ( src , dest , { overwrite : true } ) ;
336-
337- // Dynamically update the name field in package.json for Node.js services
338- if ( svcType === 'node' ) {
339- const packageJsonPath = path . join ( dest , 'package.json' ) ;
340- if ( await fs . pathExists ( packageJsonPath ) ) {
341- const packageJson = await fs . readJSON ( packageJsonPath ) ;
342- packageJson . name = `@${ projectNameArg || 'polyglot' } /${ svcName } ` ; // Ensure unique name
343- await fs . writeJSON ( packageJsonPath , packageJson , { spaces : 2 } ) ;
366+ // Non-framework services use internal templates
367+ if ( svcType !== 'remix' && svcType !== 'astro' && svcType !== 'sveltekit' ) {
368+ if ( await fs . pathExists ( src ) && ( await fs . readdir ( src ) ) . length > 0 ) {
369+ await fs . copy ( src , dest , { overwrite : true } ) ;
370+ if ( svcType === 'node' ) {
371+ const packageJsonPath = path . join ( dest , 'package.json' ) ;
372+ if ( await fs . pathExists ( packageJsonPath ) ) {
373+ const packageJson = await fs . readJSON ( packageJsonPath ) ;
374+ packageJson . name = `@${ projectNameArg || 'polyglot' } /${ svcName } ` ;
375+ await fs . writeJSON ( packageJsonPath , packageJson , { spaces : 2 } ) ;
376+ }
344377 }
345- }
346-
347- if ( templateFolder === 'spring-boot' ) {
348- const propTxt = path . join ( dest , 'src/main/resources/application.properties.txt' ) ;
349- const prop = path . join ( dest , 'src/main/resources/application.properties' ) ;
350- if ( await fs . pathExists ( propTxt ) && ! ( await fs . pathExists ( prop ) ) ) {
351- await fs . move ( propTxt , prop ) ;
378+ if ( templateFolder === 'spring-boot' ) {
379+ const propTxt = path . join ( dest , 'src/main/resources/application.properties.txt' ) ;
380+ const prop = path . join ( dest , 'src/main/resources/application.properties' ) ;
381+ if ( await fs . pathExists ( propTxt ) && ! ( await fs . pathExists ( prop ) ) ) {
382+ await fs . move ( propTxt , prop ) ;
383+ }
352384 }
385+ } else {
386+ await fs . writeFile ( path . join ( dest , 'README.md' ) , `# ${ svcName } service\n\nScaffolded by create-polyglot.` ) ;
353387 }
354- } else {
355- await fs . writeFile ( path . join ( dest , 'README.md' ) , `# ${ svcName } service\n\nScaffolded by create-polyglot.` ) ;
356388 }
357389 }
358390
@@ -444,7 +476,7 @@ export async function scaffoldMonorepo(projectNameArg, options) {
444476 const dockerfile = path . join ( svcDir , 'Dockerfile' ) ;
445477 if ( ! ( await fs . pathExists ( dockerfile ) ) ) {
446478 let dockerContent = '' ;
447- if ( svcObj . type === 'node' || svcObj . type === 'frontend' ) {
479+ if ( svcObj . type === 'node' || svcObj . type === 'frontend' || [ 'remix' , 'astro' , 'sveltekit' ] . includes ( svcObj . type ) ) {
448480 dockerContent = `# ${ svcObj . name } (${ svcObj . type } ) service\nFROM node:20-alpine AS deps\nWORKDIR /app\nCOPY package*.json ./\nRUN npm install --omit=dev || true\nCOPY . .\nEXPOSE ${ port } \nCMD [\"npm\", \"run\", \"dev\"]\n` ;
449481 } else if ( svcObj . type === 'python' ) {
450482 dockerContent = `FROM python:3.12-slim\nWORKDIR /app\nCOPY requirements.txt ./\nRUN pip install --no-cache-dir -r requirements.txt\nCOPY . .\nEXPOSE ${ port } \nCMD [\"uvicorn\", \"app.main:app\", \"--host\", \"0.0.0.0\", \"--port\", \"${ port } \"]\n` ;
0 commit comments