@uniweb/templates 0.1.0 → 0.1.2

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 ADDED
@@ -0,0 +1,277 @@
1
+ # @uniweb/templates
2
+
3
+ Template processing engine and official templates for the Uniweb CLI.
4
+
5
+ ## Overview
6
+
7
+ This package provides:
8
+ 1. **Template processing engine** - Handlebars-based file processing with variable substitution
9
+ 2. **Official templates** - Showcase templates like `marketing`, `docs`, `learning`
10
+ 3. **Validation utilities** - Version checking and template structure validation
11
+
12
+ ## Usage
13
+
14
+ ### From CLI
15
+
16
+ ```bash
17
+ # Use an official template
18
+ npx uniweb create my-project --template marketing
19
+
20
+ # Templates are resolved in order:
21
+ # 1. Built-in (single, multi) - in CLI
22
+ # 2. Official (@uniweb/templates) - marketing, docs, learning
23
+ # 3. npm packages - @scope/template-name
24
+ # 4. GitHub repos - github:user/repo
25
+ ```
26
+
27
+ ### Programmatic API
28
+
29
+ ```javascript
30
+ import { applyBuiltinTemplate, hasTemplate, listBuiltinTemplates } from '@uniweb/templates'
31
+
32
+ // Check if a template exists
33
+ if (hasTemplate('marketing')) {
34
+ // Apply template to a directory
35
+ await applyBuiltinTemplate('marketing', './my-project', {
36
+ projectName: 'my-project',
37
+ year: new Date().getFullYear()
38
+ })
39
+ }
40
+
41
+ // List available templates
42
+ const templates = await listBuiltinTemplates()
43
+ // [{ id: 'marketing', name: 'Marketing Starter', ... }]
44
+ ```
45
+
46
+ ## Creating Templates
47
+
48
+ ### Directory Structure
49
+
50
+ Each template lives in `templates/<name>/` with this structure:
51
+
52
+ ```
53
+ templates/
54
+ └── marketing/
55
+ ├── template.json # Required: Template metadata
56
+ ├── preview.png # Optional: Preview image
57
+ └── template/ # Required: Files to scaffold
58
+ ├── package.json.hbs
59
+ ├── pnpm-workspace.yaml
60
+ ├── .gitignore
61
+ ├── README.md.hbs
62
+ ├── foundation/
63
+ │ ├── package.json.hbs
64
+ │ ├── src/
65
+ │ │ ├── index.js
66
+ │ │ ├── styles.css
67
+ │ │ └── components/
68
+ │ │ └── Hero/
69
+ │ │ ├── index.jsx
70
+ │ │ └── meta.js
71
+ │ └── ...
72
+ └── site/
73
+ ├── package.json.hbs
74
+ ├── site.yml.hbs
75
+ ├── vite.config.js
76
+ ├── src/
77
+ │ └── main.jsx
78
+ └── pages/
79
+ └── home/
80
+ ├── page.yml
81
+ └── 1-hero.md
82
+ ```
83
+
84
+ ### template.json
85
+
86
+ Required metadata file at the template root:
87
+
88
+ ```json
89
+ {
90
+ "name": "Marketing Starter",
91
+ "description": "A complete marketing site with landing page components",
92
+ "uniweb": ">=0.2.0",
93
+ "preview": "preview.png",
94
+ "tags": ["marketing", "landing-page", "saas"],
95
+ "components": ["Hero", "Features", "Pricing", "Testimonials", "CTA"]
96
+ }
97
+ ```
98
+
99
+ | Field | Required | Description |
100
+ |-------|----------|-------------|
101
+ | `name` | Yes | Human-readable template name |
102
+ | `description` | No | Longer description for discovery |
103
+ | `uniweb` | No | Semver range for Uniweb compatibility |
104
+ | `preview` | No | Preview image filename |
105
+ | `tags` | No | Keywords for discovery |
106
+ | `components` | No | List of included components |
107
+
108
+ ### Handlebars Processing
109
+
110
+ Files ending in `.hbs` are processed through Handlebars. The `.hbs` extension is removed in the output.
111
+
112
+ **Available variables:**
113
+ - `{{projectName}}` - Project name from CLI
114
+ - `{{year}}` - Current year
115
+ - Custom variables can be passed via the API
116
+
117
+ **Example: package.json.hbs**
118
+ ```json
119
+ {
120
+ "name": "{{projectName}}",
121
+ "version": "0.1.0",
122
+ "private": true
123
+ }
124
+ ```
125
+
126
+ **Supported file types for processing:**
127
+ - `.js`, `.jsx`, `.ts`, `.tsx`, `.mjs`, `.cjs`
128
+ - `.json`, `.yml`, `.yaml`
129
+ - `.md`, `.mdx`
130
+ - `.html`, `.htm`, `.css`, `.scss`
131
+ - `.txt`, `.xml`, `.svg`, `.vue`, `.astro`
132
+
133
+ Binary files (images, fonts, etc.) are copied as-is.
134
+
135
+ ### Critical: Package Dependencies
136
+
137
+ **The site package MUST include the foundation as a local dependency:**
138
+
139
+ ```json
140
+ // site/package.json.hbs
141
+ {
142
+ "name": "site",
143
+ "dependencies": {
144
+ "@uniweb/runtime": "^0.1.0",
145
+ "foundation": "file:../foundation"
146
+ }
147
+ }
148
+ ```
149
+
150
+ This `"foundation": "file:../foundation"` entry is essential because:
151
+ 1. Both npm and pnpm create a symlink at `site/node_modules/foundation` pointing to the sibling foundation
152
+ 2. Vite's `#foundation` alias resolves to the `foundation` module
153
+ 3. Without this, the site build will fail with "Could not load foundation"
154
+
155
+ **Important:** Use `file:` protocol, not `workspace:*`. The `workspace:*` protocol is pnpm-specific and will fail with npm.
156
+
157
+ **Use fixed package names:**
158
+ - Foundation: `"name": "foundation"` (not `{{projectName}}-foundation`)
159
+ - Site: `"name": "site"` (not `{{projectName}}-site`)
160
+
161
+ This matches how the CLI's built-in templates work and ensures the workspace linking functions correctly.
162
+
163
+ ### Workspace Configuration
164
+
165
+ The root `pnpm-workspace.yaml` should include both packages:
166
+
167
+ ```yaml
168
+ packages:
169
+ - 'site'
170
+ - 'foundation'
171
+ - 'sites/*'
172
+ - 'foundations/*'
173
+ ```
174
+
175
+ ### Variant Support
176
+
177
+ Templates can include variant-specific directories using the `.variant` suffix:
178
+
179
+ ```
180
+ template/
181
+ ├── foundation/
182
+ ├── foundation.typescript/ # Used when variant='typescript'
183
+ └── site/
184
+ ```
185
+
186
+ When applying with `variant: 'typescript'`, the `foundation.typescript/` directory contents will be used instead of `foundation/`.
187
+
188
+ ## Validation
189
+
190
+ Templates are validated when applied:
191
+
192
+ 1. **Structure check** - `template.json` and `template/` directory must exist
193
+ 2. **Required fields** - `name` field is required in template.json
194
+ 3. **Version compatibility** - If `uniweb` field is set, checks against current version
195
+ 4. **Unresolved placeholders** - Warns if `{{variables}}` remain after processing
196
+
197
+ ## Testing Templates
198
+
199
+ Add E2E tests in the main workspace at `tests/e2e/<template>-template.test.js`:
200
+
201
+ ```javascript
202
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest'
203
+ import { createTempDir, cleanupTempDir, runCreate, installDependencies, buildProject } from './helpers.js'
204
+
205
+ describe('Marketing Template Build', () => {
206
+ let tempDir, projectDir
207
+
208
+ beforeAll(async () => {
209
+ tempDir = await createTempDir()
210
+ projectDir = join(tempDir, 'test-project')
211
+ await runCreate('test-project', { cwd: tempDir, template: 'marketing' })
212
+ await patchForLocalPackages(projectDir)
213
+ installDependencies(projectDir)
214
+ }, 300000)
215
+
216
+ it('should build foundation successfully', () => {
217
+ buildProject(join(projectDir, 'foundation'))
218
+ expect(existsSync(join(projectDir, 'foundation/dist/foundation.js'))).toBe(true)
219
+ })
220
+
221
+ it('should build site successfully', () => {
222
+ buildProject(join(projectDir, 'site'))
223
+ expect(existsSync(join(projectDir, 'site/dist/index.html'))).toBe(true)
224
+ })
225
+ })
226
+ ```
227
+
228
+ Key testing points:
229
+ - Project scaffolds correctly with all expected files
230
+ - Foundation builds and produces `schema.json` with component metadata
231
+ - Site builds and produces `site-content.json` with parsed content
232
+ - Content sections are in correct order
233
+ - Handlebars variables are properly substituted
234
+
235
+ ## Checklist for New Templates
236
+
237
+ - [ ] Create `templates/<name>/template.json` with required `name` field
238
+ - [ ] Create `templates/<name>/template/` directory structure
239
+ - [ ] Include both `foundation/` and `site/` packages
240
+ - [ ] Add `"foundation": "workspace:*"` to site's dependencies
241
+ - [ ] Use fixed names: `"name": "foundation"` and `"name": "site"`
242
+ - [ ] Include `pnpm-workspace.yaml` with workspace packages
243
+ - [ ] Add `.hbs` extension to files needing variable substitution
244
+ - [ ] Include sample content in `site/pages/`
245
+ - [ ] Create meaningful component metadata in `foundation/src/components/*/meta.js`
246
+ - [ ] Add E2E tests in the main workspace
247
+ - [ ] Test the full flow: create, install, build foundation, build site
248
+
249
+ ## API Reference
250
+
251
+ ### `applyTemplate(templatePath, targetPath, data, options)`
252
+
253
+ Apply a template from any path.
254
+
255
+ ### `applyBuiltinTemplate(name, targetPath, data, options)`
256
+
257
+ Apply one of the official templates by name.
258
+
259
+ ### `hasTemplate(name)`
260
+
261
+ Check if an official template exists.
262
+
263
+ ### `listBuiltinTemplates()`
264
+
265
+ Get list of all official templates with metadata.
266
+
267
+ ### `validateTemplate(templateRoot, options)`
268
+
269
+ Validate a template's structure and compatibility.
270
+
271
+ ### `copyTemplateDirectory(sourcePath, targetPath, data, options)`
272
+
273
+ Low-level directory copying with Handlebars processing.
274
+
275
+ ## License
276
+
277
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniweb/templates",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Template processing engine and official templates for Uniweb",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "{{projectName}}-foundation",
2
+ "name": "foundation",
3
3
  "version": "0.1.0",
4
4
  "type": "module",
5
5
  "main": "./src/index.js",
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "{{projectName}}-site",
2
+ "name": "site",
3
3
  "version": "0.1.0",
4
4
  "type": "module",
5
5
  "private": true,
@@ -10,7 +10,8 @@
10
10
  "preview": "vite preview"
11
11
  },
12
12
  "dependencies": {
13
- "@uniweb/runtime": "^0.1.0"
13
+ "@uniweb/runtime": "^0.1.0",
14
+ "foundation": "file:../foundation"
14
15
  },
15
16
  "devDependencies": {
16
17
  "@vitejs/plugin-react": "^4.2.1",