diff --git a/.gitignore b/.gitignore index 089503701..dec41990c 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,8 @@ config.rst package-lock.json share/jupyter/voila/templates/base/static/*voila.js +share/jupyter/voila/templates/base/static/*ipywidgets7shared.js +share/jupyter/voila/templates/base/static/*ipywidgets8shared.js share/jupyter/voila/templates/base/static/*treepage.js share/jupyter/voila/templates/base/static/*voila-style.js share/jupyter/voila/templates/base/static/*.woff diff --git a/packages/voila/package.json b/packages/voila/package.json index 04a24bdc3..d48a59f56 100644 --- a/packages/voila/package.json +++ b/packages/voila/package.json @@ -13,6 +13,7 @@ "dependencies": { "@jupyter-widgets/base": "^6.0.10", "@jupyter-widgets/base7": "npm:@jupyter-widgets/base@4.1.6", + "@jupyter-widgets/controls": "^5.0.11", "@jupyter-widgets/controls7": "npm:@jupyter-widgets/controls@3.1.6", "@jupyter-widgets/jupyterlab-manager": "^5.0.13", "@jupyterlab/application": "^4.0.0", diff --git a/packages/voila/src/ipywidgets7.ts b/packages/voila/src/ipywidgets7.ts index a59e4ade6..438d5b70e 100644 --- a/packages/voila/src/ipywidgets7.ts +++ b/packages/voila/src/ipywidgets7.ts @@ -31,6 +31,7 @@ export const baseWidgets7Plugin: JupyterFrontEndPlugin = { name: '@jupyter-widgets/base', version: JUPYTER_WIDGETS_VERSION, exports: () => { + require('./ipywidgets7shared'); return require('@jupyter-widgets/base7') as any; } }); @@ -52,6 +53,7 @@ export const controlWidgets7Plugin: JupyterFrontEndPlugin = { name: '@jupyter-widgets/controls', version: JUPYTER_CONTROLS_VERSION, exports: () => { + require('./ipywidgets7shared'); const controlsWidgets = require('@jupyter-widgets/controls7') as any; require('@jupyter-widgets/controls7/css/widgets-base.css'); return controlsWidgets; diff --git a/packages/voila/src/ipywidgets7shared.ts b/packages/voila/src/ipywidgets7shared.ts new file mode 100644 index 000000000..6ef95a77f --- /dev/null +++ b/packages/voila/src/ipywidgets7shared.ts @@ -0,0 +1,11 @@ +/*************************************************************************** + * Copyright (c) 2024, Voilà contributors * + * Copyright (c) 2024, QuantStack * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ + +export * as base from '@jupyter-widgets/base7'; +export * as controls from '@jupyter-widgets/controls7'; diff --git a/packages/voila/src/ipywidgets8.ts b/packages/voila/src/ipywidgets8.ts new file mode 100644 index 000000000..3eff80310 --- /dev/null +++ b/packages/voila/src/ipywidgets8.ts @@ -0,0 +1,63 @@ +/*************************************************************************** + * Copyright (c) 2024, Voilà contributors * + * Copyright (c) 2024, QuantStack * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ + +import * as base from '@jupyter-widgets/base'; +import { + JupyterFrontEnd, + JupyterFrontEndPlugin +} from '@jupyterlab/application'; + +const JUPYTER_WIDGETS_VERSION = '2.0.0'; +const JUPYTER_CONTROLS_VERSION = '2.0.0'; + +/** + * The base widgets. + */ +export const baseWidgets8Plugin: JupyterFrontEndPlugin = { + id: `@jupyter-widgets/jupyterlab-manager:base-${JUPYTER_WIDGETS_VERSION}`, + requires: [base.IJupyterWidgetRegistry], + autoStart: true, + activate: ( + app: JupyterFrontEnd, + registry: base.IJupyterWidgetRegistry + ): void => { + registry.registerWidget({ + name: '@jupyter-widgets/base', + version: JUPYTER_WIDGETS_VERSION, + exports: () => { + require('./ipywidgets8shared'); + return require('@jupyter-widgets/base') as any; + } + }); + } +}; + +/** + * The control widgets. + */ +export const controlWidgets8Plugin: JupyterFrontEndPlugin = { + id: `@jupyter-widgets/jupyterlab-manager:controls-${JUPYTER_CONTROLS_VERSION}`, + requires: [base.IJupyterWidgetRegistry], + autoStart: true, + activate: ( + app: JupyterFrontEnd, + registry: base.IJupyterWidgetRegistry + ): void => { + registry.registerWidget({ + name: '@jupyter-widgets/controls', + version: JUPYTER_CONTROLS_VERSION, + exports: () => { + require('./ipywidgets8shared'); + const controlsWidgets = require('@jupyter-widgets/controls') as any; + require('@jupyter-widgets/controls/css/widgets-base.css'); + return controlsWidgets; + } + }); + } +}; diff --git a/packages/voila/src/ipywidgets8shared.ts b/packages/voila/src/ipywidgets8shared.ts new file mode 100644 index 000000000..78580bbd5 --- /dev/null +++ b/packages/voila/src/ipywidgets8shared.ts @@ -0,0 +1,11 @@ +/*************************************************************************** + * Copyright (c) 2024, Voilà contributors * + * Copyright (c) 2024, QuantStack * + * * + * Distributed under the terms of the BSD 3-Clause License. * + * * + * The full license is in the file LICENSE, distributed with this software. * + ****************************************************************************/ + +export * as base from '@jupyter-widgets/base'; +export * as controls from '@jupyter-widgets/controls'; diff --git a/packages/voila/src/main.ts b/packages/voila/src/main.ts index c3f835dae..96a3d4b14 100644 --- a/packages/voila/src/main.ts +++ b/packages/voila/src/main.ts @@ -15,6 +15,7 @@ import { PageConfig, URLExt } from '@jupyterlab/coreutils'; import { VoilaApp } from './app'; import plugins from './voilaplugins'; import { baseWidgets7Plugin, controlWidgets7Plugin } from './ipywidgets7'; +import { baseWidgets8Plugin, controlWidgets8Plugin } from './ipywidgets8'; import { VoilaServiceManager } from './services/servicemanager'; import { VoilaShell } from './shell'; import { @@ -46,7 +47,10 @@ async function main() { plugins, // For backward compat with ipywidgets 7 baseWidgets7Plugin, - controlWidgets7Plugin + controlWidgets7Plugin, + // For compat with ipywidgets 8 + baseWidgets8Plugin, + controlWidgets8Plugin ]; if (shouldUseMathJax2()) { diff --git a/packages/voila/webpack.config.js b/packages/voila/webpack.config.js index d79b19037..7c8eef0df 100644 --- a/packages/voila/webpack.config.js +++ b/packages/voila/webpack.config.js @@ -69,21 +69,29 @@ const distRoot = path.resolve( 'static' ); -const shared = {}; +const voilaIndexSharedPackages = {}; for (const dependency of Object.keys(data.dependencies)) { - // TODO Why can we not share those? + // Do not share jupyter-widgets packages in the Voila index if ( - ['@jupyter-widgets/base7', '@jupyter-widgets/controls7'].includes( + [ + '@jupyter-widgets/base7', + '@jupyter-widgets/base', + '@jupyter-widgets/controls7', + '@jupyter-widgets/controls' + ].includes( dependency ) ) { continue; } - shared[dependency] = data.dependencies[dependency]; + voilaIndexSharedPackages[dependency] = data.dependencies[dependency]; } module.exports = [ + /* + * Voila main index + */ merge(baseConfig, { mode: 'development', entry: { @@ -109,7 +117,7 @@ module.exports = [ name: ['_JUPYTERLAB', 'CORE_LIBRARY_FEDERATION'] }, name: 'CORE_FEDERATION', - shared + shared: voilaIndexSharedPackages }) ], resolve: { @@ -118,6 +126,9 @@ module.exports = [ } } }), + /* + * Voila styles + */ merge(baseConfig, { entry: './' + path.relative(__dirname, styleEntryPoint), mode: 'production', @@ -125,5 +136,77 @@ module.exports = [ path: distRoot, filename: 'voila-style.js' } - }) + }), + /* + * jupyter-widgets 7 packages + */ + merge(baseConfig, { + mode: 'development', + entry: { + ipywidgets7shared: ['./publicpath.js', './' + path.relative(__dirname, path.join(buildDir, 'ipywidgets7shared.js'))] + }, + output: { + path: distRoot, + library: { + type: 'var', + name: ['_JUPYTERLAB', 'CORE_OUTPUT'] + }, + filename: '[name].js', + chunkFilename: '[name].ipywidgets7shared.js' + }, + plugins: [ + new ModuleFederationPlugin({ + library: { + type: 'var', + name: ['_JUPYTERLAB', 'CORE_LIBRARY_FEDERATION'] + }, + name: 'CORE_FEDERATION', + shared: { + '@jupyter-widgets/base': data.dependencies['@jupyter-widgets/base7'], + '@jupyter-widgets/controls': data.dependencies['@jupyter-widgets/controls7'] + } + }) + ], + resolve: { + fallback: { + util: require.resolve('util/') + } + } + }), + /* + * jupyter-widgets 8 packages + */ + merge(baseConfig, { + mode: 'development', + entry: { + ipywidgets8shared: ['./publicpath.js', './' + path.relative(__dirname, path.join(buildDir, 'ipywidgets8shared.js'))] + }, + output: { + path: distRoot, + library: { + type: 'var', + name: ['_JUPYTERLAB', 'CORE_OUTPUT'] + }, + filename: '[name].js', + chunkFilename: '[name].ipywidgets8shared.js' + }, + plugins: [ + new ModuleFederationPlugin({ + library: { + type: 'var', + name: ['_JUPYTERLAB', 'CORE_LIBRARY_FEDERATION'] + }, + name: 'CORE_FEDERATION', + shared: { + '@jupyter-widgets/base': data.dependencies['@jupyter-widgets/base'], + '@jupyter-widgets/controls': data.dependencies['@jupyter-widgets/controls'] + } + }) + ], + resolve: { + fallback: { + util: require.resolve('util/') + } + } + }), ].concat(extras); diff --git a/yarn.lock b/yarn.lock index 99a1801c5..e7996e3ab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5151,6 +5151,7 @@ __metadata: dependencies: "@jupyter-widgets/base": ^6.0.10 "@jupyter-widgets/base7": "npm:@jupyter-widgets/base@4.1.6" + "@jupyter-widgets/controls": ^5.0.11 "@jupyter-widgets/controls7": "npm:@jupyter-widgets/controls@3.1.6" "@jupyter-widgets/jupyterlab-manager": ^5.0.13 "@jupyterlab/application": ^4.0.0