@uniweb/templates 0.1.0 → 0.1.1

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,275 @@
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 workspace dependency:**
138
+
139
+ ```json
140
+ // site/package.json.hbs
141
+ {
142
+ "name": "site",
143
+ "dependencies": {
144
+ "@uniweb/runtime": "^0.1.0",
145
+ "foundation": "workspace:*"
146
+ }
147
+ }
148
+ ```
149
+
150
+ This `"foundation": "workspace:*"` entry is essential because:
151
+ 1. pnpm creates a symlink at `site/node_modules/foundation` pointing to the workspace 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
+ **Use fixed package names:**
156
+ - Foundation: `"name": "foundation"` (not `{{projectName}}-foundation`)
157
+ - Site: `"name": "site"` (not `{{projectName}}-site`)
158
+
159
+ This matches how the CLI's built-in templates work and ensures the workspace linking functions correctly.
160
+
161
+ ### Workspace Configuration
162
+
163
+ The root `pnpm-workspace.yaml` should include both packages:
164
+
165
+ ```yaml
166
+ packages:
167
+ - 'site'
168
+ - 'foundation'
169
+ - 'sites/*'
170
+ - 'foundations/*'
171
+ ```
172
+
173
+ ### Variant Support
174
+
175
+ Templates can include variant-specific directories using the `.variant` suffix:
176
+
177
+ ```
178
+ template/
179
+ ├── foundation/
180
+ ├── foundation.typescript/ # Used when variant='typescript'
181
+ └── site/
182
+ ```
183
+
184
+ When applying with `variant: 'typescript'`, the `foundation.typescript/` directory contents will be used instead of `foundation/`.
185
+
186
+ ## Validation
187
+
188
+ Templates are validated when applied:
189
+
190
+ 1. **Structure check** - `template.json` and `template/` directory must exist
191
+ 2. **Required fields** - `name` field is required in template.json
192
+ 3. **Version compatibility** - If `uniweb` field is set, checks against current version
193
+ 4. **Unresolved placeholders** - Warns if `{{variables}}` remain after processing
194
+
195
+ ## Testing Templates
196
+
197
+ Add E2E tests in the main workspace at `tests/e2e/<template>-template.test.js`:
198
+
199
+ ```javascript
200
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest'
201
+ import { createTempDir, cleanupTempDir, runCreate, installDependencies, buildProject } from './helpers.js'
202
+
203
+ describe('Marketing Template Build', () => {
204
+ let tempDir, projectDir
205
+
206
+ beforeAll(async () => {
207
+ tempDir = await createTempDir()
208
+ projectDir = join(tempDir, 'test-project')
209
+ await runCreate('test-project', { cwd: tempDir, template: 'marketing' })
210
+ await patchForLocalPackages(projectDir)
211
+ installDependencies(projectDir)
212
+ }, 300000)
213
+
214
+ it('should build foundation successfully', () => {
215
+ buildProject(join(projectDir, 'foundation'))
216
+ expect(existsSync(join(projectDir, 'foundation/dist/foundation.js'))).toBe(true)
217
+ })
218
+
219
+ it('should build site successfully', () => {
220
+ buildProject(join(projectDir, 'site'))
221
+ expect(existsSync(join(projectDir, 'site/dist/index.html'))).toBe(true)
222
+ })
223
+ })
224
+ ```
225
+
226
+ Key testing points:
227
+ - Project scaffolds correctly with all expected files
228
+ - Foundation builds and produces `schema.json` with component metadata
229
+ - Site builds and produces `site-content.json` with parsed content
230
+ - Content sections are in correct order
231
+ - Handlebars variables are properly substituted
232
+
233
+ ## Checklist for New Templates
234
+
235
+ - [ ] Create `templates/<name>/template.json` with required `name` field
236
+ - [ ] Create `templates/<name>/template/` directory structure
237
+ - [ ] Include both `foundation/` and `site/` packages
238
+ - [ ] Add `"foundation": "workspace:*"` to site's dependencies
239
+ - [ ] Use fixed names: `"name": "foundation"` and `"name": "site"`
240
+ - [ ] Include `pnpm-workspace.yaml` with workspace packages
241
+ - [ ] Add `.hbs` extension to files needing variable substitution
242
+ - [ ] Include sample content in `site/pages/`
243
+ - [ ] Create meaningful component metadata in `foundation/src/components/*/meta.js`
244
+ - [ ] Add E2E tests in the main workspace
245
+ - [ ] Test the full flow: create, install, build foundation, build site
246
+
247
+ ## API Reference
248
+
249
+ ### `applyTemplate(templatePath, targetPath, data, options)`
250
+
251
+ Apply a template from any path.
252
+
253
+ ### `applyBuiltinTemplate(name, targetPath, data, options)`
254
+
255
+ Apply one of the official templates by name.
256
+
257
+ ### `hasTemplate(name)`
258
+
259
+ Check if an official template exists.
260
+
261
+ ### `listBuiltinTemplates()`
262
+
263
+ Get list of all official templates with metadata.
264
+
265
+ ### `validateTemplate(templateRoot, options)`
266
+
267
+ Validate a template's structure and compatibility.
268
+
269
+ ### `copyTemplateDirectory(sourcePath, targetPath, data, options)`
270
+
271
+ Low-level directory copying with Handlebars processing.
272
+
273
+ ## License
274
+
275
+ 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.1",
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": "workspace:*"
14
15
  },
15
16
  "devDependencies": {
16
17
  "@vitejs/plugin-react": "^4.2.1",