【実務・中級編】JupyterLabの「拡張機能作成」で業務を自動化!TypeScriptでUIを拡張するテンプレート入門 – 総合開発環境(IDE)生産性向上バイブル

はじめに:なぜ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アシスタント