feat: Implement extension boot refactor with prebuild approach

- Modified prebuild.js to generate extension shims in app/extensions/
- Generate extension-loaders.js with dynamic import map
- Added ember-auto-import allowAppImports configuration
- Extension setup code is now code-split into separate chunks
- Removed FleetbaseExtensionsIndexer in favor of prebuild generation
- Added generated files to .gitignore

Successfully tested: extension code is code-split into separate chunk
(chunk.app_extensions_fleetops_js.*.js)
This commit is contained in:
roncodes
2025-11-27 00:34:12 -05:00
parent ffab66ac6c
commit a0fc1ce402
5 changed files with 930 additions and 5404 deletions

4
console/.gitignore vendored
View File

@@ -26,3 +26,7 @@
# broccoli-debug
/DEBUG/
# Auto-generated extension files
/app/extensions/
/app/utils/extension-loaders.js

View File

@@ -2,12 +2,7 @@
/** eslint-disable node/no-unpublished-require */
const EmberApp = require('ember-cli/lib/broccoli/ember-app');
const ExtensionDiscoveryPlugin = require('./lib/build-plugins/extension-discovery');
const ExtensionShimGeneratorPlugin = require('./lib/build-plugins/extension-shim-generator');
const ExtensionLoadersGeneratorPlugin = require('./lib/build-plugins/extension-loaders-generator');
const RouterGeneratorPlugin = require('./lib/build-plugins/router-generator');
const Funnel = require('broccoli-funnel');
const mergeTrees = require('broccoli-merge-trees');
const writeFile = require('broccoli-file-creator');
const postcssImport = require('postcss-import');
const postcssPresetEnv = require('postcss-preset-env');
@@ -66,83 +61,16 @@ module.exports = function (defaults) {
},
autoImport: {
// Allow dynamic imports of app/extensions/* files
// This is required for the extension setup code to be bundled
// by ember-auto-import and loaded via dynamic import()
allowAppImports: ['extensions/*'],
// Optional: Configure webpack for better code splitting
webpack: {
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
// Group all extension files into a single chunk
extensions: {
test: /[\\/]app[\\/]extensions[\\/]/,
name: 'extensions',
priority: 10,
},
},
},
},
},
allowAppImports: [
'extensions/**',
'utils/extension-loaders'
]
},
});
// ============================================================================
// FLEETBASE EXTENSION BUILD PLUGINS
// ============================================================================
// Discover all Fleetbase extensions
const extensionDiscovery = new ExtensionDiscoveryPlugin([], {
projectRoot: __dirname,
annotation: 'Discover Fleetbase Extensions',
});
// Extension shims are generated by prebuild.js before ember build
// Generate extension shim files
const extensionShims = new ExtensionShimGeneratorPlugin([extensionDiscovery], {
projectRoot: __dirname,
annotation: 'Generate Extension Shims',
});
// Generate extension loaders map
const extensionLoaders = new ExtensionLoadersGeneratorPlugin([extensionDiscovery], {
projectRoot: __dirname,
annotation: 'Generate Extension Loaders',
});
// Generate router with engine mounts
const router = new RouterGeneratorPlugin([extensionDiscovery], {
projectRoot: __dirname,
routerMapFile: __dirname + '/router.map.js',
annotation: 'Generate Router with Engine Mounts',
});
// ============================================================================
// FUNNEL GENERATED FILES INTO APP TREE
// ============================================================================
// Funnel extension shims to app/extensions/
const extensionShimsTree = new Funnel(extensionShims, {
destDir: 'app',
});
// Funnel extension loaders to app/utils/
const extensionLoadersTree = new Funnel(extensionLoaders, {
destDir: 'app',
});
// Funnel router to app
const routerTree = new Funnel(router, {
destDir: 'app',
});
// Generated extension files
const extensions = mergeTrees([extensionShimsTree, extensionLoadersTree, routerTree], {
overwrite: true,
annotation: 'Merge Extension Generated Files',
});
// let extensions = new FleetbaseExtensionsIndexer();
// Runtime config
let runtimeConfigTree;
if (toBoolean(process.env.DISABLE_RUNTIME_CONFIG)) {
runtimeConfigTree = writeFile('fleetbase.config.json', '{}');
@@ -153,5 +81,5 @@ module.exports = function (defaults) {
});
}
return app.toTree([extensions, runtimeConfigTree].filter(Boolean));
return app.toTree([runtimeConfigTree].filter(Boolean));
};

View File

