iOSアプリ「Scriptable」のスクリプトを管理するためのプロジェクト
を置いた。以下、バンドルの仕組みを説明する。(TODO:図解が必要)
ScriptableはiOS/iPadOS内のJavaScript実行環境。
Scriptableを使っていると、Scriptableからnpmパッケージを利用したいことも出てくる。
Macでパッケージをバンドルしてモジュールを作れば利用できる。そのためのプロジェクト。
Scriptableアプリ。無料。ScriptableiCloudMacとVSCode
Scriptableアプリで実行するスクリプトはiCloudを通してMacからも編集できる。
それを利用して、Macでモジュールをバンドルする。
Scriptableのスクリプトを書いている時に、npmパッケージを使いたいことがある。
このプロジェクトを使って、バンドルされたモジュールを作成し、ScriptableからimportModuleでインポートできる。
- このリポジトリをクローンする
- 必要なシンボリックリンクを張る
- このプロジェクトにて
dist:Scriptableディレクトリ(iCloud内にあるScriptableのスクリプトが格納されているディレクトリ)へのシンボリックリンク。バンドル後に格納するため。ln -s "~/Library/Mobile Documents/iCloud~dk~simonbs~Scriptable/Documents" dist- 各種設定ファイル:
.eslintrc,.editorconfig,.prettierrcなど。ScriptableのスクリプトをMacで編集する時と同じ設定で使いたい場合に、必要なファイルをシンボリックリンクで共有。
Scriptableディレクトリにて$ cd "~/Library/Mobile Documents/iCloud~dk~simonbs~Scriptable/Documents"@types: プロジェクトのnode_modules/@typesにリンクを張る
- このプロジェクトにて
- 必要なパッケージをインストールする
srcにて、パッケージとスクリプトをつなぐためのモジュールを作成する。src/some-module.jsを作成src/some-module.js内で、さっきインストールした外部パッケージをimportするimportしたものをmodule.exportsを使ってexportする- バンドルと配置を実施する。コマンドパレットを開き、「タスクの実行」から「このファイルをバンドルしdistに配置する」を選ぶ。
npm buildでsrc/*.jsを全てビルドしてもよい。 dist内にバンドル後のファイルdist/some.bundle.jsが配置されたことを確認するScriptableスクリプトを作成する- そのスクリプトでバンドル後のファイルをインポートする
importModule('some.bundle.js') - パッケージの機能を使ったスクリプトを実行する(
iPhoneまたはiPadで) - Enjoy!
- ピュアJS。ネイティブコードを利用したパッケージなどは利用できない
Scriptableにないnodeコアモジュールを使用していないこと。ただし、モックでカバーすればビルド可能fs,path,utilについて、モックでカバーしているrequire.main定数について、モックでカバーしている 適切なポリフィルがあればそれを持ってくればよいが、Scriptableで動くという条件を満たさないことがほとんど。完璧なポリフィルを探す旅に出ると永遠に帰ってこられない。だからといって、あちこちで気軽に利用されているコアモジュールにぶつかるたびに諦めるのも悔しい。実際の動作として必要のあるところだけ実装して、他はインタフェースだけ用意するモンキーパッチでしのいでいく方針でやっている。
src/にいくつかスクリプトが置いてある。これらは外部パッケージを利用可能にするモジュールで、バンドルすればScriptableから利用できる。バンドル前のスクリプる(バンドルすると.bundleつきのファイルができる)。いくつか説明する。
絵文字にマッチする正規表現オブジェクトを提供するモジュール emoji-regex を require/exportするモジュール。/絵文字1文字/gの正規表現を返す。ZWJ Sequencesを考慮したマッチを提供してくれる。
const text = "🐱😗👩💻👨👨👦👦"
const emojiRegex = importModule("emoji-regex.bundle")()
const match = text.match(emojiRegex)
console.log(match)
// [ '🐱', '😗', '👩💻', '👨👨👦👦' ]CSVパースライブラリpapaparseをrequireしexportするだけのモジュール。ピュアJSで書かれており、単純にrequireしてexportするだけのモジュールを書いてバンドルすればScriptableで利用できる。
discordjsの一部(REST呼び出し)を利用するためのモジュール。
Routes: エンドポイント作成のためのAPI。discord-api-types/v10をインポートして利用REST4Scriptable:Discord RESTリクエストを発行するAPI。本来なら@discordjs/restを使うところだが、fetchを利用しているために利用できない。Scriptable用にサブセットを実装した。
スクリプト側(importModule()を呼び出すスクリプト)のコメントに @type を書く。
/**
* @type {import("discord-rest").REST4Scriptable}
* @type {import('discord-api-types/v10').Routes}
*/モジュール側にJSDocを書いておくとJSDocの情報が表示される(補完は難しいようだ)。
外部パッケージを利用している場合はそちらの@typesを参照するとよい。
ディレクトリに.publicというファイル(YAML形式)がある場合、そこで指定されたディレクトリから指定ファイルをコピーしてきてステージする。というコマンドを用意した。コミット前に実行するようになっている。
scriptsディレクトリの.publicファイルはこうなっている:
- original: ../dist
files:
- README.md
- lg.js
- template4script.js
- scriptable-ix.jsoriginal: 公開したいファイルの入っているディレクトリを指定。当該.publicのあるディレクトリからの相対パスか、~で始まるパス、または絶対パスで指定する。../dist には実際のスクリプトが入っているが、すべて公開するわけにはいかない。ここで指定したスクリプトだけを公開する。
files: 公開したいファイルのリスト。originalからの相対パスで指定する。