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:
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:
<% if (includeTests) { %>
import { test } from 'vitest'
test('<%= name %> works', () => {
// Test implementation
})
<% } %>
3. Template Loops
Generate repetitive structures:
<% 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:
/**
* <%= helpers.titleCase(name) %> Component
* File: <%= helpers.kebabCase(name) %>.ts
*/
export class <%= helpers.pascalCase(name) %> {
// Implementation
}
Commands
new-app
Create complete application structure:
./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:
./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:
./bin/cli new-config --eslint --prettier --jest
Options:
--eslint: ESLint configuration--prettier: Prettier configuration--jest: Jest configuration--typescript: TypeScript configuration
Template Variables
Common Props
{
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
{
// 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:
// 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:
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:
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:
// 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:
// 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
- Organize Templates: Group related templates in directories
- Use Helpers: Extract common logic into helper functions
- Validate Input: Check user input before generation
- Provide Feedback: Show progress with spinners
- Handle Errors: Gracefully handle missing templates
- Document Variables: Comment template variables
- Test Templates: Generate samples to verify output
Testing Generated Code
# Generate sample
./bin/cli new-app test-project --all
# Verify structure
cd test-project
npm install
npm test
npm run build
Template Development Workflow
- Create template file with
.ejsextension - Add template variables with
<%= %>syntax - Test template with sample props
- Add conditional sections with
<% if %>blocks - Validate generated output
- Document template variables and options