uniweb 0.7.2 → 0.7.4
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 +3 -3
- package/package.json +1 -1
- package/src/commands/add.js +9 -1
- package/src/index.js +47 -8
- package/src/templates/resolver.js +1 -1
- package/src/utils/scaffold.js +21 -0
package/README.md
CHANGED
|
@@ -53,7 +53,7 @@ pnpm create uniweb my-site --template dynamic
|
|
|
53
53
|
pnpm create uniweb my-site --template extensions
|
|
54
54
|
|
|
55
55
|
# Default starter (foundation + site + sample content)
|
|
56
|
-
pnpm create uniweb my-site
|
|
56
|
+
pnpm create uniweb my-site --template starter
|
|
57
57
|
|
|
58
58
|
# Blank workspace (grow with `add`)
|
|
59
59
|
pnpm create uniweb my-site --template blank
|
|
@@ -260,8 +260,8 @@ The workspace grows organically. `add` handles placement, wires dependencies, up
|
|
|
260
260
|
```bash
|
|
261
261
|
pnpm create uniweb acme --template blank
|
|
262
262
|
cd acme
|
|
263
|
-
uniweb add foundation
|
|
264
|
-
uniweb add site
|
|
263
|
+
npx uniweb add foundation
|
|
264
|
+
npx uniweb add site
|
|
265
265
|
pnpm install && pnpm dev
|
|
266
266
|
```
|
|
267
267
|
|
package/package.json
CHANGED
package/src/commands/add.js
CHANGED
|
@@ -14,7 +14,7 @@ import { readFile, writeFile } from 'node:fs/promises'
|
|
|
14
14
|
import { join, relative } from 'node:path'
|
|
15
15
|
import prompts from 'prompts'
|
|
16
16
|
import yaml from 'js-yaml'
|
|
17
|
-
import { scaffoldFoundation, scaffoldSite, applyContent } from '../utils/scaffold.js'
|
|
17
|
+
import { scaffoldFoundation, scaffoldSite, applyContent, mergeTemplateDependencies } from '../utils/scaffold.js'
|
|
18
18
|
import {
|
|
19
19
|
readWorkspaceConfig,
|
|
20
20
|
addWorkspaceGlob,
|
|
@@ -469,6 +469,14 @@ async function applyFromTemplate(templateId, packageType, targetDir, projectName
|
|
|
469
469
|
onProgress: (msg) => info(` ${msg}`),
|
|
470
470
|
})
|
|
471
471
|
|
|
472
|
+
// Merge template dependencies
|
|
473
|
+
if (metadata.dependencies) {
|
|
474
|
+
const deps = metadata.dependencies[packageType] || metadata.dependencies[match?.name]
|
|
475
|
+
if (deps) {
|
|
476
|
+
await mergeTemplateDependencies(join(targetDir, 'package.json'), deps)
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
472
480
|
// If site content applied, inform about expected section types
|
|
473
481
|
if (packageType === 'site' && metadata.components) {
|
|
474
482
|
log('')
|
package/src/index.js
CHANGED
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
parseTemplateId,
|
|
28
28
|
} from './templates/index.js'
|
|
29
29
|
import { validateTemplate } from './templates/validator.js'
|
|
30
|
-
import { scaffoldWorkspace, scaffoldFoundation, scaffoldSite, applyContent, applyStarter } from './utils/scaffold.js'
|
|
30
|
+
import { scaffoldWorkspace, scaffoldFoundation, scaffoldSite, applyContent, applyStarter, mergeTemplateDependencies } from './utils/scaffold.js'
|
|
31
31
|
|
|
32
32
|
// Colors for terminal output
|
|
33
33
|
const colors = {
|
|
@@ -40,6 +40,19 @@ const colors = {
|
|
|
40
40
|
red: '\x1b[31m',
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
// Template choices for interactive prompt
|
|
44
|
+
const TEMPLATE_CHOICES = [
|
|
45
|
+
{ title: 'Starter', value: 'starter', description: 'Foundation + site + sample content' },
|
|
46
|
+
{ title: 'Blank', value: 'blank', description: 'Empty workspace — grow with uniweb add' },
|
|
47
|
+
{ title: 'Marketing', value: 'marketing', description: 'Landing page, features, pricing, testimonials' },
|
|
48
|
+
{ title: 'Docs', value: 'docs', description: 'Documentation with sidebar and search' },
|
|
49
|
+
{ title: 'Academic', value: 'academic', description: 'Research site with publications and team' },
|
|
50
|
+
{ title: 'Dynamic', value: 'dynamic', description: 'Live API data fetching with loading states' },
|
|
51
|
+
{ title: 'International', value: 'international', description: 'Multilingual site with i18n and blog' },
|
|
52
|
+
{ title: 'Store', value: 'store', description: 'E-commerce with product grid' },
|
|
53
|
+
{ title: 'Extensions', value: 'extensions', description: 'Multi-foundation with visual effects extension' },
|
|
54
|
+
]
|
|
55
|
+
|
|
43
56
|
function log(message) {
|
|
44
57
|
console.log(message)
|
|
45
58
|
}
|
|
@@ -202,6 +215,14 @@ async function createFromContentTemplate(projectDir, projectName, metadata, temp
|
|
|
202
215
|
onProgress?.(`Applying ${metadata.name} content to ${pkg.name}...`)
|
|
203
216
|
await applyContent(contentDir.dir, fullPath, { projectName }, { onProgress, onWarning })
|
|
204
217
|
}
|
|
218
|
+
|
|
219
|
+
// Merge template dependencies into package.json
|
|
220
|
+
if (metadata.dependencies) {
|
|
221
|
+
const deps = metadata.dependencies[pkg.name] || metadata.dependencies[pkg.type]
|
|
222
|
+
if (deps) {
|
|
223
|
+
await mergeTemplateDependencies(join(fullPath, 'package.json'), deps)
|
|
224
|
+
}
|
|
225
|
+
}
|
|
205
226
|
}
|
|
206
227
|
|
|
207
228
|
success(`Created project: ${projectName}`)
|
|
@@ -375,6 +396,22 @@ async function main() {
|
|
|
375
396
|
process.exit(1)
|
|
376
397
|
}
|
|
377
398
|
|
|
399
|
+
// Prompt for template if not specified via --template
|
|
400
|
+
if (!templateType) {
|
|
401
|
+
const templateResponse = await prompts({
|
|
402
|
+
type: 'select',
|
|
403
|
+
name: 'template',
|
|
404
|
+
message: 'Template:',
|
|
405
|
+
choices: TEMPLATE_CHOICES,
|
|
406
|
+
}, {
|
|
407
|
+
onCancel: () => {
|
|
408
|
+
log('\nScaffolding cancelled.')
|
|
409
|
+
process.exit(0)
|
|
410
|
+
},
|
|
411
|
+
})
|
|
412
|
+
templateType = templateResponse.template
|
|
413
|
+
}
|
|
414
|
+
|
|
378
415
|
const effectiveName = displayName || projectName
|
|
379
416
|
|
|
380
417
|
// Create project directory
|
|
@@ -396,8 +433,8 @@ async function main() {
|
|
|
396
433
|
onProgress: progressCb,
|
|
397
434
|
onWarning: warningCb,
|
|
398
435
|
})
|
|
399
|
-
} else if (
|
|
400
|
-
//
|
|
436
|
+
} else if (templateType === 'starter') {
|
|
437
|
+
// Starter: foundation + site + sample content
|
|
401
438
|
log('\nCreating project...')
|
|
402
439
|
await createFromPackageTemplates(projectDir, effectiveName, {
|
|
403
440
|
onProgress: progressCb,
|
|
@@ -431,7 +468,7 @@ async function main() {
|
|
|
431
468
|
log(`${colors.yellow}Troubleshooting:${colors.reset}`)
|
|
432
469
|
log(` • Check your network connection`)
|
|
433
470
|
log(` • Official templates require GitHub access (may be blocked by corporate networks)`)
|
|
434
|
-
log(` • Try the
|
|
471
|
+
log(` • Try the starter template instead: ${colors.cyan}uniweb create ${projectName} --template starter${colors.reset}`)
|
|
435
472
|
process.exit(1)
|
|
436
473
|
}
|
|
437
474
|
}
|
|
@@ -460,8 +497,8 @@ async function main() {
|
|
|
460
497
|
if (templateType === 'blank') {
|
|
461
498
|
log(`Next steps:\n`)
|
|
462
499
|
log(` ${colors.cyan}cd ${projectName}${colors.reset}`)
|
|
463
|
-
log(` ${colors.cyan}uniweb add foundation${colors.reset}`)
|
|
464
|
-
log(` ${colors.cyan}uniweb add site${colors.reset}`)
|
|
500
|
+
log(` ${colors.cyan}npx uniweb add foundation${colors.reset}`)
|
|
501
|
+
log(` ${colors.cyan}npx uniweb add site${colors.reset}`)
|
|
465
502
|
log(` ${colors.cyan}pnpm install${colors.reset}`)
|
|
466
503
|
log(` ${colors.cyan}pnpm dev${colors.reset}`)
|
|
467
504
|
} else {
|
|
@@ -489,7 +526,7 @@ ${colors.bright}Commands:${colors.reset}
|
|
|
489
526
|
i18n <cmd> Internationalization (extract, sync, status)
|
|
490
527
|
|
|
491
528
|
${colors.bright}Create Options:${colors.reset}
|
|
492
|
-
--template <type> Project template (
|
|
529
|
+
--template <type> Project template (prompts if not specified)
|
|
493
530
|
--name <name> Project display name
|
|
494
531
|
--no-git Skip git repository initialization
|
|
495
532
|
|
|
@@ -525,6 +562,7 @@ ${colors.bright}i18n Commands:${colors.reset}
|
|
|
525
562
|
status Show translation coverage per locale
|
|
526
563
|
|
|
527
564
|
${colors.bright}Template Types:${colors.reset}
|
|
565
|
+
starter Foundation + site + sample content (default)
|
|
528
566
|
blank Empty workspace (grow with 'add')
|
|
529
567
|
marketing Official marketing template
|
|
530
568
|
./path/to/template Local directory
|
|
@@ -533,7 +571,8 @@ ${colors.bright}Template Types:${colors.reset}
|
|
|
533
571
|
https://github.com/user/repo GitHub URL
|
|
534
572
|
|
|
535
573
|
${colors.bright}Examples:${colors.reset}
|
|
536
|
-
npx uniweb create my-project #
|
|
574
|
+
npx uniweb create my-project # Interactive (prompts for template)
|
|
575
|
+
npx uniweb create my-project --template starter # Foundation + site + starter content
|
|
537
576
|
npx uniweb create my-project --template blank # Blank workspace
|
|
538
577
|
npx uniweb create my-project --template marketing # Official template
|
|
539
578
|
npx uniweb create my-project --template ./my-template # Local template
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
// Built-in templates (programmatic, not file-based)
|
|
6
|
-
export const BUILTIN_TEMPLATES = ['blank']
|
|
6
|
+
export const BUILTIN_TEMPLATES = ['blank', 'starter']
|
|
7
7
|
|
|
8
8
|
// Official templates from @uniweb/templates package (downloaded from GitHub releases)
|
|
9
9
|
export const OFFICIAL_TEMPLATES = ['marketing', 'academic', 'docs', 'international', 'dynamic', 'store', 'extensions']
|
package/src/utils/scaffold.js
CHANGED
|
@@ -173,3 +173,24 @@ export async function applyStarter(projectDir, context, options = {}) {
|
|
|
173
173
|
const siteTargetDir = join(projectDir, siteDir)
|
|
174
174
|
await applyContent(siteContentDir, siteTargetDir, context, options)
|
|
175
175
|
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Merge additional dependencies from a content template into a scaffolded package.json
|
|
179
|
+
*
|
|
180
|
+
* Reads the package.json at the given path, adds any deps not already present
|
|
181
|
+
* (in either dependencies or devDependencies), and writes it back.
|
|
182
|
+
*
|
|
183
|
+
* @param {string} packageJsonPath - Absolute path to package.json
|
|
184
|
+
* @param {Object} deps - Dependencies to merge (name → version)
|
|
185
|
+
*/
|
|
186
|
+
export async function mergeTemplateDependencies(packageJsonPath, deps) {
|
|
187
|
+
if (!deps || Object.keys(deps).length === 0) return
|
|
188
|
+
const pkg = JSON.parse(await fs.readFile(packageJsonPath, 'utf-8'))
|
|
189
|
+
if (!pkg.dependencies) pkg.dependencies = {}
|
|
190
|
+
for (const [name, version] of Object.entries(deps)) {
|
|
191
|
+
if (!pkg.dependencies[name] && !pkg.devDependencies?.[name]) {
|
|
192
|
+
pkg.dependencies[name] = version
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
await fs.writeFile(packageJsonPath, JSON.stringify(pkg, null, 2) + '\n')
|
|
196
|
+
}
|