はじめに:なぜJupyterLab拡張機能の自作が、データサイエンスチームの生産性を限界突破させるのか
データサイエンスやAI開発の現場において、JupyterLabは事実上の標準IDEとして君臨しています。しかし、実務で使い込むほど、このような「モヤモヤ」を抱えないでしょうか。
- 「社内の特定の推論APIを叩くコードを、毎回ノートブックにコピペしている」
- 「実験結果のメタデータを、手動でS3や社内DBに登録するオペレーションが面倒かつミスが多い」
- 「JupyterのデフォルトUIのままでは、非エンジニアのドメインエキスパートにとって敷居が高すぎる」
ネット上には「JupyterLabの拡張機能を作ろう」というチュートリアルが溢れていますが、その多くは古い`cookiecutter`テンプレートを使った挫折しやすいものか、あるいはAPIの変更に追いついていない動かないコードの羅列です。
本稿では、テックリードである私が、TypeScriptとReact、そして現代の標準である`@jupyterlab/extension-builder`(正確にはJupyterLabが推奨する標準ビルドシステムである`jlpm` / `jupyterlab-builder`)を用いた、最も堅牢でモダンな拡張機能開発の最短ルートを伝授します。
単なる「ボタンの置き方」にとどまらず、チーム全体の開発スピードを劇的に高めるための実践知を余すところなく公開しましょう。
—
1. 開発環境の要塞化:迷いのないTypeScript拡張開発フロー
JupyterLabの拡張機能(JupyterLab Extension)の実体は、実はJupyterLabのフロントエンド(LuminoというアプリケーションフレームワークをベースにしたPhosphor系UI)に動的にロードされるNPMパッケージです。そのため、Pythonの環境だけでなく、Node.jsとTypeScriptの厳格な型安全の恩恵を受ける開発環境を構築する必要があります。
究極のプロジェクト初期化手順
まずは、拡張機能開発のベースとなるディレクトリ構造を構築します。環境を汚さないために、Pythonの仮想環境とNode.jsのバージョンを固定しましょう。
1. 開発専用の仮想環境を作成し、JupyterLabと開発用ツールをインストール
conda create -n jlab-dev python=3.10 -y
conda activate jlab-dev
pip install jupyterlab cookiecutter
2. 公式が提供する最新のTS拡張機能テンプレートからプロジェクトを生成
(対話式プロンプトで名前等を指定。ここでは拡張機能名を ‘jupyterlab-ai-assistant’ と仮定)
cookiecutter https://github.com/jupyterlab/extension-cookiecutter-ts
3. 生成されたディレクトリに移動
cd jupyterlab-ai-assistant
4. JupyterLab同梱のyarn(jlpm)を用いて依存関係をインストールし、開発モードでビルド
jlpm install
jlpm run build
jupyter labextension develop . –overwrite
ここで重要なのが、最後の `jupyter labextension develop . –overwrite` というコマンドです。このコマンドにより、ソースコードを変更した際に、わざわざパッケージを再インストールしなくても、シンボリックリンク経由でJupyterLab側へ即座に変更が反映されるようになります。
—
2. 実装:Reactでサイドバーウィジェットとコマンドを爆速構築する
それでは、JupyterLabの左サイドバーに独自のカスタムパネル(React製)を表示し、それを操作する「コマンド」をシステムに登録する実装を行います。
ターゲットファイル構成
プロジェクト内の `src/index.ts`(メインのエントリーポイント)と、新しく作成する `src/AIPanel.tsx` を書き換えます。
`src/AIPanel.tsx` (Reactコンポーネント)
UIの構築にはReactを採用します。JupyterLabのUIテーマ(ダークモード等)に完全準拠させるため、JupyterLab標準のCSS変数を意識したスタイリングを行います。
import React, { useState } from ‘react’;
import { ReactWidget } from ‘@jupyterlab/apputils’;
/
- 1. 実際に描画されるReactコンポーネント
/
const AIPanelComponent: React.FC = () => {
const [prompt, setPrompt] = useState(”);
const [response, setResponse] = useState(”);
const handleExecute = () => {
// 実務ではここでバックエンドAPI(Python側)へリクエストを飛ばします
setResponse(`[AI Mock Response]: “${prompt}” の処理が完了しました。`);
setPrompt(”);
};
return (
社内AIアシスタント
);
};
/
- 2. JupyterLabのLuminoウィジェットシステムにReactをマウントするためのラッパー
/
export class AIPanelWidget extends ReactWidget {
constructor() {
super();
// JupyterLab上のDOM要素としてのクラス名を付与
this.addClass(‘jp-AI-Panel’);
this.id = ‘ai-assistant-sidebar’;
this.title.label = ‘AIアシスタント’;
// JupyterLab標準のアイコン(UIkit)を付与。ここではダミーとしてロケットアイコン
this.title.iconClass = ‘jp-Icon jp-Icon-16 jp-RocketIcon’;
}
protected render(): React.ReactElement {
return
}
}
`src/index.ts` (JupyterLabプラグインの登録)
作成したReactウィジェットをJupyterLabのアプリケーションライフサイクルに組み込みます。
import {
JupyterFrontEnd,
JupyterFrontEndPlugin
} from ‘@jupyterlab/application’;
import { ICommandPalette } from ‘@jupyterlab/apputils’;
import { AIPanelWidget } from ‘./AIPanel’;
/
- JupyterLab拡張機能のコア定義オブジェクト
/
const plugin: JupyterFrontEndPlugin
id: ‘jupyterlab-ai-assistant:plugin’,
autoStart: true, // JupyterLab起動時に自動ロード
requires: [ICommandPalette], // コマンドパレット機能に依存
activate: (app: JupyterFrontEnd, palette: ICommandPalette) => {
console.log(‘JupyterLab拡張機能 “jupyterlab-ai-assistant” がアクティブ化されました。’);
// 1. ウィジェットのインスタンス化
const widget = new AIPanelWidget();
// 2. 左側のサイドバー(Shell.left)にウィジェットを追加
app.shell.add(widget, ‘left’, { rank: 500 });
// 3. コマンドパレットから呼び出せる「コマンド」の定義
const commandId = ‘ai-assistant:toggle’;
app.commands.addCommand(commandId, {
label: ‘AIアシスタントパネルの表示/非表示’,
execute: () => {
// サイドバーの表示状態をトグルする
if (widget.isHidden) {
app.shell.activateById(widget.id);
} else {
widget.close();
}
}
});
// 4. コマンドパレット(Ctrl+Shift+P等)へコマンドを登録
palette.addItem({ command: commandId, category: ‘AI 拡張機能’ });
}
};
export default plugin;
—
3. プロの実践テクニック:開発スピードを極限まで高めるノウハウ
ここからは、ネットのチュートリアルには載っていない、現場のテックリードが実践している「生産性を爆上げする極意」を伝授します。
① 開発ループの超高速化(Watchモード)
コードを書くたびに `jlpm run build` を手動で叩いていたら日が暮れます。以下のコマンドを別のターミナルタブで常時起動させておいてください。
TypeScriptのコンパイラをWatchモードで常時監視・ビルド
jlpm run watch
これにより、ソースコードを保存(Ctrl+S)した瞬間にTypeScriptがコンパイルされ、ブラウザをリロードするだけで変更が反映されます(JupyterLabのHot Module Replacementに近い挙動を得られます)。
② チーム開発で絶対に事故らない「バージョン固定」と「設定の共有化」
複数のデータサイエンティストやエンジニアが同じ拡張機能を使う、あるいは共同開発する場合、JupyterLab自体のバージョン差異によるビルドエラーが頻発します。これを防ぐため、リポジトリのルートに以下の設定を強制します。
推奨する `package.json` の依存関係管理ベストプラクティス
{
“name”: “jupyterlab-ai-assistant”,
“version”: “0.1.0”,
“private”: true,
“engines”: {
“node”: “>=18.0.0”,
“jupyterlab”: “^4.0.0”
},
“scripts”: {
“build”: “jlpm run build:lib && jlpm run build:labextension”,
“build:lib”: “tsc”,
“build:labextension”: “jupyter labextension build .”,
“watch”: “run-p watch:src watch:labextension”,
“watch:src”: “tsc -w”,
“watch:labextension”: “jupyter labextension watch .”
},
“dependencies”: {
“@jupyterlab/application”: “^4.0.0”,
“@jupyterlab/apputils”: “^4.0.0”,
“@lumino/widgets”: “^2.0.0”,
“react”: “^18.2.0”
},
“devDependencies”: {
“@jupyterlab/builder”: “^4.0.0”,
“typescript”: “~5.0.2”
}
}
> アーキテクトの知見: `engines` フィールドで Node.js と JupyterLab のバージョンレンジを厳密に縛ることで、CI/CDパイプラインや他メンバーのローカル環境での「動かない」トラブルを未然に防ぎます。
—
4. チーム全体へ展開する:CI/CDによる自動ビルドと配布
自作した拡張機能をチームメンバー全員に簡単に使ってもらうため、`.whl`(Pythonのホイールファイル)またはnpmパッケージとしてビルドし、社内のプライベートPyPIやGitHub Packagesで共有するのがプロのやり方です。
拡張機能をパッケージングするコマンド
1. 本番用の最適化されたバンドルを作成
jlpm run build
2. Pythonのインストール可能なパッケージ(アーティファクト)を作成
pip install build
python -m build
このコマンドを実行すると、`dist/` ディレクトリに `.tar.gz` と `.whl` ファイルが生成されます。チームメンバーは、以下のコマンドを叩くだけで、あなたの作った最強の拡張機能を即座に導入できます。
pip install dist/jupyterlab_ai_assistant-0.1.0-py3-none-any.whl
jupyter labextension enable jupyterlab-ai-assistant
—
ニッチな要件のために、毎回面倒な手作業を繰り返すのは今日で終わりにしましょう。TypeScriptとReact、そしてJupyterLabの拡張機能アーキテクチャをマスターすれば、データサイエンス環境はあなたとチームの手に完全に服従します。ぜひ、明日の開発からこのテンプレートを導入し、チームの生産性を圧倒的な高みへと引き上げてください。