AI 技術開発部プロダクトグループの Atsushi Morimoto (@74th)です。
プロダクトグループでは、主に Android+Python の組み合わせで開発を進めることが多いですが、 今回 Web アプリとして作る必要があり、TypeScript(React&Redux)+Go、TypeScript(React&Redux)+Python という組み合わせで、2 つのプロダクトを開発することになりました。
フロントエンドの開発では多数のツールを使って開発することが求められ、それぞれのツールの設定が必要になります。また、Web API とフロントエンドを連携して動作させる必要があり、これまではAPIとフロントエンドをそれぞれデバッグやテストを実行することが主でした。
今回メンバーの作業環境を VS Code に揃えることができたため、開発環境の設定の多くを、VS Code のプロジェクト設定として作り込むことができました。 この記事では、TypeScript(React)+Pythonの開発環境を、VS Code で開発環境を整える方法にについて解説します。
フロントエンドとWeb API の開発者が同一であるため、一つのリポジトリで管理することにしました。Pythonは1つのパッケージにわけ、依存するパッケージはPoetryを使って管理します。
product_folder
|- product_api/ PythonのサーバAPIのコード
| |- __init__.py
| `- __main__.py
|- pyproject.toml Python依存ライブラリの管理ファイル
|- poetry.lock
|
|- front/ フロントエンドのコード
| |- package.json 依存NPMライブラリの管理ファイル
| `- index.tsx
|
`- public/ HTML、CSSなどWebで公開されるディレクトリ
|- index.html
`- js/ ビルド後のフロントエンドのJavaScriptの配置ディレクトリ
VS Code ではプロジェクトに依存した設定を.vscode ディレクトリに格納することで、開発者間で設定を共有することができます。
今回は以下の4つの設定を使いました。
product_folder
`- .vscode/
|- settings.json : VS Code の環境設定
|- tasks.json : タスク
|- launch.json : デバッグ
`- extensions.json : インストールする拡張機能
.vscode/extensions.json に、拡張機能の ID を記述しておくと、リポジトリを VS Code で開いたときに「推奨する拡張機能があります」とポップアップが表示されるようになります。ポップアップでインストールを選ぶと、すべての拡張機能を一度にインストールさせることができます。この方法で使用する拡張機能を揃えることができます。
今回、TypeScript+Python の開発環境でインストールした拡張機能は以下のとおりです。
{
"recommendations": [
// TypeScript、HTML、CSSのフォーマット
"esbenp.prettier-vscode",
// Python
"ms-python.python",
// Pylance も試しに有効にする
"ms-python.vscode-pylance",
// フロントエンドのデバッガ
"msjsdiag.debugger-for-chrome",
// タブ/スペースの数やエンコードなど、
// テキストのフォーマットを統一する
"editorconfig.editorconfig",
]
}
TypeScript の開発ツールは、VS Code に最初からビルドインされているため、必要なものは少なくて済みます。
VS Code上で表示や検索をさせないファイルの設定や、利用するフォーマッタの指定、ユニットテストの実行に必要な引数などを、ワークスペースの設定 .vscode/settings.json に作り込むことができます。
今回は以下の設定を使用しました。
{
// .venvのファイルや、一部の生成ファイルは検索から除外する
"files.exclude": {
".venv": true
},
"search.exclude": {
".venv": true,
"_openapi_generator": true
},
// mypyを有効化する
"python.linting.mypyEnabled": true,
"python.testing.pytestEnabled": false,
"python.testing.nosetestsEnabled": false,
// Pylanceを有効にする場合、コメントを解除する
// "python.languageServer": "Pylance",
// Pythonのフォーマッタは black とする
"python.formatting.provider": "black",
// TypeScriptのフォーマッタは prettier とする
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
// フォーマットはファイル保存で自動で行う
"editor.formatOnSave": true,
// Pythonのユニットテストを有効化する
"editor.codeLens": true,
"python.testing.unittestEnabled": true,
"python.testing.unittestArgs": [
"-v",
"-s",
"product_folder.test",
"-p",
"test_*.py"
],
}
フロントエンドの開発では、webpack を使って、依存する NPM モジュールをすべてまとめて 1 ファイルにし、フロントエンドで使えるようにしてくれます。 また、この時に TypeScript と React を JavaScript に変換する処理が行われます。
今回 TypeScript の設定である.tsconfig.json は、Chrome ブラウザのみを対象にして良いこともあり、以下のように設定しました。
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"jsx": "react",
"strict": true,
"esModuleInterop": true,
"sourceMap": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}
webpack の設定である webpack.config.js に、TypeScript と React の設定を盛り込みます。ts-loader によって、TypeScript のファイルを webpack が解釈できるようになります。 babel-loader は param?.property というような記述が、ts-loader だけではエラーになることがあり、追加しています。
const path = require("path");
let exclude = [path.resolve(__dirname, "public")];
module.exports = {
entry: "./index.tsx",
mode: "development",
devtool: "source-map",
resolve: {
extensions: [".tsx", ".ts", ".js"],
},
module: {
rules: [
{
test: /\\.tsx?$/,
exclude,
use: [
{
loader: "babel-loader",
options: {
plugins: ["@babel/plugin-proposal-optional-chaining"],
},
},
{
loader: "ts-loader",
options: {
transpileOnly: true,
happyPackMode: true,
},
},
],
},
{
enforce: "pre",
test: /\\.js$/,
loader: "source-map-loader",
exclude,
},
],
},
devServer: {
contentBase: "../public/",
},
output: {
filename: "index.js",
path: path.resolve(__dirname, "../public/js"),
},
};
この webpack のビルドを行うには、コマンドラインでは以下のコマンドを実行します。 オプション -w をつけると、ディレクトリのファイルの変更を検出し、自動的にビルドを行うようになります。
npx webpack-cli -w
これを、NPM パッケージのタスクランナーに記述すると、以下のように記述できます。 watch:webpack という設定がそれにあたります。npm-run-allは、タスクランナーを直列(npm-s)、並列(npm-p)に実行するときに便利なパッケージで、挟んでいます。
{
"略": "...",
"devDependencies": {
"npm-run-all": "^4.1.5",
"source-map-loader": "^1.0.0",
"ts-loader": "^7.0.5",
"ts-node": "^8.10.2",
"typescript": "^3.9.6",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11"
},
"scripts": {
"build": "run-s build:webpack",
"build:webpack": "webpack-cli",
"watch": "run-p watch:webpack",
"watch:webpack": "webpack-cli -w"
}
}
VS Code は、NPM パッケージのタスクランナーの設定を自動で読み取り、実行できるようにする機能がついています。 それを実行するには以下の手順になります。
しかし、VS Code を起動するたびに毎回コマンドを実行するのは億劫です。 VS Code 起動時に、自動的にこのタスクが実行する設定ができます。
それにはまず、VS Code のタスクとして NPM パッケージのタスクランナーを登録します。 "type": "npm"とし、"script"に実行するタスク名を記述します。
これに加えて、"runOptions": { "runOn": "folderOpen" },を設定します。これは、VS Code でフォルダーを開いたときに自動で実行させるようにするオプションです。
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"label": "watch webpack",
"script": "watch:webpack",
"path": "front/",
"group": "build",
"runOptions": { "runOn": "folderOpen" },
"problemMatcher": []
}
]
}
セキュリティ上、不用意に自動実行されることがないように、VS Code ではこの設定がされていたとしても、コマンド"Tasks: Manage Automatic Task in Folder"を使って許可しない限り実行がされないようになっています。よってこのコマンド実行し、"Allow"を選択します。
すると、次に VS Code でこのフォルダーを開いたときに自動でこのタスクが実行されるようになります。
VS Code の特徴として、複数のデバッグを同時に実行して、協調してデバッグ実行できることがあります。 では実際に、PythonのWeb API と、フロントエンドの Type Script のデバッグ実行を行う方法を解説します。
まず、PythonのWeb API のコードは以下のようになっています。
この API をシェル上で実行するには、以下のコマンドを実行します。
python -m product_api
では、このproduct_apiモジュールのデバッグを開始するには、.vscode/launch.json に以下のように記述します。
{
"version": "0.2.0",
"configurations": [
{
"name": "API",
"type": "python",
"request": "launch",
"module": "product_api"
}
]
}
次に、フロントエンドの Type Script のデバッグ実行の設定を示します。
{
"version": "0.2.0",
"configurations": [
{
"name": "API"
// 省略
},
{
"name": "frontend",
"request": "launch",
"type": "pwa-chrome",
"url": "<http://localhost:8080/index.html>",
"webRoot": "${workspaceFolder}/public",
"sourceMaps": true,
"sourceMapPathOverrides": {
"webpack:///./*": "${workspaceFolder}/front/*"
}
}
]
}
ポイントは Source Map を使う点です。 TypeScript は JavaScript に変換されるため、実際に実行しているのは JavaScript になります。TypeScriptをデバッグ実行するとは、JavaScriptをデバッグ実行しながら、そのJavaScriptの元になっているTypeScriptを表示することです。Source Mapによって、それが可能になります。 今回の、TypeScript のコードは、 webpack の上では、webpack:///./index.tsx といったように webpack:///./ というプレフィックスで管理されています。 どのように管理されているかは、実際に Chrome の DevTools で開いてみることで確認することができます。
VS Code では、このwebpack:///./*というパスを、実際のディレクトリに対応させることで、デバッグ実行時に TypeScript のファイルを表示することができます。
最後に、Web API とフロントエンドを同時デバッグする方法を説明します。
まず、Web API のデバッグであるAPIをデバッグの設定から選択し、デバッグの開始▷を押します。 すると、Web API がデバッグ実行が開始されます。
次に、もう一度デバッグの設定をfrontに変更し、デバッグの開始▷を押します。 すると、Chrome ブラウザが立ち上がり、フロントエンドのデバッグ実行が開始されます。
コールスタックの欄には、APIとフロントエンドの2つが表示されます。変数などの表示を切り替えるには、これをクリックしたり、ステップ実行のボタンの横のプルダウンで切り替えます。
Web API の Python のコード、フロントエンドの Type Script のコードの両方にブレイクポイントを設定した場合、それぞれのプログラムがブレイクポイントに到達したときに自動でWeb APIとフロントエンドのデバッグの表示が切り替わります。
これにより、Web APIとフロントエンドを協調させてデバッグ実行することが可能になります。
.vscode ディレクトリに設定を書き込んでいくことで、VS Code で以下のことを実現できました。
VS Code はエンジニア間での開発環境を整えるのに最適な環境です。ぜひこの記事を参考に、開発環境を作ってみてもらえればと思います。より詳しい VS Code の使い方については、拙書『Visual Studio Code 実践ガイド』森下篤著(技術評論社)も参考にしていただければと思います。
また、今回の記事のネタのように、Mobility Technologiesでは、AI技術に特化した領域だけでなく、AI技術をプロダクトにつなげることができるサーバサイドエンジニアも随時募集しています!
https://hrmos.co/pages/mo-t/jobs