@@ -1,6 +1,6 @@
{
"name": "@fleetbase/console",
"version": "0.7.18",
"version": "0.7.20",
"private": true,
"description": "Modular logistics and supply chain operating system (LSOS)",
"repository": "https://github.com/fleetbase/fleetbase",
@@ -11,8 +11,7 @@
"test": "tests"
},
"scripts": {
"prebuild": "node prebuild.js",
"build": "pnpm run prebuild && ember build",
"build": "ember build",
"lint": "concurrently \"npm:lint:*(!fix)\" --names \"lint:\"",
"lint:css": "stylelint \"**/*.css\"",
"lint:css:fix": "concurrently \"npm:lint:css -- --fix\"",
@@ -22,25 +21,18 @@
"lint:js": "eslint . --cache",
"lint:js:fix": "eslint . --fix",
"lint:intl": "fleetbase-intl-lint",
"start": "pnpm run prebuild && ember serve",
"start:dev": "pnpm run prebuild && ember serve --environment development",
"start": "ember serve",
"start:dev": "ember serve --environment development",
"test": "concurrently \"npm:lint\" \"npm:test:*\" --names \"lint,test:\"",
"test:ember": "ember test"
},
"dependencies": {
"@ember/legacy-built-in-components": "^0.4.2",
"@fleetbase/billing-engine": "link:../packages/billing",
"@fleetbase/dev-engine": "^0.2.10",
"@fleetbase/ember-core": "latest",
"@fleetbase/ember-ui": "^0.3.9",
"@fleetbase/fleetops-data": "latest",
"@fleetbase/ember-core": "link:../packages/ember-core",
"@fleetbase/ember-ui": "link:../packages/ember-ui",
"@fleetbase/fleetops-data": "^0.1.23",
"@fleetbase/fleetops-engine": "link:../packages/fleetops",
"@fleetbase/fliit-engine": "link:../packages/fliit",
"@fleetbase/iam-engine": "^0.1.4",
"@fleetbase/internals-engine": "link:../packages/internals",
"@fleetbase/leaflet-routing-machine": "^3.2.17",
"@fleetbase/registry-bridge-engine": "^0.1.0",
"@fleetbase/storefront-engine": "link:../packages/storefront",
"@formatjs/intl-datetimeformat": "^6.18.2",
"@formatjs/intl-numberformat": "^8.15.6",
"@formatjs/intl-pluralrules": "^5.4.6",
@@ -81,6 +73,7 @@
"broccoli-asset-rev": "^3.0.0",
"broccoli-file-creator": "^2.1.1",
"broccoli-funnel": "^3.0.8",
"broccoli-merge-trees": "^4.2.0",
"concurrently": "^8.2.2",
"date-fns": "^2.30.0",
"dragula": "^3.7.3",
@@ -146,8 +139,8 @@
},
"pnpm": {
"overrides": {
"@fleetbase/ember-core": "latest",
"@fleetbase/ember-ui": "latest",
"@fleetbase/ember-core": "link:../packages/ember-core",
"@fleetbase/ember-ui": "link:../packages/ember-ui",
"@fleetbase/fleetops-data": "latest"
}
},

6159
console/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -173,4 +173,62 @@ function getRouterFileContents() {
const output = recast.print(ast, { quote: 'single' }).code;
fs.writeFileSync(path.join(__dirname, 'app/router.js'), output);
// Generate extension shims
console.log('[Prebuild] Generating extension shims...');
generateExtensionShims(extensions);
})();
function generateExtensionShims(extensions) {
const extensionsDir = path.join(__dirname, 'app', 'extensions');
const utilsDir = path.join(__dirname, 'app', 'utils');
// Create directories
fs.mkdirSync(extensionsDir, { recursive: true });
fs.mkdirSync(utilsDir, { recursive: true });
const loaderEntries = [];
// Generate shim for each extension that has extension.js
for (const extension of extensions) {
const extensionPath = path.join(__dirname, 'node_modules', extension.name, 'addon', 'extension.js');
if (fs.existsSync(extensionPath)) {
try {
// Read the extension code
const extensionCode = fs.readFileSync(extensionPath, 'utf8');
// Generate shim content
const shimContent = `// AUTO-GENERATED - DO NOT EDIT
// Extension shim for ${extension.name}
${extensionCode}
`;
// Write shim file
const mountName = getExtensionMountPath(extension.name);
const shimPath = path.join(extensionsDir, `${mountName}.js`);
fs.writeFileSync(shimPath, shimContent, 'utf8');
// Add to loader map
loaderEntries.push(` '${extension.name}': () => import('@fleetbase/console/extensions/${mountName}')`);
console.log(`[Prebuild] ✓ Generated shim: app/extensions/${mountName}.js`);
} catch (error) {
console.error(`[Prebuild] Failed to generate shim for ${extension.name}:`, error.message);
}
}
}
// Generate extension loaders file
const loadersContent = `// AUTO-GENERATED - DO NOT EDIT
// Extension loader map for dynamic imports
export const EXTENSION_LOADERS = {
${loaderEntries.join(',\n')}
};
`;
const loadersPath = path.join(utilsDir, 'extension-loaders.js');
fs.writeFileSync(loadersPath, loadersContent, 'utf8');
console.log(`[Prebuild] ✓ Generated ${loaderEntries.length} extension shims and loader map`);
}