Plugins
Gitit supports a plugin system that allows you to extend its functionality. Plugins can add new template sources, modify the behavior of existing commands, add new commands, or hook into various stages of the template cloning process.
Plugin Architecture
Gitit plugins are JavaScript or TypeScript modules that export a specific interface. Plugins can be distributed as npm packages or local files.
Plugin Interface
A basic Gitit plugin follows this structure:
// my-gitit-plugin.ts
import type { GitItPlugin } from '@stacksjs/gitit'
const myPlugin: GitItPlugin = {
name: 'my-gitit-plugin',
version: '1.0.0',
// Plugin functionality
hooks: {
// Hook implementations
},
providers: {
// Custom template providers
},
commands: {
// Custom commands
}
}
export default myPlugin
Installing Plugins
From npm
To use a plugin published on npm:
# Install the plugin
npm install gitit-plugin-example --save-dev
# Add to your gitit.config.ts
// gitit.config.ts
import examplePlugin from 'gitit-plugin-example'
export default {
plugins: [
examplePlugin,
// More plugins...
],
// Other configuration...
}
Local Plugins
You can also use local plugins:
// gitit.config.ts
import myLocalPlugin from './plugins/my-local-plugin.js'
export default {
plugins: [
myLocalPlugin,
// More plugins...
],
// Other configuration...
}
Developing Plugins
Creating a Basic Plugin
To create a Gitit plugin, start with this template:
// my-gitit-plugin.ts
import type { GitItPlugin, TemplateInfo } from '@stacksjs/gitit'
const myPlugin: GitItPlugin = {
name: 'my-gitit-plugin',
version: '1.0.0',
description: 'A plugin for Gitit that adds custom functionality',
// Hook into various lifecycle events
hooks: {
beforeDownload: (template, options) => {
console.log(`Downloading template: ${template}`)
return { template, options }
},
afterDownload: (result) => {
console.log(`Template downloaded to: ${result.dir}`)
return result
}
},
// Add custom template providers
providers: {
myCustomSource: (input, options) => {
// Handle custom template source
const info: TemplateInfo = {
name: 'custom-template',
tar: `https://example.com/templates/${input}.tar.gz`,
// Other TemplateInfo properties...
}
return info
}
}
}
export default myPlugin
Available Hooks
Plugins can hook into various stages of the Gitit lifecycle:
beforeDownload
: Called before template download startsafterDownload
: Called after template download completesbeforeExtract
: Called before template extractionafterExtract
: Called after template extractionbeforeInstall
: Called before dependencies are installedafterInstall
: Called after dependencies are installed
Each hook receives relevant context and can modify the behavior of Gitit.
Custom Template Providers
Plugins can add new template sources by implementing custom providers:
providers: {
myCompany: (input, options) => {
// Parse input and generate template info
return {
name: `company-template-${input}`,
tar: `https://internal.mycompany.com/templates/${input}.tar.gz`,
// Other properties...
}
}
}
This would allow users to use templates with:
gitit myCompany:template-name my-project
Plugin Configuration
Plugins can accept configuration options:
// gitit.config.ts
import myPlugin from 'my-gitit-plugin'
export default {
plugins: [
[myPlugin, {
option1: 'value1',
option2: true
}]
],
// Other configuration...
}
In your plugin, access these options:
// my-gitit-plugin.ts
import type { GitItPlugin } from '@stacksjs/gitit'
function createPlugin(options = {}) {
return {
name: 'my-gitit-plugin',
// Access options.option1, options.option2, etc.
hooks: {
beforeDownload: (template, downloadOptions) => {
if (options.option2) {
// Do something based on configuration
}
return { template, options: downloadOptions }
}
}
} as GitItPlugin
}
export default createPlugin
Examples
Template Transformer Plugin
This example plugin transforms templates by replacing variables:
// gitit-template-transformer-plugin.ts
import type { GitItPlugin } from '@stacksjs/gitit'
import { readdir, readFile, writeFile } from 'node:fs/promises'
import { extname, join } from 'node:path'
const transformerPlugin: GitItPlugin = {
name: 'gitit-template-transformer',
version: '1.0.0',
hooks: {
afterExtract: async (result) => {
const variables = {
PROJECT_NAME: result.dir.split('/').pop(),
TIMESTAMP: new Date().toISOString(),
AUTHOR: process.env.USER || 'unknown'
}
// Find and process files with variables
await processDirectory(result.dir, variables)
return result
}
}
}
async function processDirectory(dir, variables) {
const entries = await readdir(dir, { withFileTypes: true })
for (const entry of entries) {
const fullPath = join(dir, entry.name)
if (entry.isDirectory()) {
await processDirectory(fullPath, variables)
}
else if (entry.isFile()) {
await processFile(fullPath, variables)
}
}
}
async function processFile(file, variables) {
// Skip binary files
if (isBinaryPath(file))
return
try {
let content = await readFile(file, 'utf8')
let changed = false
// Replace variables in format {{ VARIABLE_NAME }}
for (const [name, value] of Object.entries(variables)) {
const regex = new RegExp(`\\{\\{\\s*${name}\\s*\\}\\}`, 'g')
if (regex.test(content)) {
content = content.replace(regex, value)
changed = true
}
}
if (changed) {
await writeFile(file, content, 'utf8')
}
}
catch (error) {
console.error(`Error processing file ${file}:`, error)
}
}
function isBinaryPath(filePath) {
// Simple check for binary files
const ext = extname(filePath).toLowerCase()
return ['.png', '.jpg', '.jpeg', '.gif', '.pdf', '.zip', '.gz'].includes(ext)
}
export default transformerPlugin
Publishing Plugins
To publish your plugin to npm:
- Create a package with an appropriate name (e.g.,
gitit-plugin-*
) - Set up your
package.json
file:
{
"name": "gitit-plugin-example",
"version": "1.0.0",
"description": "Example plugin for Gitit",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.js",
"types": "./dist/index.d.ts"
}
},
"keywords": ["gitit", "gitit-plugin"],
"peerDependencies": {
"@stacksjs/gitit": "^1.0.0"
}
}
- Build your plugin (transpile TypeScript if needed)
- Publish to npm with
npm publish
(orbun publish
)
Best Practices
When developing Gitit plugins:
- Follow naming conventions: Use
gitit-plugin-*
for npm packages - Document your plugin: Include clear documentation on usage and options
- Handle errors gracefully: Don't let your plugin crash the main process
- Keep it focused: Each plugin should have a clear purpose
- Use TypeScript: Leverage type checking for more robust plugins
- Test thoroughly: Ensure your plugin works with different Gitit workflows