Appearance
Hooks
Execute code at different stages of the build process.
Available Hooks
| Hook | When | Use Case |
|---|---|---|
onPreBuild | Before build starts | Validation, setup, notifications |
onModifyAssets | After assets copied | Transform files, inject code |
onBeforePackage | Before Electron packaging | Final modifications |
onPostBuild | After build complete | Cleanup, notifications, upload |
onBuildError | On build failure | Error reporting |
onBuildProgress | During build | Progress tracking |
Hook Signatures
onPreBuild
javascript
async onPreBuild(context, settings) {
// context.gamePath - Source game folder
// context.config - Game configuration
// settings - Plugin settings values
}onModifyAssets
javascript
async onModifyAssets(context, settings) {
// context.gamePath - Source game folder
// context.outputPath - Build output folder
// context.config - Game configuration
// context.platform - 'darwin', 'win32', 'linux'
// context.arch - 'arm64', 'x64', 'ia32'
// settings - Plugin settings values
}onBeforePackage
javascript
async onBeforePackage(context, settings) {
// Same as onModifyAssets
// Called just before Electron packaging
}onPostBuild
javascript
async onPostBuild(context, settings) {
// context.gamePath - Source game folder
// context.outputPath - Final build folder
// context.config - Game configuration
// context.platform - Target platform
// context.arch - Target architecture
// settings - Plugin settings values
}onBuildError
javascript
async onBuildError(context, settings) {
// context.gamePath - Source game folder
// context.config - Game configuration
// context.error - Error message
// settings - Plugin settings values
}onBuildProgress
javascript
onBuildProgress(context, settings) {
// context.gamePath - Source game folder
// context.config - Game configuration
// context.percent - Progress 0-100
// context.message - Status message
// settings - Plugin settings values
}Example: Complete Plugin
javascript
module.exports = {
name: 'Build Pipeline',
version: '1.0.0',
settings: [
{ id: 'validateAssets', type: 'checkbox', label: 'Validate assets', default: true },
{ id: 'webhookUrl', type: 'text', label: 'Webhook URL' }
],
async onPreBuild(context, settings) {
gemshell.log('Starting build...');
if (settings.validateAssets) {
// Validate required files exist
const required = ['index.html'];
for (const file of required) {
if (!gemshell.fs.exists(file)) {
throw new Error(`Missing required file: ${file}`);
}
}
gemshell.log('Asset validation passed');
}
},
async onModifyAssets(context, settings) {
gemshell.log('Processing assets...');
// Add build timestamp
const timestamp = new Date().toISOString();
gemshell.transform.injectIntoHtml(
`<meta name="build-time" content="${timestamp}">`,
'head'
);
},
async onBeforePackage(context, settings) {
gemshell.log('Preparing for packaging...');
// Remove development files
const devFiles = ['*.map', '*.ts', 'tsconfig.json'];
for (const pattern of devFiles) {
const files = gemshell.glob(pattern);
for (const file of files) {
gemshell.fs.remove(file);
}
}
},
async onPostBuild(context, settings) {
gemshell.log('Build complete!');
// Send webhook notification
if (settings.webhookUrl) {
await gemshell.http.post(settings.webhookUrl, {
event: 'build_complete',
game: context.config.title,
version: context.config.version,
platform: `${context.platform}-${context.arch}`,
time: new Date().toISOString()
});
}
},
async onBuildError(context, settings) {
gemshell.error('Build failed:', context.error);
if (settings.webhookUrl) {
await gemshell.http.post(settings.webhookUrl, {
event: 'build_failed',
game: context.config.title,
error: context.error,
time: new Date().toISOString()
});
}
},
onBuildProgress(context, settings) {
// Called frequently, keep lightweight
if (context.percent % 25 === 0) {
gemshell.log(`Progress: ${context.percent}%`);
}
}
};Error Handling
Throw errors to abort the build:
javascript
async onPreBuild(context, settings) {
if (!gemshell.fs.exists('index.html')) {
throw new Error('index.html is required');
}
}The error message will be shown to the user and onBuildError will be called.
Async vs Sync
All hooks can be async:
javascript
async onPostBuild(context, settings) {
// Async operations work
await gemshell.http.post(...);
await someAsyncFunction();
}Exception: onBuildProgress should be synchronous for performance.
