主机页面与 IFrame 中运行的 JupyterLite 实例之间的通信#
当 JupyterLite 实例通过 IFrame 嵌入到网站中时,可能需要在主机页面和实例之间建立通信通道。
在以下内容中,我们将构建一个前端扩展,允许位于 IFrame 中的 JupyterLite 实例接收和处理由主机页面上的按钮触发的主题更改命令。该实例还可以向主机页面发送消息。
此扩展首先为 JupyterLab 构建,然后为 JupyterLite 构建。
创建开发环境并初始化项目#
最好为扩展开发创建一个特定环境。有多种方法可供选择。这里我们使用 conda,这是一个包和环境管理器。conda 的安装过程 在此。
按照 JupyterLab 教程 创建环境
conda create -n jupyterlab-iframe-ext --override-channels --strict-channel-priority -c conda-forge -c nodefaults jupyterlab=4 nodejs=20 git copier=7 jinja2-time jupyterlite-core
conda activate jupyterlab-iframe-ext
在您的工作区中创建一个目录,移动到该目录,然后使用 copier 生成扩展模板
copier copy https://github.com/jupyterlab/extension-template .
Select kind:
1 - frontend
2 - server
3 - theme
Choose from 1, 2, 3 [1]: 1
author_name [My Name]:
author_email [[email protected]]:
labextension_name [myextension]: jupyterlab-iframe-bridge-example
python_name [jupyterlab-iframe-bridge-example]: jupyterlab-iframe-bridge-example
project_short_description [A JupyterLab extension.]: Communication between a host page and an instance of JupyterLab located in an IFrame
has_settings [n]: n
has_binder [n]: n
test [y]: n
repository [https://github.com/github_username/jupyterlab-iframe-bridge-example]:
最后,将依赖项和扩展(目前为空)安装到环境中,然后从 JupyterLab 创建一个指向源代码的符号链接,以避免每次修改后都运行 pip install
cd jupyterlab-iframe-bridge-example
pip install -ve .
jupyter labextension develop --overwrite .
扩展开发#
使用文本编辑器修改文件 jupyterlab-iframe-bridge-example/src/index.ts
。
由于宿主页面会要求 IFrame 更改主题,因此请导入支持主题管理的插件。
import { JupyterFrontEnd, JupyterFrontEndPlugin } from '@jupyterlab/application';
import { IThemeManager } from '@jupyterlab/apputils';
还需要修改 plugin
对象的代码。
/**
* Initialization data for the jupyterlab-iframe-bridge-example extension.
*/
const plugin: JupyterFrontEndPlugin<void> = {
id: 'jupyterlab-iframe-bridge-example:plugin',
autoStart: true,
requires: [IThemeManager],
activate: (app: JupyterFrontEnd, themeManager: IThemeManager) => {
console.log('JupyterLab extension jupyterlab-iframe-bridge-example is activated!');
/* Incoming messages management */
window.addEventListener('message', (event) => {
if (event.data.type === 'from-host-to-iframe') {
console.log('Message received in the iframe:', event.data);
if (themeManager.theme === 'JupyterLab Dark') {
themeManager.setTheme('JupyterLab Light');
} else {
themeManager.setTheme('JupyterLab Dark');
}
}
});
/* Outgoing messages management */
const notifyThemeChanged = (): void => {
const message = { type: 'from-iframe-to-host', theme: themeManager.theme };
window.parent.postMessage(message, '*');
console.log('Message sent to the host:', message);
};
themeManager.themeChanged.connect(notifyThemeChanged);
},
};
export default plugin;
themeManager
对象实现了 IThemeManager
接口,其 文档 列出了可访问的属性和方法。
需要区分两种情况:接收来自宿主页面的消息和向宿主页面发送消息。
对于第一种情况,我们使用 themeManager.theme
属性来识别当前主题,并使用 themeManager.setTheme
方法来更改主题。当 IFrame 接收类型为 from-host-to-iframe
的消息时,将触发主题更改。
对于第二种情况,使用 themeManager.themeChanged
属性。当主题实际更改时,会触发此信号。它用于通过 postMessage
方法 (文档) 通知宿主页面。
从 JupyterLab 扩展到 JupyterLite 扩展#
首先安装之前代码中显示的依赖项。
jlpm add @jupyterlab/apputils
jlpm add @jupyterlab/application
构建 JupyterLab 扩展。
jlpm run build
JupyterLab 扩展已创建!以下命令检查它是否在环境中正确加载。
jupyter labextension list
移动到应该测试扩展的目录,并运行此扩展的构建以用于 JupyterLite。
mkdir examples
cd examples
jupyter lite build --output-dir lite
以下行显示扩展已成功构建。
...
federated_extensions:copy:ext:jupyterlab-iframe-bridge-example
. pre_build:federated_extensions:copy:ext:jupyterlab-iframe-bridge-example
...
一个包含 JupyterLite 工作所需的所有内容的 jupyterlab-iframe-bridge-example/examples/lite/
目录已创建(注意我们的扩展在 extensions
子目录中)。
测试扩展#
要测试包含 JupyterLite 的宿主页面和 IFrame 之间的通信,请创建一个文件 jupyterlab-iframe-bridge-example/examples/index.html
。使用以下代码编辑此文件。
<html>
<title>Example bridge between a host app and JupyterLite</title>
<body>
<script type="text/javascript">
/* Outgoing messages */
function toggle() {
window.frames.jupyterlab.postMessage({ type: 'from-host-to-iframe' });
}
/* Incoming messages */
window.addEventListener('message', (event) => {
if (event.data.type === 'from-iframe-to-host') {
document.getElementById('chosenTheme').innerText = event.data.theme;
}
});
</script>
<h2>Below is a JupyterLite site running in an IFrame</h2>
<p>
Click the following button sends a message to the JupyterLab IFrame to toggle the
theme.
</p>
<p>The IFrame indicates that the current theme is: <em id="chosenTheme"></em></p>
<input type="button" value="Toggle the JupyterLab Theme" onclick="toggle()" />
<iframe
name="jupyterlab"
src="lite/"
width="100%"
height="600px"
sandbox="allow-scripts allow-same-origin"
></iframe>
</body>
</html>
当用户单击按钮时, toggle
函数通过 postMessage
方法向 IFrame 发送消息。此消息被我们的扩展拦截,该扩展更改主题。此外,当宿主页面收到来自 IFrame 的通知有效主题更改的消息时,它会将其显示给用户。
为了可视化此过程,请从 examples
目录启动一个最小服务器。
cd examples
python -m http.server -b 127.0.0.1
在浏览器中,在地址 http://127.0.0.1:8000
,您应该能够注意到宿主页面和 IFrame 之间的通信(如果需要,请刷新浏览器)。
此外,浏览器控制台应显示类似于以下内容的消息。