323 lines
6.4 KiB
Markdown
323 lines
6.4 KiB
Markdown
# Template Generator Example
|
|
|
|
Advanced template patterns for Gluegun CLI generators.
|
|
|
|
## Structure
|
|
|
|
```
|
|
template-generator/
|
|
├── src/
|
|
│ └── commands/
|
|
│ ├── new-app.ts # Multi-file generator
|
|
│ ├── new-feature.ts # Feature scaffold
|
|
│ └── new-config.ts # Config generator
|
|
├── templates/
|
|
│ ├── app/
|
|
│ │ ├── package.json.ejs
|
|
│ │ ├── tsconfig.json.ejs
|
|
│ │ ├── src/
|
|
│ │ │ └── index.ts.ejs
|
|
│ │ └── README.md.ejs
|
|
│ ├── feature/
|
|
│ │ ├── component.tsx.ejs
|
|
│ │ ├── test.spec.ts.ejs
|
|
│ │ └── styles.css.ejs
|
|
│ └── config/
|
|
│ └── config.json.ejs
|
|
└── README.md
|
|
```
|
|
|
|
## Features
|
|
|
|
- Multi-file generation from template sets
|
|
- Conditional template sections
|
|
- Nested directory creation
|
|
- Template composition
|
|
- Helper functions for common operations
|
|
|
|
## Patterns
|
|
|
|
### 1. Multi-File Generation
|
|
|
|
Generate complete project structure:
|
|
|
|
```typescript
|
|
await template.generate({
|
|
template: 'app/package.json.ejs',
|
|
target: `${name}/package.json`,
|
|
props: { name, version }
|
|
})
|
|
|
|
await template.generate({
|
|
template: 'app/src/index.ts.ejs',
|
|
target: `${name}/src/index.ts`,
|
|
props: { name }
|
|
})
|
|
```
|
|
|
|
### 2. Conditional Templates
|
|
|
|
Templates with conditional sections:
|
|
|
|
```ejs
|
|
<% if (includeTests) { %>
|
|
import { test } from 'vitest'
|
|
|
|
test('<%= name %> works', () => {
|
|
// Test implementation
|
|
})
|
|
<% } %>
|
|
```
|
|
|
|
### 3. Template Loops
|
|
|
|
Generate repetitive structures:
|
|
|
|
```ejs
|
|
<% features.forEach(feature => { %>
|
|
export { <%= feature.name %> } from './<%= feature.path %>'
|
|
<% }) %>
|
|
```
|
|
|
|
### 4. Nested Templates
|
|
|
|
Organize templates in directories:
|
|
|
|
```
|
|
templates/
|
|
├── react-app/
|
|
│ ├── components/
|
|
│ │ └── Component.tsx.ejs
|
|
│ ├── pages/
|
|
│ │ └── Page.tsx.ejs
|
|
│ └── layouts/
|
|
│ └── Layout.tsx.ejs
|
|
```
|
|
|
|
### 5. Template Helpers
|
|
|
|
Use helper functions in templates:
|
|
|
|
```ejs
|
|
/**
|
|
* <%= helpers.titleCase(name) %> Component
|
|
* File: <%= helpers.kebabCase(name) %>.ts
|
|
*/
|
|
|
|
export class <%= helpers.pascalCase(name) %> {
|
|
// Implementation
|
|
}
|
|
```
|
|
|
|
## Commands
|
|
|
|
### new-app
|
|
|
|
Create complete application structure:
|
|
|
|
```bash
|
|
./bin/cli new-app my-project --typescript --tests
|
|
```
|
|
|
|
Options:
|
|
- `--typescript`: Include TypeScript configuration
|
|
- `--tests`: Include test setup
|
|
- `--git`: Initialize git repository
|
|
- `--install`: Run npm install
|
|
|
|
### new-feature
|
|
|
|
Scaffold a new feature with tests and styles:
|
|
|
|
```bash
|
|
./bin/cli new-feature UserProfile --redux --tests
|
|
```
|
|
|
|
Options:
|
|
- `--redux`: Include Redux setup
|
|
- `--tests`: Generate test files
|
|
- `--styles`: Include CSS/SCSS files
|
|
|
|
### new-config
|
|
|
|
Generate configuration files:
|
|
|
|
```bash
|
|
./bin/cli new-config --eslint --prettier --jest
|
|
```
|
|
|
|
Options:
|
|
- `--eslint`: ESLint configuration
|
|
- `--prettier`: Prettier configuration
|
|
- `--jest`: Jest configuration
|
|
- `--typescript`: TypeScript configuration
|
|
|
|
## Template Variables
|
|
|
|
### Common Props
|
|
|
|
```typescript
|
|
{
|
|
name: string // Component/project name
|
|
description: string // Description
|
|
author: string // Author name
|
|
version: string // Version number
|
|
timestamp: string // ISO timestamp
|
|
year: number // Current year
|
|
}
|
|
```
|
|
|
|
### Feature-Specific Props
|
|
|
|
```typescript
|
|
{
|
|
// React component
|
|
componentType: 'class' | 'function'
|
|
withHooks: boolean
|
|
withState: boolean
|
|
|
|
// Configuration
|
|
includeESLint: boolean
|
|
includePrettier: boolean
|
|
includeTests: boolean
|
|
|
|
// Dependencies
|
|
dependencies: string[]
|
|
devDependencies: string[]
|
|
}
|
|
```
|
|
|
|
## Advanced Techniques
|
|
|
|
### 1. Template Composition
|
|
|
|
Combine multiple templates:
|
|
|
|
```typescript
|
|
// Base component template
|
|
await template.generate({
|
|
template: 'base/component.ts.ejs',
|
|
target: 'src/components/Base.ts',
|
|
props: baseProps
|
|
})
|
|
|
|
// Extended component using base
|
|
await template.generate({
|
|
template: 'extended/component.ts.ejs',
|
|
target: 'src/components/Extended.ts',
|
|
props: { ...baseProps, extends: 'Base' }
|
|
})
|
|
```
|
|
|
|
### 2. Dynamic Template Selection
|
|
|
|
Choose templates based on user input:
|
|
|
|
```typescript
|
|
const framework = await prompt.select('Framework:', [
|
|
'React',
|
|
'Vue',
|
|
'Angular'
|
|
])
|
|
|
|
const templatePath = `${framework.toLowerCase()}/component.ejs`
|
|
await template.generate({
|
|
template: templatePath,
|
|
target: `src/components/${name}.tsx`,
|
|
props: { name }
|
|
})
|
|
```
|
|
|
|
### 3. Template Preprocessing
|
|
|
|
Modify props before generation:
|
|
|
|
```typescript
|
|
const props = {
|
|
name,
|
|
pascalName: strings.pascalCase(name),
|
|
kebabName: strings.kebabCase(name),
|
|
dependencies: dependencies.sort(),
|
|
imports: generateImports(dependencies)
|
|
}
|
|
|
|
await template.generate({
|
|
template: 'component.ts.ejs',
|
|
target: `src/${props.kebabName}.ts`,
|
|
props
|
|
})
|
|
```
|
|
|
|
### 4. Post-Generation Actions
|
|
|
|
Run actions after template generation:
|
|
|
|
```typescript
|
|
// Generate files
|
|
await template.generate({ /* ... */ })
|
|
|
|
// Format generated code
|
|
await system.run('npm run format')
|
|
|
|
// Run initial build
|
|
await system.run('npm run build')
|
|
|
|
// Initialize git
|
|
if (options.git) {
|
|
await system.run('git init')
|
|
await system.run('git add .')
|
|
await system.run('git commit -m "Initial commit"')
|
|
}
|
|
```
|
|
|
|
### 5. Template Validation
|
|
|
|
Validate templates before generation:
|
|
|
|
```typescript
|
|
// Check if template exists
|
|
if (!filesystem.exists(`templates/${templatePath}`)) {
|
|
print.error(`Template not found: ${templatePath}`)
|
|
return
|
|
}
|
|
|
|
// Validate template syntax
|
|
const templateContent = await filesystem.read(`templates/${templatePath}`)
|
|
if (!validateEJS(templateContent)) {
|
|
print.error('Invalid EJS syntax in template')
|
|
return
|
|
}
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
1. **Organize Templates**: Group related templates in directories
|
|
2. **Use Helpers**: Extract common logic into helper functions
|
|
3. **Validate Input**: Check user input before generation
|
|
4. **Provide Feedback**: Show progress with spinners
|
|
5. **Handle Errors**: Gracefully handle missing templates
|
|
6. **Document Variables**: Comment template variables
|
|
7. **Test Templates**: Generate samples to verify output
|
|
|
|
## Testing Generated Code
|
|
|
|
```bash
|
|
# Generate sample
|
|
./bin/cli new-app test-project --all
|
|
|
|
# Verify structure
|
|
cd test-project
|
|
npm install
|
|
npm test
|
|
npm run build
|
|
```
|
|
|
|
## Template Development Workflow
|
|
|
|
1. Create template file with `.ejs` extension
|
|
2. Add template variables with `<%= %>` syntax
|
|
3. Test template with sample props
|
|
4. Add conditional sections with `<% if %>` blocks
|
|
5. Validate generated output
|
|
6. Document template variables and options
|