diff options
Diffstat (limited to 'packages/create-astro/src/index.ts')
-rw-r--r-- | packages/create-astro/src/index.ts | 98 |
1 files changed, 86 insertions, 12 deletions
diff --git a/packages/create-astro/src/index.ts b/packages/create-astro/src/index.ts index e3487e8d4..dcb87086e 100644 --- a/packages/create-astro/src/index.ts +++ b/packages/create-astro/src/index.ts @@ -1,10 +1,13 @@ import fs from 'fs'; import path from 'path'; import { bold, cyan, gray, green, red } from 'kleur/colors'; +import fetch from 'node-fetch'; import prompts from 'prompts'; import degit from 'degit'; import yargs from 'yargs-parser'; +import { FRAMEWORKS, COUNTER_COMPONENTS } from './frameworks.js'; import { TEMPLATES } from './templates.js'; +import { createConfig } from './config.js'; const args = yargs(process.argv); prompts.override(args); @@ -19,7 +22,7 @@ export function mkdirp(dir: string) { const { version } = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf-8')); -const POSTPROCESS_FILES = ['package.json']; // some files need processing after copying. +const POSTPROCESS_FILES = ['package.json', 'astro.config.mjs', 'CHANGELOG.md']; // some files need processing after copying. export async function main() { console.log('\n' + bold('Welcome to Astro!') + gray(` (create-astro v${version})`)); @@ -40,6 +43,9 @@ export async function main() { if (!response.forceOverwrite) { process.exit(1); } + + await fs.promises.rm(cwd, { recursive: true }); + mkdirp(cwd); } } else { mkdirp(cwd); @@ -54,6 +60,10 @@ export async function main() { }, ]); + if (!options.template) { + process.exit(1); + } + const hash = args.commit ? `#${args.commit}` : ''; const templateTarget = options.template.includes('/') ? @@ -66,6 +76,25 @@ export async function main() { verbose: false, }); + const selectedTemplate = TEMPLATES.find(template => template.value === options.template); + let renderers: string[] = []; + + if (selectedTemplate?.renderers === true) { + const result = /** @type {import('./types/internal').Options} */ await prompts([ + { + type: 'multiselect', + name: 'renderers', + message: 'Which frameworks would you like to use?', + choices: FRAMEWORKS, + }, + ]); + renderers = result.renderers; + } else if (selectedTemplate?.renderers && Array.isArray(selectedTemplate.renderers)) { + renderers = selectedTemplate.renderers; + const titles = renderers.map(renderer => FRAMEWORKS.find(item => item.value === renderer)?.title).join(', '); + console.log(green(`✔`) + bold(` Using template's default renderers`) + gray(' › ') + titles); + } + // Copy try { // emitter.on('info', info => { console.log(info.message) }); @@ -78,20 +107,65 @@ export async function main() { } // Post-process in parallel - await Promise.all( - POSTPROCESS_FILES.map(async (file) => { - const fileLoc = path.join(cwd, file); - - switch (file) { - case 'package.json': { - const packageJSON = JSON.parse(await fs.promises.readFile(fileLoc, 'utf8')); - delete packageJSON.snowpack; // delete snowpack config only needed in monorepo (can mess up projects) - await fs.promises.writeFile(fileLoc, JSON.stringify(packageJSON, undefined, 2)); + await Promise.all(POSTPROCESS_FILES.map(async (file) => { + const fileLoc = path.resolve(path.join(cwd, file)); + + switch (file) { + case 'CHANGELOG.md': { + if (fs.existsSync(fileLoc)) { + await fs.promises.rm(fileLoc); + } + break; + } + case 'astro.config.mjs': { + if (selectedTemplate?.renderers !== true) { break; } + await fs.promises.writeFile(fileLoc, createConfig({ renderers })); + break; } - }) - ); + case 'package.json': { + const packageJSON = JSON.parse(await fs.promises.readFile(fileLoc, 'utf8')); + delete packageJSON.snowpack; // delete snowpack config only needed in monorepo (can mess up projects) + // Fetch latest versions of selected renderers + const rendererEntries = await Promise.all(['astro', ...renderers].map((renderer: string) => fetch(`https://registry.npmjs.org/${renderer}/latest`).then((res: any) => res.json()).then((res: any) => [renderer, `^${res['version']}`]))) as any; + packageJSON.devDependencies = { ...packageJSON.devDependencies ?? {}, ...Object.fromEntries(rendererEntries) } + await fs.promises.writeFile(fileLoc, JSON.stringify(packageJSON, undefined, 2)); + break; + } + } + })); + + // Inject framework components into starter template + if (selectedTemplate?.value === 'starter') { + let importStatements: string[] = []; + let components: string[] = []; + await Promise.all(renderers.map(async renderer => { + const component = COUNTER_COMPONENTS[renderer as keyof typeof COUNTER_COMPONENTS]; + const componentName = path.basename(component.filename, path.extname(component.filename)); + const absFileLoc = path.resolve(cwd, component.filename); + importStatements.push(`import ${componentName} from '${component.filename.replace(/^src/, '..')}';`); + components.push(`<${componentName}:visible />`); + await fs.promises.writeFile(absFileLoc, component.content); + })); + + const pageFileLoc = path.resolve(path.join(cwd, 'src', 'pages', 'index.astro')); + const content = (await fs.promises.readFile(pageFileLoc)).toString(); + const lines = content.split('\n'); + const indent = ' '; + const doc = `\n<!-- + - Use imported Framework Components directly in your markup! + - + - Note: by default, components are NOT interactive on the client. + - The \`:visible\` directive tells Astro to make it interactive. + - + - See https://github.com/snowpackjs/astro/blob/main/docs/core-concepts/component-hydration.md + --> +`; + lines.splice(41, 0, importStatements.length > 0 ? doc.split('\n').map(ln => `${indent}${ln}`).join('\n') : '', ...components.map(ln => `${indent}${ln}`)); + lines.splice(3, 0, importStatements.length > 0 ? `// Framework Component Imports` : '', ...importStatements); + await fs.promises.writeFile(pageFileLoc, lines.join('\n')) + } console.log(bold(green('✔') + ' Done!')); |