fix: Router generation and add file watching for extension changes

**Router Generation Fixes:**
- Fix router.js parsing (was looking for non-existent router.map.js)
- Parse Router.map(function() {...}) structure correctly
- Fix console route detection (check for path: '/' config)
- Fix function expression location (3rd arg after path config)
- Fix root extensions to use this.mount() not router.mount()

**File Watching:**
- Add chokidar to watch extension.js files in development
- Regenerate shims and loaders when extension.js changes
- Cache discovered extensions for regeneration
- Only watch in development mode

**Issues Fixed:**
1. Router.js now properly contains engine mounts
2. Extension.js changes trigger automatic regeneration
This commit is contained in:
roncodes
2025-11-27 04:35:16 -05:00
parent 3f12e98448
commit 4fb596c866
3 changed files with 110 additions and 23 deletions

View File

@@ -24,19 +24,72 @@ module.exports = {
console.log('[fleetbase-extensions-generator] included() hook called');
console.log('[fleetbase-extensions-generator] Project root:', this.project.root);
// Discover extensions
const extensions = this.discoverExtensions();
console.log('[fleetbase-extensions-generator] Found', extensions.length, 'extension(s)');
// Discover extensions and cache them
this._extensions = this.discoverExtensions();
console.log('[fleetbase-extensions-generator] Found', this._extensions.length, 'extension(s)');
// Generate files directly to app directory
this.generateExtensionShims(extensions);
this.generateExtensionLoaders(extensions);
this.generateRouter(extensions);
this.generateExtensionsManifest(extensions);
this.generateExtensionShims(this._extensions);
this.generateExtensionLoaders(this._extensions);
this.generateRouter(this._extensions);
this.generateExtensionsManifest(this._extensions);
// Set up file watching for extension.js files
this.setupFileWatching();
console.log('[fleetbase-extensions-generator] ========================================');
},
/**
* Set up file watching for extension.js files to regenerate on changes
*/
setupFileWatching() {
if (this.app.env !== 'development') {
return; // Only watch in development
}
const chokidar = require('chokidar');
const extensionPaths = [];
// Collect all extension.js file paths
for (const extension of this._extensions) {
const extensionPath = path.join(
this.project.root,
'node_modules',
extension.name,
'addon',
'extension.js'
);
if (fs.existsSync(extensionPath)) {
extensionPaths.push(extensionPath);
}
}
if (extensionPaths.length === 0) {
return;
}
console.log('[fleetbase-extensions-generator] Watching', extensionPaths.length, 'extension file(s) for changes');
// Watch extension files
const watcher = chokidar.watch(extensionPaths, {
persistent: true,
ignoreInitial: true
});
watcher.on('change', (changedPath) => {
console.log('[fleetbase-extensions-generator] Extension file changed:', changedPath);
console.log('[fleetbase-extensions-generator] Regenerating extension files...');
// Regenerate all extension files
this.generateExtensionShims(this._extensions);
this.generateExtensionLoaders(this._extensions);
console.log('[fleetbase-extensions-generator] ✓ Regeneration complete');
});
},
/**
* Discover Fleetbase extensions from node_modules
*/
@@ -223,16 +276,15 @@ ${extensionCode}
generateRouter(extensions) {
console.log('[fleetbase-extensions-generator] Generating router.js...');
const routerMapFile = path.join(this.project.root, 'app', 'router.map.js');
const routerFile = path.join(this.project.root, 'app', 'router.js');
if (!fs.existsSync(routerMapFile)) {
console.error('[fleetbase-extensions-generator] ! router.map.js not found at:', routerMapFile);
if (!fs.existsSync(routerFile)) {
console.error('[fleetbase-extensions-generator] ! router.js not found at:', routerFile);
return;
}
// Read router.map.js
const routerMapContent = fs.readFileSync(routerMapFile, 'utf8');
// Read router.js
const routerContent = fs.readFileSync(routerFile, 'utf8');
// Separate extensions by mount location
const consoleExtensions = [];
@@ -257,7 +309,7 @@ ${extensionCode}
const recast = require('recast');
const babelParser = require('recast/parsers/babel');
const ast = recast.parse(routerMapContent, { parser: babelParser });
const ast = recast.parse(routerContent, { parser: babelParser });
let consoleAdded = 0;
let rootAdded = 0;
@@ -300,17 +352,25 @@ ${extensionCode}
visitCallExpression(path) {
const node = path.node;
// Look for this.route('console', ...)
// Look for this.route('console', ...) with path: '/'
if (n.MemberExpression.check(node.callee) &&
n.ThisExpression.check(node.callee.object) &&
node.callee.property.name === 'route' &&
node.arguments.length > 0 &&
n.Literal.check(node.arguments[0]) &&
node.arguments[0].value === 'console') {
node.arguments[0].value === 'console' &&
node.arguments.length > 1 &&
n.ObjectExpression.check(node.arguments[1]) &&
node.arguments[1].properties.some(p =>
n.Property.check(p) &&
p.key.name === 'path' &&
n.Literal.check(p.value) &&
p.value.value === '/'
)) {
// Find the function expression in the second argument
if (node.arguments.length > 1 && n.FunctionExpression.check(node.arguments[1])) {
const functionExpression = node.arguments[1];
// Find the function expression in the third argument (after path config)
if (node.arguments.length > 2 && n.FunctionExpression.check(node.arguments[2])) {
const functionExpression = node.arguments[2];
// Add mount statements for each extension
extensions.forEach(extension => {
@@ -359,12 +419,18 @@ ${extensionCode}
let addedCount = 0;
types.visit(ast, {
visitExportDefaultDeclaration(path) {
visitCallExpression(path) {
const node = path.node;
// Look for export default function(router) { ... }
if (n.FunctionExpression.check(node.declaration)) {
const functionExpression = node.declaration;
// Look for Router.map(function() { ... })
if (n.MemberExpression.check(node.callee) &&
n.Identifier.check(node.callee.object) &&
node.callee.object.name === 'Router' &&
node.callee.property.name === 'map' &&
node.arguments.length > 0 &&
n.FunctionExpression.check(node.arguments[0])) {
const functionExpression = node.arguments[0];
// Add mount statements for each root extension
extensions.forEach(extension => {
@@ -373,7 +439,7 @@ ${extensionCode}
const mountStatement = b.expressionStatement(
b.callExpression(
b.memberExpression(
b.identifier('router'),
b.thisExpression(),
b.identifier('mount')
),
[
@@ -392,6 +458,9 @@ ${extensionCode}
return false; // Don't traverse children
}
return false; // Don't traverse children
}
this.traverse(path);
}

View File

@@ -79,6 +79,7 @@
"broccoli-file-creator": "^2.1.1",
"broccoli-funnel": "^3.0.8",
"broccoli-merge-trees": "^4.2.0",
"chokidar": "^5.0.0",
"concurrently": "^8.2.2",
"date-fns": "^2.30.0",
"dragula": "^3.7.3",

17
console/pnpm-lock.yaml generated
View File

@@ -149,6 +149,9 @@ importers:
broccoli-merge-trees:
specifier: ^4.2.0
version: 4.2.0
chokidar:
specifier: ^5.0.0
version: 5.0.0
concurrently:
specifier: ^8.2.2
version: 8.2.2
@@ -2467,6 +2470,10 @@ packages:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'}
chokidar@5.0.0:
resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==}
engines: {node: '>= 20.19.0'}
chrome-trace-event@1.0.4:
resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==}
engines: {node: '>=6.0'}
@@ -6021,6 +6028,10 @@ packages:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
readdirp@5.0.0:
resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==}
engines: {node: '>= 20.19.0'}
recast@0.18.10:
resolution: {integrity: sha512-XNvYvkfdAN9QewbrxeTOjgINkdY/odTgTS56ZNEWL9Ml0weT4T3sFtvnTuF+Gxyu46ANcRm1ntrF6F5LAJPAaQ==}
engines: {node: '>= 4'}
@@ -10290,6 +10301,10 @@ snapshots:
optionalDependencies:
fsevents: 2.3.3
chokidar@5.0.0:
dependencies:
readdirp: 5.0.0
chrome-trace-event@1.0.4: {}
ci-info@3.9.0: {}
@@ -14615,6 +14630,8 @@ snapshots:
dependencies:
picomatch: 2.3.1
readdirp@5.0.0: {}
recast@0.18.10:
dependencies:
ast-types: 0.13.3