feat(App): Loads mode extensions on demand (#3312)

* feat: Dynamic plugin imports

* Remove unused file

* Fix basic dev mode

* Fix the modes issue that Joe requested

* Merge fixes

* Add the ability to publish directory contents

* PR review changes

---------
This commit is contained in:
Bill Wallace authored and GitHub committed 2023-05-08 21:18:35 -04:00
1 parent 2f355fa158
commit a688f03fdb
11 files changed
+225 -197

No files matched your search

@@ -1,11 +1,14 @@
const pluginConfig = require('../pluginConfig.json');
const fs = require('fs');
const os = require('os');
const glob = require('glob');
const autogenerationDisclaimer = `
// THIS FILE IS AUTOGENERATED AS PART OF THE EXTENSION AND MODE PLUGIN PROCESS.
// IT SHOULD NOT BE MODIFIED MANUALLY \n`;
const extractName = (val) => (typeof val === 'string') ? val : val.packageName;
function constructLines(input, categoryName) {
let pluginCount = 0;
@@ -19,14 +22,10 @@ function constructLines(input, categoryName) {
input.forEach(entry => {
if (entry.default === false) return;
const packageName = entry.packageName;
const defaultImportName = `${categoryName}${pluginCount}`;
const packageName = extractName(entry);
lines.importLines.push(
`import ${defaultImportName} from '${packageName}';\n`
);
lines.addToWindowLines.push(
`${categoryName}.push(${defaultImportName});\n`
`${categoryName}.push("${packageName}");\n`
);
pluginCount++;
@@ -49,7 +48,7 @@ function getFormattedWindowBlock(addToWindowLines) {
let content =
'const extensions = [];\n' +
'const modes = [];\n' +
'const modesFactory = [];\n' +
'\n// Not required any longer\n' +
'window.extensions = extensions;\n' +
'window.modes = modes;\n\n';
@@ -60,47 +59,55 @@ function getFormattedWindowBlock(addToWindowLines) {
return content;
}
function getRuntimeLoadModesExtensions() {
return (
'\n\n// Add a dynamic runtime loader\n' +
'export default async () => {\n' +
' for(const modeFactory of modesFactory) {\n' +
' const newModes = await modeFactory(modes,extensions);\n' +
' newModes.forEach(newMode => modes.push(newMode));\n' +
'}\n}\n\n\n' +
'async function loadRuntimeImports(config) {\n' +
' if (config && config.modes && config.modes.length) {\n' +
' for (const modeName of config.modes) {\n' +
' const existingMode = modes.find(mode => mode.id === modeName);\n' +
' if (!existingMode) {\n' +
' if (modeName === `@ohif/mode-test`) {\n' +
' const mode = await import(`@ohif/mode-test`);\n' +
' window.modes.push(mode.default);\n' +
' const extension = await import(`@ohif/extension-test`);\n' +
' window.extensions.push(extension.default);\n' +
' }\n' +
' }\n' +
' };\n' +
' }\n' +
'}\n' +
'export { loadRuntimeImports };\n\n'
);
function getRuntimeLoadModesExtensions(modules) {
const dynamicLoad = [];
dynamicLoad.push(
'\n\n// Add a dynamic runtime loader',
'async function loadModule(module) {',
' if (typeof module !== \'string\') return module;');
modules.forEach(module => {
const packageName = extractName(module);
dynamicLoad.push(
` if( module==="${packageName}") {`,
` const imported = await import("${packageName}");`,
' return imported.default;',
' }'
);
})
dynamicLoad.push(
' return (await import(module)).default;',
'}\n',
'// Import a list of items (modules or string names)',
'// @return a Promise evaluating to a list of modules',
'export default function importItems(modules) {',
' return Promise.all(modules.map(loadModule));',
'}\n',
'export { loadModule, modes, extensions, importItems };\n\n');
return dynamicLoad.join('\n');
}
const fromDirectory = (srcDir, path) => {
if (!path) return;
if (path[0] === '.') return srcDir + '/../../..' + path.substring(1);
if (path[0] === '~') return os.homedir() + path.substring(1);
return path;
}
const createCopyPluginToDistForLink = (
SRC_DIR,
DIST_DIR,
srcDir,
distDir,
plugins,
folderName
) => {
return plugins
.map(plugin => {
const from = `${SRC_DIR}/../node_modules/${plugin.packageName}/${folderName}/`;
const fromDir = fromDirectory(srcDir, plugin.directory);
const from = fromDir || `${srcDir}/../node_modules/${plugin.packageName}/${folderName}/`;
const exists = fs.existsSync(from);
return exists
? {
from,
to: DIST_DIR,
to: distDir,
toType: 'dir',
}
: undefined;
@@ -134,23 +141,20 @@ function writePluginImportsFile(SRC_DIR, DIST_DIR) {
const extensionLines = constructLines(pluginConfig.extensions, 'extensions');
const modeLines = constructLines(pluginConfig.modes, 'modes');
const modesFactoryLines = constructLines(
pluginConfig.modesFactory,
'modesFactory'
);
pluginImportsJsContent += getFormattedImportBlock([
...extensionLines.importLines,
...modeLines.importLines,
...modesFactoryLines.importLines,
]);
pluginImportsJsContent += getFormattedWindowBlock([
...extensionLines.addToWindowLines,
...modeLines.addToWindowLines,
...modesFactoryLines.addToWindowLines,
]);
pluginImportsJsContent += getRuntimeLoadModesExtensions();
pluginImportsJsContent += getRuntimeLoadModesExtensions([
...pluginConfig.extensions,
...pluginConfig.modes,
]);
fs.writeFileSync(
`${SRC_DIR}/pluginImports.js`,
@@ -172,10 +176,8 @@ function writePluginImportsFile(SRC_DIR, DIST_DIR) {
SRC_DIR,
DIST_DIR,
[
...pluginConfig.modesFactory,
...pluginConfig.modes,
...pluginConfig.extensions,
...pluginConfig.umd,
],
'public'
);
@@ -184,10 +186,9 @@ function writePluginImportsFile(SRC_DIR, DIST_DIR) {
SRC_DIR,
DIST_DIR,
[
...pluginConfig.modesFactory,
...pluginConfig.modes,
...pluginConfig.extensions,
...pluginConfig.umd,
...pluginConfig.public,
],
'public'
);
@@ -198,10 +199,8 @@ function writePluginImportsFile(SRC_DIR, DIST_DIR) {
SRC_DIR,
DIST_DIR,
[
...pluginConfig.modesFactory,
...pluginConfig.modes,
...pluginConfig.extensions,
...pluginConfig.umd,
],
'dist'
);
@@ -210,15 +209,13 @@ function writePluginImportsFile(SRC_DIR, DIST_DIR) {
SRC_DIR,
DIST_DIR,
[
...pluginConfig.modesFactory,
...pluginConfig.modes,
...pluginConfig.extensions,
...pluginConfig.umd,
],
'dist'
);
console.log('copy plugins', [
console.warn('copy plugins', [
...copyPluginPublicToDistBuild,
...copyPluginPublicToDistLink,
...copyPluginDistToDistBuild,