diff --git a/examples/embed-amd/README.md b/examples/embed-amd/README.md new file mode 100644 index 0000000000..5c31dd9592 --- /dev/null +++ b/examples/embed-amd/README.md @@ -0,0 +1,24 @@ +# Using the HTML widget manager as a RequireJS AMD module + +## Description + +This is an example project showing how to embed widgets in an HTML document using a RequireJS AMD module. + +In order to test the current development repo, make a symbolic link from the `packages/html-manager` directory to this directory and uncomment the `html-manager` paths config in `index.html`. + +The widget data in this example was generated from the following code: + +```python +from ipywidgets import VBox, jsdlink, IntSlider, Button + +s1, s2 = IntSlider(max=200, value=100), IntSlider(value=40) +b = Button(icon='legal') +jsdlink((s1, 'value'), (s2, 'max')) +VBox([s1, s2, b]) +``` + +## Try it + +1. Start with a repository checkout, and run `yarn install` in the root directory. +2. Run `yarn run build:examples` in the root directory. +3. Open the `index.html` file in this directory. diff --git a/examples/embed-amd/index.html b/examples/embed-amd/index.html new file mode 100644 index 0000000000..b93306c652 --- /dev/null +++ b/examples/embed-amd/index.html @@ -0,0 +1,167 @@ + + + + + + + + + + + + diff --git a/packages/html-manager/amd-public-path.js b/packages/html-manager/amd-public-path.js new file mode 100644 index 0000000000..4e83ce2235 --- /dev/null +++ b/packages/html-manager/amd-public-path.js @@ -0,0 +1,8 @@ +// In an AMD module, we set the public path using the magic requirejs 'module' dependency +// See https://github.com/requirejs/requirejs/wiki/Differences-between-the-simplified-CommonJS-wrapper-and-standard-AMD-define#module +// Since 'module' is a requirejs magic module, we must include 'module' in the webpack externals configuration. +var module = require('module'); +var url = new URL(module.uri, document.location); +// Using lastIndexOf('/')+1 gives us the empty string if there is no '/', so pathname becomes '/' +url.pathname = url.pathname.slice(0, url.pathname.lastIndexOf('/') + 1); +__webpack_public_path__ = `${url.origin}${url.pathname}`; diff --git a/packages/html-manager/webpack.config.js b/packages/html-manager/webpack.config.js index 7dca7e496b..7b8dc1d5bb 100644 --- a/packages/html-manager/webpack.config.js +++ b/packages/html-manager/webpack.config.js @@ -5,12 +5,18 @@ var path = require('path'); -var rules = [ - { test: /\.css$/, use: ['style-loader', 'css-loader'] }, - // required to load font-awesome - { test: /\.(woff|woff2|eot|ttf|otf)$/i, type: 'asset/resource' }, - { test: /\.svg$/i, type: 'asset' }, -]; +var options = { + devtool: 'source-map', + mode: 'production', + module: { + rules: [ + { test: /\.css$/, use: ['style-loader', 'css-loader'] }, + // required to load font-awesome + { test: /\.(woff|woff2|eot|ttf|otf)$/i, type: 'asset/resource' }, + { test: /\.svg$/i, type: 'asset' }, + ], + }, +}; module.exports = [ { @@ -20,9 +26,7 @@ module.exports = [ filename: 'embed.js', path: path.resolve(__dirname, 'dist'), }, - devtool: 'source-map', - module: { rules: rules }, - mode: 'production', + ...options, }, { // script that renders widgets using the amd embedding and can render third-party custom widgets @@ -31,57 +35,62 @@ module.exports = [ filename: 'embed-amd-render.js', path: path.resolve(__dirname, 'dist', 'amd'), }, - module: { rules: rules }, - mode: 'production', + ...options, }, { // embed library that depends on requirejs, and can load third-party widgets dynamically - entry: './lib/libembed-amd.js', + entry: ['./amd-public-path.js', './lib/libembed-amd.js'], output: { library: '@jupyter-widgets/html-manager/dist/libembed-amd', filename: 'libembed-amd.js', path: path.resolve(__dirname, 'dist', 'amd'), libraryTarget: 'amd', + publicPath: '', // Set in amd-public-path.js }, - module: { rules: rules }, - mode: 'production', + // 'module' is the magic requirejs dependency used to set the publicPath + externals: ['module'], + ...options, }, { // @jupyter-widgets/html-manager - entry: './lib/index.js', + entry: ['./amd-public-path.js', './lib/index.js'], output: { library: '@jupyter-widgets/html-manager', filename: 'index.js', path: path.resolve(__dirname, 'dist', 'amd'), libraryTarget: 'amd', + publicPath: '', // Set in amd-public-path.js }, - module: { rules: rules }, - externals: ['@jupyter-widgets/base', '@jupyter-widgets/controls'], - mode: 'production', + // 'module' is the magic requirejs dependency used to set the publicPath + externals: ['@jupyter-widgets/base', '@jupyter-widgets/controls', 'module'], + ...options, }, { // @jupyter-widgets/base - entry: '@jupyter-widgets/base/lib/index', + entry: ['./amd-public-path.js', '@jupyter-widgets/base/lib/index'], output: { library: '@jupyter-widgets/base', filename: 'base.js', path: path.resolve(__dirname, 'dist', 'amd'), libraryTarget: 'amd', + publicPath: '', // Set in amd-public-path.js }, - module: { rules: rules }, - mode: 'production', + // 'module' is the magic requirejs dependency used to set the publicPath + externals: ['module'], + ...options, }, { // @jupyter-widgets/controls - entry: '@jupyter-widgets/controls/lib/index', + entry: ['./amd-public-path.js', '@jupyter-widgets/controls/lib/index'], output: { library: '@jupyter-widgets/controls', filename: 'controls.js', path: path.resolve(__dirname, 'dist', 'amd'), libraryTarget: 'amd', + publicPath: '', // Set in amd-public-path.js }, - module: { rules: rules }, - externals: ['@jupyter-widgets/base'], - mode: 'production', + // 'module' is the magic requirejs dependency used to set the publicPath + externals: ['@jupyter-widgets/base', 'module'], + ...options, }, ]; diff --git a/python/widgetsnbextension/amd-public-path.js b/python/widgetsnbextension/amd-public-path.js new file mode 100644 index 0000000000..4e83ce2235 --- /dev/null +++ b/python/widgetsnbextension/amd-public-path.js @@ -0,0 +1,8 @@ +// In an AMD module, we set the public path using the magic requirejs 'module' dependency +// See https://github.com/requirejs/requirejs/wiki/Differences-between-the-simplified-CommonJS-wrapper-and-standard-AMD-define#module +// Since 'module' is a requirejs magic module, we must include 'module' in the webpack externals configuration. +var module = require('module'); +var url = new URL(module.uri, document.location); +// Using lastIndexOf('/')+1 gives us the empty string if there is no '/', so pathname becomes '/' +url.pathname = url.pathname.slice(0, url.pathname.lastIndexOf('/') + 1); +__webpack_public_path__ = `${url.origin}${url.pathname}`; diff --git a/python/widgetsnbextension/webpack.config.js b/python/widgetsnbextension/webpack.config.js index e5559ece82..47ce2dc947 100644 --- a/python/widgetsnbextension/webpack.config.js +++ b/python/widgetsnbextension/webpack.config.js @@ -1,10 +1,11 @@ var path = require('path'); module.exports = { - entry: './src/extension.js', + entry: ['./amd-public-path.js', './src/extension.js'], output: { filename: 'extension.js', path: path.resolve(__dirname, 'widgetsnbextension', 'static'), libraryTarget: 'amd', + publicPath: '', // Set in amd-public-path.js }, devtool: 'source-map', module: { @@ -15,4 +16,6 @@ module.exports = { { test: /\.svg$/i, type: 'asset' }, ], }, + // 'module' is the magic requirejs dependency used to set the publicPath + externals: ['module'], };