diff --git a/packages/voila/index.js b/packages/voila/index.js deleted file mode 100644 index 523103563..000000000 --- a/packages/voila/index.js +++ /dev/null @@ -1,189 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2018, VoilĂ  contributors * - * Copyright (c) 2018, QuantStack * - * * - * Distributed under the terms of the BSD 3-Clause License. * - * * - * The full license is in the file LICENSE, distributed with this software. * - ****************************************************************************/ - -// Copyright (c) Jupyter Development Team. -// Distributed under the terms of the Modified BSD License. - -// Inspired by: https://github.com/jupyterlab/jupyterlab/blob/master/dev_mode/index.js - -import './style.css'; - -import { PageConfig, URLExt } from '@jupyterlab/coreutils'; - -import { VoilaApp } from '@voila-dashboards/voila'; - -function loadScript(url) { - return new Promise((resolve, reject) => { - const newScript = document.createElement('script'); - newScript.onerror = reject; - newScript.onload = resolve; - newScript.async = true; - document.head.appendChild(newScript); - newScript.src = url; - }); -} -async function loadComponent(url, scope) { - await loadScript(url); - - // From MIT-licensed https://github.com/module-federation/module-federation-examples/blob/af043acd6be1718ee195b2511adf6011fba4233c/advanced-api/dynamic-remotes/app1/src/App.js#L6-L12 - // eslint-disable-next-line no-undef - await __webpack_init_sharing__('default'); - const container = window._JUPYTERLAB[scope]; - // Initialize the container, it may provide shared modules and may need ours - // eslint-disable-next-line no-undef - await container.init(__webpack_share_scopes__.default); -} - -async function createModule(scope, module) { - try { - const factory = await window._JUPYTERLAB[scope].get(module); - return factory(); - } catch (e) { - console.warn( - `Failed to create module: package: ${scope}; module: ${module}` - ); - throw e; - } -} - -const disabled = ['@jupyter-widgets/jupyterlab-manager']; - -/** - * The main function - */ -async function main() { - let mods = [ - // @jupyterlab plugins - require('@jupyterlab/markdownviewer-extension'), - require('@jupyterlab/mathjax2-extension'), - require('@jupyterlab/rendermime-extension'), - // TODO: add the settings endpoint to re-enable the theme plugins? - // This would also need the theme manager plugin and settings - // require('@jupyterlab/theme-light-extension'), - // require('@jupyterlab/theme-dark-extension'), - require('./plugins') - ]; - - const mimeExtensions = [require('@jupyterlab/json-extension')]; - - /** - * Iterate over active plugins in an extension. - * - * #### Notes - * This also populates the disabled - */ - function* activePlugins(extension) { - // Handle commonjs or es2015 modules - let exports; - if (Object.prototype.hasOwnProperty.call(extension, '__esModule')) { - exports = extension.default; - } else { - // CommonJS exports. - exports = extension; - } - - let plugins = Array.isArray(exports) ? exports : [exports]; - for (let plugin of plugins) { - if ( - PageConfig.Extension.isDisabled(plugin.id) || - disabled.includes(plugin.id) || - disabled.includes(plugin.id.split(':')[0]) - ) { - continue; - } - yield plugin; - } - } - - const extensionData = JSON.parse( - PageConfig.getOption('federated_extensions') - ); - - const federatedExtensionPromises = []; - const federatedMimeExtensionPromises = []; - const federatedStylePromises = []; - - const extensions = await Promise.allSettled( - extensionData.map(async data => { - await loadComponent( - `${URLExt.join( - PageConfig.getOption('fullLabextensionsUrl'), - data.name, - data.load - )}`, - data.name - ); - return data; - }) - ); - - extensions.forEach(p => { - if (p.status === 'rejected') { - // There was an error loading the component - console.error(p.reason); - return; - } - - const data = p.value; - if (data.extension) { - federatedExtensionPromises.push(createModule(data.name, data.extension)); - } - if (data.mimeExtension) { - federatedMimeExtensionPromises.push( - createModule(data.name, data.mimeExtension) - ); - } - if (data.style) { - federatedStylePromises.push(createModule(data.name, data.style)); - } - }); - - // Add the federated extensions. - const federatedExtensions = await Promise.allSettled( - federatedExtensionPromises - ); - federatedExtensions.forEach(p => { - if (p.status === 'fulfilled') { - for (let plugin of activePlugins(p.value)) { - mods.push(plugin); - } - } else { - console.error(p.reason); - } - }); - - // Add the federated mime extensions. - const federatedMimeExtensions = await Promise.allSettled( - federatedMimeExtensionPromises - ); - federatedMimeExtensions.forEach(p => { - if (p.status === 'fulfilled') { - for (let plugin of activePlugins(p.value)) { - mimeExtensions.push(plugin); - } - } else { - console.error(p.reason); - } - }); - - // Load all federated component styles and log errors for any that do not - (await Promise.allSettled(federatedStylePromises)) - .filter(({ status }) => status === 'rejected') - .forEach(({ reason }) => { - console.error(reason); - }); - - const app = new VoilaApp({ mimeExtensions }); - app.registerPluginModules(mods); - await app.start(); - - window.jupyterapp = app; -} - -window.addEventListener('load', main); diff --git a/packages/voila/src/index.ts b/packages/voila/src/index.ts index c44c9300a..08dab445c 100644 --- a/packages/voila/src/index.ts +++ b/packages/voila/src/index.ts @@ -11,7 +11,4 @@ export * from './app'; export * from './manager'; export * from './shell'; export * from './output'; - -import * as plugins from './plugins'; - -export { plugins }; +export * from './plugins'; diff --git a/packages/voila/src/main.ts b/packages/voila/src/main.ts index 7c150594e..a3a2a9379 100644 --- a/packages/voila/src/main.ts +++ b/packages/voila/src/main.ts @@ -18,6 +18,7 @@ import { PageConfig, URLExt } from '@jupyterlab/coreutils'; import { VoilaApp } from './app'; import { VoilaShell } from './shell'; +import plugins from './plugins'; function loadScript(url: string): Promise { return new Promise((resolve, reject) => { @@ -68,9 +69,8 @@ async function main() { // This would also need the theme manager plugin and settings // require('@jupyterlab/theme-light-extension'), // require('@jupyterlab/theme-dark-extension'), - require('./plugins') + plugins ]; - const mimeExtensions = [require('@jupyterlab/json-extension')]; /** diff --git a/packages/voila/src/plugins.ts b/packages/voila/src/plugins.ts index 36dd016fc..8ab39cb07 100644 --- a/packages/voila/src/plugins.ts +++ b/packages/voila/src/plugins.ts @@ -34,7 +34,7 @@ import { WidgetManager as VoilaWidgetManager } from './manager'; /** * The default paths. */ -const paths: JupyterFrontEndPlugin = { +export const pathsPlugin: JupyterFrontEndPlugin = { id: '@voila-dashboards/voila:paths', activate: ( app: JupyterFrontEnd @@ -51,7 +51,7 @@ const paths: JupyterFrontEndPlugin = { * TODO: a cleaner solution would involve a custom ServiceManager to the VoilaApp * to prevent the default behavior of polling the /api endpoints. */ -const stopPolling: JupyterFrontEndPlugin = { +export const stopPollingPlugin: JupyterFrontEndPlugin = { id: '@voila-dashboards/voila:stop-polling', autoStart: true, activate: (app: JupyterFrontEnd): void => { @@ -69,7 +69,7 @@ const stopPolling: JupyterFrontEndPlugin = { /** * A simplified Translator */ -const translator: JupyterFrontEndPlugin = { +export const translatorPlugin: JupyterFrontEndPlugin = { id: '@voila-dashboards/voila:translator', activate: (app: JupyterFrontEnd): ITranslator => { const translationManager = new TranslationManager(); @@ -82,7 +82,7 @@ const translator: JupyterFrontEndPlugin = { /** * The Voila widgets manager plugin. */ -const widgetManager: JupyterFrontEndPlugin = { +export const widgetManager: JupyterFrontEndPlugin = { id: '@voila-dashboards/voila:widget-manager', autoStart: true, requires: [IRenderMimeRegistry], @@ -135,9 +135,9 @@ const widgetManager: JupyterFrontEndPlugin = { * Export the plugins as default. */ const plugins: JupyterFrontEndPlugin[] = [ - paths, - stopPolling, - translator, + pathsPlugin, + stopPollingPlugin, + translatorPlugin, widgetManager ]; diff --git a/packages/voilite/src/global.d.ts b/packages/voilite/src/global.d.ts index 8df0f7a33..114b86a94 100644 --- a/packages/voilite/src/global.d.ts +++ b/packages/voilite/src/global.d.ts @@ -9,9 +9,7 @@ interface ICellData { cell_type: string; cell_source: string; } -declare var cells: { - [key: number]: ICellData; -}; + declare function update_loading_text( cell_index: number, cell_count: number, diff --git a/packages/voilite/src/index.ts b/packages/voilite/src/index.ts index e38f85022..65e3200c2 100644 --- a/packages/voilite/src/index.ts +++ b/packages/voilite/src/index.ts @@ -203,7 +203,6 @@ async function main() { litePluginsToRegister.push(plugin); } }); - console.log('start server'); // create the in-browser JupyterLite Server const jupyterLiteServer = new JupyterLiteServer({ shell: null as never }); @@ -211,7 +210,7 @@ async function main() { jupyterLiteServer.registerPluginModules(litePluginsToRegister); // start the server await jupyterLiteServer.start(); - console.log('done server'); + const serviceManager = jupyterLiteServer.serviceManager; const app = new VoiliteApp({ serviceManager: serviceManager as any, diff --git a/packages/voilite/src/plugins.ts b/packages/voilite/src/plugins.ts index 73546021f..ef8f538e4 100644 --- a/packages/voilite/src/plugins.ts +++ b/packages/voilite/src/plugins.ts @@ -1,4 +1,3 @@ -import { PageConfig } from '@jupyterlab/coreutils'; /*************************************************************************** * Copyright (c) 2022, VoilĂ  contributors * * Copyright (c) 2022, QuantStack * @@ -13,64 +12,15 @@ import { JupyterFrontEndPlugin } from '@jupyterlab/application'; import { IThemeManager } from '@jupyterlab/apputils'; -import { ITranslator, TranslationManager } from '@jupyterlab/translation'; import { PromiseDelegate } from '@lumino/coreutils'; -import { VoilaApp } from '@voila-dashboards/voila'; - +import { translatorPlugin, pathsPlugin } from '@voila-dashboards/voila'; +import { PageConfig } from '@jupyterlab/coreutils'; import { VoiliteWidgetManager } from './manager'; -/** - * The default paths. - */ -const paths: JupyterFrontEndPlugin = { - id: '@voila-dashboards/voila:paths', - activate: ( - app: JupyterFrontEnd - ): JupyterFrontEnd.IPaths => { - return (app as VoilaApp).paths; - }, - autoStart: true, - provides: JupyterFrontEnd.IPaths -}; - -/** - * A plugin to stop polling the kernels, sessions and kernel specs. - * - * TODO: a cleaner solution would involve a custom ServiceManager to the VoilaApp - * to prevent the default behavior of polling the /api endpoints. - */ -const stopPolling: JupyterFrontEndPlugin = { - id: '@voila-dashboards/voila:stop-polling', - autoStart: true, - activate: (app: JupyterFrontEnd): void => { - app.serviceManager.sessions?.ready.then(value => { - app.serviceManager.sessions['_kernelManager']['_pollModels']?.stop(); - void app.serviceManager.sessions['_pollModels'].stop(); - }); - - app.serviceManager.kernelspecs?.ready.then(value => { - void app.serviceManager.kernelspecs.dispose(); - }); - } -}; - -/** - * A simplified Translator - */ -const translator: JupyterFrontEndPlugin = { - id: '@voila-dashboards/voila:translator', - activate: (app: JupyterFrontEnd): ITranslator => { - const translationManager = new TranslationManager(); - return translationManager; - }, - autoStart: true, - provides: ITranslator -}; - export const managerPromise = new PromiseDelegate(); /** - * The Voila widgets manager plugin. + * The Voilite widgets manager plugin. */ const widgetManager = { id: '@voila-dashboards/voilite:widget-manager', @@ -113,9 +63,8 @@ const themePlugin: JupyterFrontEndPlugin = { * Export the plugins as default. */ const plugins: JupyterFrontEndPlugin[] = [ - paths, - stopPolling, - translator, + pathsPlugin, + translatorPlugin, widgetManager, themePlugin ];