Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better logic to set webpack public path in AMD modules #3508

Merged
merged 1 commit into from
Jul 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions examples/embed-amd/README.md
Original file line number Diff line number Diff line change
@@ -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.
167 changes: 167 additions & 0 deletions examples/embed-amd/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF8">
<style>
.jupyter-widgetarea {
margin: 5px;
margin-left: auto;
margin-right: auto;
max-width: 900px;
}
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.js"></script>
<script>
require.config({
bundles: {
'@jupyter-widgets/html-manager/dist/embed-amd': [
'@jupyter-widgets/html-manager',
'@jupyter-widgets/base',
'@jupyter-widgets/controls'
]
},
paths: {
'@jupyter-widgets/html-manager': [
// 'html-manager', // if a symbolic link is set up to the html-manager package for local dev
'https://cdn.jsdelivr.net/npm/@jupyter-widgets/html-manager',
]
},
})
require(["@jupyter-widgets/html-manager/dist/embed-amd"], () => {
console.log('Processing widgets on page');
});
</script>
<script type="application/vnd.jupyter.widget-state+json">
{
"version_major": 2,
"version_minor": 0,
"state": {
"1d915e54eff54fd89e505a46ccabdabd": {
"model_name": "LayoutModel",
"model_module": "@jupyter-widgets/base",
"model_module_version": "2.0.0",
"state": {}
},
"48a42260652f4b7eb7851c65cd155604": {
"model_name": "SliderStyleModel",
"model_module": "@jupyter-widgets/controls",
"model_module_version": "2.0.0",
"state": {
"description_width": ""
}
},
"105655a5e8dc4b7bb19d824cc3ff7770": {
"model_name": "IntSliderModel",
"model_module": "@jupyter-widgets/controls",
"model_module_version": "2.0.0",
"state": {
"value": 100,
"max": 200,
"style": "IPY_MODEL_48a42260652f4b7eb7851c65cd155604",
"behavior": "drag-tap",
"layout": "IPY_MODEL_1d915e54eff54fd89e505a46ccabdabd"
}
},
"cb13b25cf84542ba882ab2a9c6e57c6d": {
"model_name": "LayoutModel",
"model_module": "@jupyter-widgets/base",
"model_module_version": "2.0.0",
"state": {}
},
"f0479b348e2441cd87e1bd856fac5c22": {
"model_name": "SliderStyleModel",
"model_module": "@jupyter-widgets/controls",
"model_module_version": "2.0.0",
"state": {
"description_width": ""
}
},
"2182c1a3fe4a410f9b0a5306ae05c530": {
"model_name": "IntSliderModel",
"model_module": "@jupyter-widgets/controls",
"model_module_version": "2.0.0",
"state": {
"value": 40,
"style": "IPY_MODEL_f0479b348e2441cd87e1bd856fac5c22",
"behavior": "drag-tap",
"layout": "IPY_MODEL_cb13b25cf84542ba882ab2a9c6e57c6d"
}
},
"5f2da4ad981b467cb2d4f07efe5141f4": {
"model_name": "LayoutModel",
"model_module": "@jupyter-widgets/base",
"model_module_version": "2.0.0",
"state": {}
},
"e5f63e1e06af400aac8135ff3394b856": {
"model_name": "ButtonStyleModel",
"model_module": "@jupyter-widgets/controls",
"model_module_version": "2.0.0",
"state": {
"font_family": null,
"font_size": null,
"font_style": null,
"font_variant": null,
"font_weight": null,
"text_color": null,
"text_decoration": null
}
},
"891a12a9856949b4be2e520f732dcca9": {
"model_name": "ButtonModel",
"model_module": "@jupyter-widgets/controls",
"model_module_version": "2.0.0",
"state": {
"tooltip": null,
"icon": "legal",
"style": "IPY_MODEL_e5f63e1e06af400aac8135ff3394b856",
"layout": "IPY_MODEL_5f2da4ad981b467cb2d4f07efe5141f4"
}
},
"e8a6db8ff7bd4645b5b23ccb797dee9c": {
"model_name": "DirectionalLinkModel",
"model_module": "@jupyter-widgets/controls",
"model_module_version": "2.0.0",
"state": {
"target": [
"IPY_MODEL_2182c1a3fe4a410f9b0a5306ae05c530",
"max"
],
"source": [
"IPY_MODEL_105655a5e8dc4b7bb19d824cc3ff7770",
"value"
]
}
},
"b9445ea442bc4a5aae73c1e2241c3922": {
"model_name": "LayoutModel",
"model_module": "@jupyter-widgets/base",
"model_module_version": "2.0.0",
"state": {}
},
"a08a1974ba01461c8d9b91b8bfa0f6ce": {
"model_name": "VBoxModel",
"model_module": "@jupyter-widgets/controls",
"model_module_version": "2.0.0",
"state": {
"children": [
"IPY_MODEL_105655a5e8dc4b7bb19d824cc3ff7770",
"IPY_MODEL_2182c1a3fe4a410f9b0a5306ae05c530",
"IPY_MODEL_891a12a9856949b4be2e520f732dcca9"
],
"layout": "IPY_MODEL_b9445ea442bc4a5aae73c1e2241c3922"
}
}
}
}
</script>
<script type="application/vnd.jupyter.widget-view+json">
{
"version_major": 2,
"version_minor": 0,
"model_id": "a08a1974ba01461c8d9b91b8bfa0f6ce"
}
</script>
</body>
</html>
8 changes: 8 additions & 0 deletions packages/html-manager/amd-public-path.js
Original file line number Diff line number Diff line change
@@ -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}`;
59 changes: 34 additions & 25 deletions packages/html-manager/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
{
Expand All @@ -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
Expand All @@ -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,
},
];
8 changes: 8 additions & 0 deletions python/widgetsnbextension/amd-public-path.js
Original file line number Diff line number Diff line change
@@ -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}`;
5 changes: 4 additions & 1 deletion python/widgetsnbextension/webpack.config.js
Original file line number Diff line number Diff line change
@@ -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: {
Expand All @@ -15,4 +16,6 @@ module.exports = {
{ test: /\.svg$/i, type: 'asset' },
],
},
// 'module' is the magic requirejs dependency used to set the publicPath
externals: ['module'],
};