Web関係のJavascript 開発では、Node.js を使って モジュールに分割して開発をしていく。 これを InDesign 用の ExtendScript でもできるようにしたい。 もちろん、ExtendScript にも @include 記述により、モジュールを使うことはできる。 しかし、その場合できあがったコードを配布するときに、依存しているモジュールファイルも一緒に渡す必要が生じる。 これを避けたい。配布時には単にひとつのファイルだけで完結したい。
まず、ExtendScript のことは考えないで、Javascript の世界において標準の モジュール管理方法を把握しよう。 調べてみると、CommonJS や ESM(ECMAScript Modules) などの方法があるらしい。 しかし、2021年においては、ESM が主流のようなので、これを使おう。
ESM については developer.mozilla.org のページ を 読めばおおむね把握できる。
そして、この ESM 方式により複数のコードを一つのコードにまとめる方法は、Node.js + webpack を使うのが主流らしい。 このエントリーでは、いちばん基本のこの方法を試します。
なお、試行錯誤の結果、最終的には webpack ではなく rollup を使うことにした。その件はパート2にまとめました。
それでは Node.js でモジュールを使ったコードをつくっていく。 ここでは、sayHello と sayKonnitiwa という 2つのfunction を持ったモジュールを export し、メインのコードからこれらを import して使うことにする。
ここで使用するツールは Node.js と Make でそれぞれバージョンは以下の通り:
$ node -v
v12.16.2
$ make -v
GNU Make 3.81
それでは、プロジェクトとディレクトリを作成し、必要なツールをインストールする:
$ mkdir sayhello
$ cd sayhello
$ npm init -y
$ npm install webpack@5.52.0 --save-dev
$ npm install webpack-cli@4.8.0 --save-dev
ここまでのところで、一旦 package.json を確認します:
{
"name": "sayhello",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^5.52.0",
"webpack-cli": "^4.8.0"
}
}
方針は以下のようにします。
この方針にしたがって、webpack の設定を先にしておきます。 webpack では webpack コマンドを実行したときに webpack.config.js を読む、という暗黙のルールがある。
webpack.config.js :
module.exports = {
mode: 'production',
entry: './main.js',
output: {
path: __dirname,
filename: 'main.jsx'
}
};
ここでは、単に main.js から main.jsx を生成するよ、という設定をしているだけです。 モジュールに関する指定はなく、webpack が main.js 内に設定されているモジュールを読みとって、いいかんじに一つにまとめてくれるようです。
それではコードを書きます。
js_modules/say.js :
var sayHello = function(name){
return 'Hello, ' + name + '!';
};
var sayKonnitiwa = function(name){
return 'こんにちは ' + name + '!';
};
export { sayHello, sayKonnitiwa };
エクスポートした sayHello, sayKonnitiwa 関数を使うメインのコード main.js:
import {sayHello,sayKonnitiwa} from './js_modules/say.js';
console.log( sayHello('Taro') );
console.log( sayKonnitiwa('Hanako') );
ここまでで、ディレクトリ構成を確認しておきます:
.
├── js_modules
│ └── say.js
├── main.js
├── node_modules/
├── package-lock.json
├── package.json
└── webpack.config.js
それでは webpack コマンドを実行して、main.js と js_modules/say.js をひとつにまとめた main.jsx を生成します。
webpack コマンドは ./node_modules/.bin/webpack にインストールされているので:
$ ./node_modules/.bin/webpack
とすれば、webpack.config.js の内容にしたがって main.jsx が生成されます。
$ node main.jsx
Hello, Taro!
こんにちは Hanako!
うまくいきました。
ExtendScript には console.log が無いのでそれを用意します。
main.js :
import {sayHello,sayKonnitiwa} from './js_modules/say.js';
var console = {};
console.log = function(message){
$.writeln(message);
};
console.log( sayHello('Taro') );
console.log( sayKonnitiwa('Hanako') );
webpack コマンドを実行して・・・ですが、面倒なので、Make で処理できるように Makefile をつくります。
main.jsx: main.js js_modules/say.js
./node_modules/.bin/webpack
echo "//@target InDesign" >> $@
clean:
$(RM) main.jsx
VSCode + ExtendScript Debugger で InDesign を使ってこのコードを実行するために、 @target InDesign を main.jsx の末尾に追加しておきます。
make を実行して、先ほどの変更を反映しておきます:
$ make main.jsx
さらに VSCode + ExtendScript Debugger で InDesign を使ってこのコードを実行するために、 .vscode/launch.json を追加:
{
"version": "1.0.0",
"configurations": [
{
"type": "extendscript-debug",
"request": "launch",
"name": "main.jsx",
"program": "${workspaceFolder}/main.jsx",
"stopOnEntry": false
}
]
}
いろいろファイルを追加したので、現在のプロジェクトディレクトリ状況を確認:
.
├── Makefile
├── js_modules
│ └── say.js
├── .vscode
│ └── launch.json
├── main.js
├── main.jsx
├── node_modules/
├── package-lock.json
├── package.json
└── webpack.config.js
これで準備が整ったので、 code . して VSCode を起動して、InDesign で main.jsx をデバッグ実行してみます。
・・・エラーです。 webpack により生成された main.jsx の先頭部分の記述に問題があるようです。
(()=>{
こういう書き方は ExtendScript は対応していないので、手動で書き直します。
(function(){
これで再度実行。
うまくいきました。
しかし、生成対象の main.jsx を毎回手作業で直すのは面倒です。 パート2 ではこの問題を回避する方法を考えます。