create-aerobuilt 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -0
- package/index.js +152 -0
- package/lib.js +116 -0
- package/package.json +28 -0
package/README.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# create-aerobuilt
|
|
2
|
+
|
|
3
|
+
Scaffold a new [Aero](https://github.com/aerobuilt/aero) project. Aero is an HTML-first static site generator powered by Vite.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm create aerobuilt my-app
|
|
9
|
+
cd my-app
|
|
10
|
+
pnpm dev
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Also works with npm, yarn, and `pnpm dlx`:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx create-aerobuilt@latest my-app
|
|
17
|
+
yarn create aerobuilt my-app
|
|
18
|
+
pnpm dlx create-aerobuilt my-app
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Options
|
|
22
|
+
|
|
23
|
+
| Argument | Description | Default |
|
|
24
|
+
| -------- | -------------------------- | ------------ |
|
|
25
|
+
| `<dir>` | Project name and directory | _(required)_ |
|
|
26
|
+
|
|
27
|
+
## What it does
|
|
28
|
+
|
|
29
|
+
1. Copies the minimal template into a new directory
|
|
30
|
+
2. Rewrites `package.json` with your project name
|
|
31
|
+
3. Auto-detects your package manager (pnpm > yarn > npm) and installs dependencies
|
|
32
|
+
4. Prints next steps
|
|
33
|
+
|
|
34
|
+
After scaffolding, the project has `aerobuilt` as its only framework dependency.
|
|
35
|
+
|
|
36
|
+
## Project structure
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
my-app/
|
|
40
|
+
├── client/
|
|
41
|
+
│ ├── assets/ # Styles, scripts, images
|
|
42
|
+
│ ├── components/ # Reusable .html components
|
|
43
|
+
│ ├── layouts/ # Layout wrappers with <slot>
|
|
44
|
+
│ └── pages/ # File-based routing
|
|
45
|
+
├── content/
|
|
46
|
+
│ └── site.ts # Global site data
|
|
47
|
+
├── public/ # Static assets (copied as-is)
|
|
48
|
+
├── vite.config.ts # Aero Vite plugin
|
|
49
|
+
└── tsconfig.json # Path aliases
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Links
|
|
53
|
+
|
|
54
|
+
- [GitHub](https://github.com/aerobuilt/aero)
|
|
55
|
+
- [aerobuilt on npm](https://www.npmjs.com/package/aerobuilt)
|
|
56
|
+
|
|
57
|
+
## License
|
|
58
|
+
|
|
59
|
+
MIT
|
package/index.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { cpSync, mkdirSync, existsSync, statSync, readdirSync, lstatSync } from 'fs'
|
|
4
|
+
import { dirname, join, basename } from 'path'
|
|
5
|
+
import { fileURLToPath } from 'url'
|
|
6
|
+
import { spawnSync } from 'child_process'
|
|
7
|
+
import { parseArgs, rewritePackageJson, writeReadme, findWorkspaceRoot } from './lib.js'
|
|
8
|
+
|
|
9
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
10
|
+
const startPkgDir = __dirname
|
|
11
|
+
const pkgRoot = join(startPkgDir, 'node_modules')
|
|
12
|
+
const APPS_DIR = 'dist'
|
|
13
|
+
|
|
14
|
+
const TEMPLATES = ['minimal']
|
|
15
|
+
const DEFAULT_TEMPLATE = 'minimal'
|
|
16
|
+
|
|
17
|
+
function resolveTemplatePath(templateName) {
|
|
18
|
+
const pkgName = `@aerobuilt/template-${templateName}`
|
|
19
|
+
const templatePath = join(pkgRoot, pkgName)
|
|
20
|
+
if (!existsSync(templatePath)) {
|
|
21
|
+
console.error(
|
|
22
|
+
`create-aerobuilt: template "${templateName}" not found (expected ${templatePath}).`,
|
|
23
|
+
)
|
|
24
|
+
console.error('Install dependencies with: pnpm install')
|
|
25
|
+
process.exit(1)
|
|
26
|
+
}
|
|
27
|
+
return templatePath
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function copyTemplate(src, dest) {
|
|
31
|
+
const ignore = name => {
|
|
32
|
+
if (name === 'node_modules') return true
|
|
33
|
+
if (name === '.git') return true
|
|
34
|
+
if (name === 'dist' || name === '.output') return true
|
|
35
|
+
if (name.endsWith('.log') || name === '.DS_Store') return true
|
|
36
|
+
if (name === '.vite' || name === '.nitro') return true
|
|
37
|
+
return false
|
|
38
|
+
}
|
|
39
|
+
mkdirSync(dest, { recursive: true })
|
|
40
|
+
cpSync(src, dest, {
|
|
41
|
+
recursive: true,
|
|
42
|
+
dereference: true,
|
|
43
|
+
filter: source => {
|
|
44
|
+
const name = basename(source)
|
|
45
|
+
return !ignore(name)
|
|
46
|
+
},
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function isInMonorepo() {
|
|
51
|
+
try {
|
|
52
|
+
const templatePath = join(pkgRoot, `@aerobuilt/template-${DEFAULT_TEMPLATE}`)
|
|
53
|
+
if (!existsSync(templatePath)) return false
|
|
54
|
+
return lstatSync(templatePath).isSymbolicLink()
|
|
55
|
+
} catch {
|
|
56
|
+
return false
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function installInMonorepo(targetDir) {
|
|
61
|
+
const root = findWorkspaceRoot(targetDir)
|
|
62
|
+
if (!root) {
|
|
63
|
+
console.error('create-aerobuilt: could not find workspace root (pnpm-workspace.yaml).')
|
|
64
|
+
process.exit(1)
|
|
65
|
+
}
|
|
66
|
+
const r = spawnSync('pnpm', ['install', '--no-frozen-lockfile'], {
|
|
67
|
+
stdio: 'inherit',
|
|
68
|
+
cwd: root,
|
|
69
|
+
shell: true,
|
|
70
|
+
})
|
|
71
|
+
if (r.status !== 0) {
|
|
72
|
+
console.error(
|
|
73
|
+
'create-aerobuilt: pnpm install failed. Run "pnpm install" from the repo root.',
|
|
74
|
+
)
|
|
75
|
+
process.exit(1)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function installStandalone(targetDir) {
|
|
80
|
+
const hasPnpm = existsSync(join(targetDir, 'pnpm-lock.yaml'))
|
|
81
|
+
const hasNpm = existsSync(join(targetDir, 'package-lock.json'))
|
|
82
|
+
const hasYarn = existsSync(join(targetDir, 'yarn.lock'))
|
|
83
|
+
const cmd = hasPnpm ? 'pnpm' : hasYarn ? 'yarn' : 'npm'
|
|
84
|
+
const args = hasPnpm || hasYarn ? ['install'] : ['install']
|
|
85
|
+
const r = spawnSync(cmd, args, { stdio: 'inherit', cwd: targetDir, shell: true })
|
|
86
|
+
if (r.status !== 0) {
|
|
87
|
+
console.error(
|
|
88
|
+
`create-aerobuilt: ${cmd} install failed. Run "${cmd} install" in the project directory.`,
|
|
89
|
+
)
|
|
90
|
+
process.exit(1)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function main() {
|
|
95
|
+
const { target, template } = parseArgs(process.argv)
|
|
96
|
+
|
|
97
|
+
if (!target) {
|
|
98
|
+
console.error('create-aerobuilt: missing target directory.')
|
|
99
|
+
console.error('Usage: pnpm run create-aerobuilt <dir>')
|
|
100
|
+
console.error('Example: pnpm run create-aerobuilt my-app')
|
|
101
|
+
process.exit(1)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (!TEMPLATES.includes(template)) {
|
|
105
|
+
console.error(
|
|
106
|
+
`create-aerobuilt: unknown template "${template}". Use one of: ${TEMPLATES.join(', ')}`,
|
|
107
|
+
)
|
|
108
|
+
process.exit(1)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Run from packages/create-aerobuilt: scaffold into packages/create-aerobuilt/dist/<target>
|
|
112
|
+
const inMonorepo = isInMonorepo()
|
|
113
|
+
const targetDir = inMonorepo
|
|
114
|
+
? join(startPkgDir, APPS_DIR, target)
|
|
115
|
+
: join(process.cwd(), target)
|
|
116
|
+
|
|
117
|
+
if (inMonorepo) {
|
|
118
|
+
mkdirSync(join(startPkgDir, APPS_DIR), { recursive: true })
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (existsSync(targetDir)) {
|
|
122
|
+
const stat = statSync(targetDir)
|
|
123
|
+
if (!stat.isDirectory()) {
|
|
124
|
+
console.error(`create-aerobuilt: "${target}" exists and is not a directory.`)
|
|
125
|
+
process.exit(1)
|
|
126
|
+
}
|
|
127
|
+
const files = readdirSync(targetDir)
|
|
128
|
+
if (files.length > 0) {
|
|
129
|
+
console.error(`create-aerobuilt: directory "${target}" already exists and is not empty.`)
|
|
130
|
+
process.exit(1)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const templatePath = resolveTemplatePath(template)
|
|
135
|
+
console.log(`Creating Aero app in ${target} from template "${template}"...`)
|
|
136
|
+
copyTemplate(templatePath, targetDir)
|
|
137
|
+
rewritePackageJson(targetDir, target, inMonorepo)
|
|
138
|
+
writeReadme(targetDir, target, template)
|
|
139
|
+
console.log('Installing dependencies...')
|
|
140
|
+
if (inMonorepo) {
|
|
141
|
+
installInMonorepo(targetDir)
|
|
142
|
+
} else {
|
|
143
|
+
installStandalone(targetDir)
|
|
144
|
+
}
|
|
145
|
+
console.log('')
|
|
146
|
+
console.log('Done. Next steps:')
|
|
147
|
+
console.log(` cd ${targetDir}`)
|
|
148
|
+
console.log(' pnpm dev')
|
|
149
|
+
console.log('')
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
main()
|
package/lib.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from 'fs'
|
|
2
|
+
import { dirname, join } from 'path'
|
|
3
|
+
|
|
4
|
+
const DEFAULT_TEMPLATE = 'minimal'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Parse CLI argv into { target, template }.
|
|
8
|
+
* @param {string[]} argv - process.argv
|
|
9
|
+
* @returns {{ target: string | null, template: string }}
|
|
10
|
+
*/
|
|
11
|
+
export function parseArgs(argv) {
|
|
12
|
+
const args = argv.slice(2)
|
|
13
|
+
let target = null
|
|
14
|
+
let template = DEFAULT_TEMPLATE
|
|
15
|
+
for (let i = 0; i < args.length; i++) {
|
|
16
|
+
if (args[i] === '--template' && args[i + 1]) {
|
|
17
|
+
template = args[++i]
|
|
18
|
+
continue
|
|
19
|
+
}
|
|
20
|
+
if (!args[i].startsWith('-') && !target) {
|
|
21
|
+
target = args[i]
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return { target, template }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Rewrite package.json in targetDir: set name to projectName; if !inMonorepo, replace workspace:* with *.
|
|
29
|
+
* @param {string} targetDir
|
|
30
|
+
* @param {string} projectName
|
|
31
|
+
* @param {boolean} inMonorepo
|
|
32
|
+
*/
|
|
33
|
+
export function rewritePackageJson(targetDir, projectName, inMonorepo) {
|
|
34
|
+
const pkgPath = join(targetDir, 'package.json')
|
|
35
|
+
if (!existsSync(pkgPath)) return
|
|
36
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'))
|
|
37
|
+
pkg.name = projectName
|
|
38
|
+
if (!inMonorepo) {
|
|
39
|
+
const rewrite = deps => {
|
|
40
|
+
if (!deps) return
|
|
41
|
+
for (const key of Object.keys(deps)) {
|
|
42
|
+
if (deps[key] === 'workspace:*') deps[key] = '*'
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
rewrite(pkg.dependencies)
|
|
46
|
+
rewrite(pkg.devDependencies)
|
|
47
|
+
}
|
|
48
|
+
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n')
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Walk up from fromDir to find directory containing pnpm-workspace.yaml.
|
|
53
|
+
* @param {string} fromDir
|
|
54
|
+
* @returns {string | null}
|
|
55
|
+
*/
|
|
56
|
+
export function findWorkspaceRoot(fromDir) {
|
|
57
|
+
let dir = fromDir
|
|
58
|
+
for (;;) {
|
|
59
|
+
if (existsSync(join(dir, 'pnpm-workspace.yaml'))) return dir
|
|
60
|
+
const parent = dirname(dir)
|
|
61
|
+
if (parent === dir) return null
|
|
62
|
+
dir = parent
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Write a project-appropriate README.md into targetDir.
|
|
68
|
+
* @param {string} targetDir
|
|
69
|
+
* @param {string} projectName
|
|
70
|
+
* @param {string} template
|
|
71
|
+
*/
|
|
72
|
+
export function writeReadme(targetDir, projectName, template) {
|
|
73
|
+
const lines = [
|
|
74
|
+
`# ${projectName}`,
|
|
75
|
+
'',
|
|
76
|
+
`Built with [Aero](https://github.com/aerobuilt/aero) — an HTML-first static site generator powered by Vite.`,
|
|
77
|
+
'',
|
|
78
|
+
'## Commands',
|
|
79
|
+
'',
|
|
80
|
+
'| Command | Description |',
|
|
81
|
+
'|---|---|',
|
|
82
|
+
'| `pnpm dev` | Start the dev server |',
|
|
83
|
+
'| `pnpm build` | Build for production |',
|
|
84
|
+
'| `pnpm preview` | Preview the built site |',
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
lines.push(
|
|
88
|
+
'',
|
|
89
|
+
'## Project Structure',
|
|
90
|
+
'',
|
|
91
|
+
'```',
|
|
92
|
+
`${projectName}/`,
|
|
93
|
+
'├── client/',
|
|
94
|
+
'│ ├── assets/ # Styles, scripts, images',
|
|
95
|
+
'│ ├── components/ # Reusable .html components',
|
|
96
|
+
'│ ├── layouts/ # Layout wrappers with <slot>',
|
|
97
|
+
'│ └── pages/ # File-based routing',
|
|
98
|
+
'├── content/',
|
|
99
|
+
'│ └── site.ts # Global site data',
|
|
100
|
+
'├── public/ # Static assets (copied as-is)',
|
|
101
|
+
'├── vite.config.ts # Aero Vite plugin',
|
|
102
|
+
'└── tsconfig.json # Path aliases',
|
|
103
|
+
'```',
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
lines.push(
|
|
107
|
+
'',
|
|
108
|
+
'## Learn More',
|
|
109
|
+
'',
|
|
110
|
+
'- [Aero on GitHub](https://github.com/aerobuilt/aero)',
|
|
111
|
+
'- [aerobuilt on npm](https://www.npmjs.com/package/aerobuilt)',
|
|
112
|
+
'',
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
writeFileSync(join(targetDir, 'README.md'), lines.join('\n'))
|
|
116
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-aerobuilt",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Jamie Wilson",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/aerobuilt/aero.git",
|
|
10
|
+
"directory": "packages/create-aerobuilt"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/aerobuilt/aero",
|
|
13
|
+
"files": [
|
|
14
|
+
"index.js",
|
|
15
|
+
"lib.js",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"bin": {
|
|
19
|
+
"create-aerobuilt": "index.js"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@aerobuilt/template-minimal": "0.1.0"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"create": "node .",
|
|
26
|
+
"create-aerobuilt": "node index.js"
|
|
27
|
+
}
|
|
28
|
+
}
|