Pre-Build Validation
Run these checks before starting the build process:
Plugin Spec Validation
- Display name is 1-100 characters
- Display name doesn't contain special characters (no !, @, #, etc.)
- Plugin slug is lowercase kebab-case (my-plugin-name)
- Plugin slug contains only alphanumeric and hyphens
- Version is semver format (X.Y.Z)
- Version is not pre-release (not 1.0.0-alpha)
- Description is one sentence, < 100 chars
- Category is from approved list
- Icon name exists in BrainDrive icon library
- Author name is provided
- Type is one of: frontend, backend, full
File Structure Validation
-
package.jsonfile exists -
lifecycle_manager.pyfile exists -
webpack.config.jsfile exists -
tsconfig.jsonfile exists -
src/folder exists -
src/index.tsxexists and is valid - Main component file exists (e.g.,
src/MyPlugin.tsx) -
public/folder exists -
LICENSEfile exists -
README.mdfile exists
Manifest Validation
-
package.jsonname matches plugin slug -
package.jsonversion matches lifecycle_manager.py -
lifecycle_manager.pyplugin_slug matches webpack scope - webpack.config.js
namematches plugin_slug (PascalCase) -
bundlelocationis exactly "dist/remoteEntry.js" - React and React-DOM are in dependencies
- No hardcoded API keys or secrets
Configuration Validation
{
"package.json": {
"name": "should-be-kebab-case",
"version": "should-be-x.y.z",
"main": "must-be-dist/remoteEntry.js",
"dependencies": {
"react": "must-be-^18.2.0-or-compatible",
"react-dom": "must-be-^18.2.0-or-compatible"
}
},
"lifecycle_manager.py": {
"plugin_slug": "should-be-PascalCase",
"version": "must-match-package.json",
"bundle_location": "must-be-dist/remoteEntry.js"
},
"webpack.config.js": {
"name": "must-match-plugin_slug"
}
}
Build-Time Validation
After running npm install and npm run build:
Dependency Validation
# ✅ Check that npm install succeeded
npm list react react-dom typescript webpack
# ❌ Common errors:
# - npm ERR! code ERESOLVE
# - npm ERR! peer dep missing
# FIX: Ensure package.json versions are compatible
TypeScript Validation
# ✅ Check for TS errors
npx tsc --noEmit
# ❌ Common errors:
# - TS2307: Cannot find module
# - TS2688: Cannot find type definitions
# FIX: Check imports and install @types packages
Webpack Build Validation
# ✅ Check that webpack built successfully
npm run build 2>&1 | grep -i "error\|success"
# ❌ Common errors:
# - Module not found
# - Unexpected token
# - Cannot find loader
# FIX: Check webpack.config.js and imports
Output Validation
# ✅ Check that dist/ folder has the right files
ls -la dist/
# Must exist:
# - remoteEntry.js (Module Federation entry)
# - main.js (plugin code)
# ❌ If dist/ is empty:
# FIX: Check webpack.config.js output path
Post-Build Validation
After npm run build:
File Existence Checks
# ✅ Required files must exist
[ -f dist/remoteEntry.js ] || echo "❌ MISSING: dist/remoteEntry.js"
[ -f package.json ] || echo "❌ MISSING: package.json"
[ -f lifecycle_manager.py ] || echo "❌ MISSING: lifecycle_manager.py"
[ -f webpack.config.js ] || echo "❌ MISSING: webpack.config.js"
# ✅ If all pass:
echo "✓ All required files present"
Bundle Integrity Checks
# ✅ Check remoteEntry.js is valid JavaScript
node -c dist/remoteEntry.js && echo "✓ remoteEntry.js is valid JS"
# ❌ If error: check webpack.config.js Module Federation settings
# ✅ Check bundle size is reasonable
du -sh dist/
# Typical: 100KB - 500KB
# ❌ If > 2MB: check for large dependencies
find dist/ -size +500k
Manifest Consistency Checks
# Extract and verify versions match
PACKAGE_VER=$(grep '"version"' package.json | head -1 | cut -d'"' -f4)
LIFECYCLE_VER=$(grep '"version"' lifecycle_manager.py | head -1 | cut -d'"' -f2)
if [ "$PACKAGE_VER" = "$LIFECYCLE_VER" ]; then
echo "✓ Versions match: $PACKAGE_VER"
else
echo "❌ VERSION MISMATCH: package=$PACKAGE_VER lifecycle=$LIFECYCLE_VER"
fi
# Extract and verify slugs match
PACKAGE_NAME=$(grep '"name"' package.json | head -1 | cut -d'"' -f4)
PACKAGE_SLUG=$(echo $PACKAGE_NAME | sed 's/-//g' | tr 'a-z' 'A-Z' | cut -c1-1)$(echo $PACKAGE_NAME | cut -d'-' -f1 | cut -c2- | tr 'a-z' 'A-Z')
LIFECYCLE_SLUG=$(grep "plugin_slug" lifecycle_manager.py | head -1 | cut -d'"' -f2)
echo "Package name: $PACKAGE_NAME"
echo "Lifecycle slug: $LIFECYCLE_SLUG"
Common Failure Modes
Failure Mode 1: Module Not Found
Error:
Module not found: Error: Can't resolve 'react'
Cause: React not in dependencies
Fix:
npm install react react-dom
# Update package.json
Failure Mode 2: TypeScript Compilation Error
Error:
error TS2307: Cannot find module './services/api'
Cause: Incorrect import path
Fix:
// Check import path matches file location
// If file is src/services/api.ts:
import { ApiService } from './services/api'; // ✓ Correct
import { ApiService } from '../services/api'; // ✗ Wrong path
Failure Mode 3: Webpack Build Fails
Error:
ERROR in ./src/index.tsx
Module parse failed: Unexpected token
Cause: Loader not configured, or syntax error
Fix:
// webpack.config.js must have ts-loader
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
}
Failure Mode 4: remoteEntry.js Not Generated
Error:
dist/remoteEntry.js NOT FOUND
Cause: ModuleFederationPlugin not in webpack config
Fix:
// webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;
plugins: [
new ModuleFederationPlugin({
name: 'YourPlugin',
filename: 'remoteEntry.js', // Must be exactly this
exposes: {
'./index': './src/index.tsx'
}
})
]
Failure Mode 5: Version Mismatch
Error:
Plugin won't load: Version mismatch detected
package.json: 1.0.0
lifecycle_manager.py: 1.0.1
Cause: Forgot to update both files
Fix:
# Update package.json
"version": "1.0.1"
# Update lifecycle_manager.py
"version": "1.0.1"
# Rebuild
npm run build
Failure Mode 6: Plugin Slug Inconsistency
Error:
Plugin won't register: scope mismatch
Cause: Slugs don't match across files
Fix:
package.json: "name": "my-plugin"
lifecycle_manager.py: "plugin_slug": "MyPlugin"
webpack.config.js: name: 'MyPlugin'
All three must represent the same plugin!
- package.json: kebab-case (my-plugin)
- lifecycle_manager.py: PascalCase (MyPlugin)
- webpack: PascalCase (MyPlugin)
Failure Mode 7: Missing React Peer Dependency
Error:
npm ERR! code ERESOLVE
npm ERR! ERESOLVE could not resolve dependency peer
Cause: React version conflict
Fix:
{
"peerDependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
Failure Mode 8: ZIPfile Too Large
Error:
ZIP file is 50MB - too large to upload
Cause: node_modules included in ZIP
Fix:
# Never ZIP node_modules
rm -rf node_modules/
zip -r my-plugin-1.0.0.zip my-plugin/
# Users will run npm install when building
Failure Mode 9: Component Not Exported
Error:
DashboardPage component not found in bundle
Cause: Component registered but not exported
Fix:
// src/index.tsx
export { DashboardPage } from './pages/Dashboard';
// In lifecycle_manager.py
"component": "DashboardPage" // Must match export name
Failure Mode 10: No Default Page
Error:
BrainDrive doesn't know which page to load first
Cause: No page marked as default
Fix:
"pages": [
{
"slug": "dashboard",
"title": "Dashboard",
...,
"default": True # Add this
},
{ ... }
]
Runtime Validation Tests
After packaging and before release:
Test 1: ZIP Extraction
# Create temp dir
mkdir test_plugin
cd test_plugin
# Extract ZIP
unzip ../my-plugin-1.0.0.zip
# Verify structure
ls -la my-plugin/
# Should show: package.json, lifecycle_manager.py, etc.
Test 2: Mock Installation
cd my-plugin
# Install dependencies
npm install
# Build
npm run build
# Check dist/
ls -la dist/remoteEntry.js
Test 3: Lifecycle Manager Import
# If Python available
python3 -c "import sys; sys.path.insert(0, '.'); from lifecycle_manager import YourPluginLifecycleManager; print('✓ Lifecycle manager imports successfully')"
Test 4: Bundle Analysis
# Check what's in remoteEntry.js
file dist/remoteEntry.js
# Should output: JavaScript source
# Check if it's minified (as expected in production)
head -c 100 dist/remoteEntry.js | grep -q "function\|const\|var" && echo "✓ Appears to be minified"
Pre-Release Checklist
Before releasing your plugin:
SPEC VALIDATION
- [ ] Plugin name is clear and memorable
- [ ] Description is one sentence and accurate
- [ ] Version follows semver
- [ ] Icon matches plugin purpose
- [ ] Category is appropriate
TECHNICAL VALIDATION
- [ ] All required files exist
- [ ] npm install succeeds
- [ ] npm run build succeeds
- [ ] dist/remoteEntry.js exists and is > 1KB
- [ ] All versions match across files
- [ ] All slugs match across files
FEATURE VALIDATION
- [ ] Main component renders without errors
- [ ] Settings load if defined
- [ ] API calls use correct endpoints
- [ ] No hardcoded secrets or API keys
- [ ] Error handling is present
DOCUMENTATION
- [ ] README.md has installation instructions
- [ ] README.md lists features
- [ ] README.md has troubleshooting section
- [ ] LICENSE file is present
- [ ] CHANGELOG.md documents version history
PACKAGING
- [ ] ZIP file created successfully
- [ ] ZIP file is < 2MB (or documented reason for size)
- [ ] ZIP contains dist/ folder
- [ ] ZIP doesn't contain node_modules
- [ ] ZIP filename matches plugin-version pattern
FINAL CHECKS
- [ ] Plugin installs without errors
- [ ] Plugin loads in BrainDrive
- [ ] All pages render correctly
- [ ] Settings can be modified
- [ ] Plugin uninstalls cleanly
Validation is your safety net. The more thorough you are here, the fewer user issues you'll face.