extendscript
TypeScript
AfterEffects
gulp

typescriptでExtendScriptを書いてみた その2

More than 1 year has passed since last update.

前回のまとめ

前回はtypescriptでExtendScriptを書いてみました。

typescriptでExtendScriptを書いてみた

typescriptではjsへの変換が必要なので以下のような手順を踏むことになります

コードを書く>保存>jsに変換>estkで開く>実行

作成するスクリプトが単体のファイルであれば、vscodeの「tscウォッチ」タスクで自動に変換されたjsファイルをそのままestkで実行可能ですが、ファイルを複数に分けている場合には変換後にbrowserifyを使用してファイルを1本化する必要がありました。

今回はこれら変換、結合を自動化するためにgulpを使用してみようと思います。

gulpを使用する

gulp.js

gulpもnpmでインストールします。相変わらず-gでインストールしたくないので以下のようにします

cmd
npm install gulp --save-dev

そしてgulpfile.jsをいうのを記述します。

gulpfile.js
const gulp = require('gulp');

gulp.task('default', function () {
    console.log('test');
})

vscodeでタスクの構成を選ぶと
gulp: defaultが出てきていると思います。
これを選ぶと.vscodeフォルダ内にtask.jsonというファイルが作成されて、そこに実行可能タスクが書き込まれます。

タスクの実行を選ぶと
gulp: defaultが出ているので、それを選択して実行すると、ターミナルウィンドウに実行結果が表示されます。

一度構成を登録してしまえば、あとはタスクの実行から選ぶだけでそのタスクを実行してくれます。

gulpではgulp.task(タスク名, 実行処理)という形で、好きなようにタスクをいくつもgulpfile.js内に書くことができます。
実行名はdefaultとwatchが予約語になっているので、それ以外の名前なら好きなタスク名を付けることができます。

このタスクで使用するためのgulpプラグインというものがたくさんあるので、gulpでtypescriptをコンパイルするgulp-typescriptというのをインストールして、利用してみます。
gulpプラグインもnpmからインストールします。

gulpでtypescriptのコンパイル

cmd
npm install gulp-typescript --save-dev
gulpfile.js
const gulp = require('gulp');
const typescript = require('gulp-typescript')

gulp.task('default', function () {
    console.log('test');
})

gulp.task('compile', function () {
    gulp.src('*.ts')
    .pipe(typescript())
    .pipe(gulp.dest('./'))
})

タスクの構成からgulp: compileを選択して、タスクの実行からgulp: compileを実行すると、全てのtsファイルがコンパイルされて、jsファイルが作成されました。

これでよいかと思いきや、実はこの書き方ではtsconfig.jsを使用せずにコンパイルしている様なので、tsconfig.jsonを使用するようにしてみます。

gulpfile.js
const gulp = require('gulp');
const typescript = require('gulp-typescript')

gulp.task('default', function () {
    console.log('test');
})

gulp.task('compile', function () {
    const conf = typescript.createProject("./tsconfig.json");
    gulp.src('*.ts')
    .pipe(conf())
    .pipe(gulp.dest('./'))
})

tsconfigを使うか、gulpfileに直書きするかはお好みで。

gulpでbrowserify

結合にはbrowserifyを使用しました、gulp-browserifyというのもあるようなのですが、いろいろ調べるとgulp-browserifyを使用しないほうが良いということでした。
browserifyをgulpfile上で使用するのですが、browserifyが吐き出す形式とgulpが扱う形式に違いがあるため、vinyl-source-streamというものをかます必要があるようです。

cmd
nmp install vinyl-source-stream --save-dev

browserifyは前回インストールしているのでそのままgulpfiles.jsを書き換えます。

gulpfile.js
const gulp = require('gulp');
const typescript = require('gulp-typescript')
const browserify = require('browserify');
const source = require('vinyl-source-stream');


gulp.task('default', function () {
    console.log('test');
})

gulp.task('compile', function () {
    const conf = typescript.createProject("./tsconfig.json");
    gulp.src('*.ts')
        .pipe(conf())
        .pipe(gulp.dest('./'))
})

gulp.task('jsx', function () {
    return browserify('./secondProgram.js')
    .bundle()
    .pipe(source('bundle.jsx'))
    .pipe(gulp.dest('./jsx'));
})

これでタスクの構成にgulp: jsxが出てくるので、実行すると
jsxフォルダに1本化されたbundle.jsxが作られます。

自動化する

これでタスクをgulp: compile、gulp: jsxと続けて実行すると望んだ結果を得ることができました。gulpにはgulpのタスクを監視して連続実行させる機能が付いているので、それを使ってtypescriptを保存したらコンパイルと結合を自動実行するようにしてみましょう。

具体的にはwatchというタスクを設定します。

gulpfile.js
gulp.task('watch', function () {
    gulp.watch('./*.ts', ['compile', 'jsx']);
})

こんな感じにwatchしたいものとそれが変更された際に実行したいタスクを書くと、watchしてるファイルに変更があると、タスクを実行するのですが、どうも非同期で実行するようなので、このままでは、コンパイルを待たずに1本化してしまうことになるようです。

これを同期実行するように、run-sequenceというものを利用してみます。

cmd
nmp install run-sequence --save-dev

そして新たなsequenceというタスクを作成して、そちらで同期処理するようにしてみます。
また、タスクを同期処理するには、タスクをreturnしないといけないようなのでcompileタスク部分にretuenを付加しています。

gulpfile.js
const gulp = require('gulp');
const typescript = require('gulp-typescript')
const browserify = require('browserify');
const source = require('vinyl-source-stream');
const runSequence = require('run-sequence');


gulp.task('default', function () {
    console.log('test');
})

gulp.task('compile', function () {
    const conf = typescript.createProject("./tsconfig.json");
    return gulp.src('*.ts')
        .pipe(conf())
        .pipe(gulp.dest('./'))
})

gulp.task('jsx', function () {
    return browserify('./secondProgram.js')
        .bundle()
        .pipe(source('bundle.jsx'))
        .pipe(gulp.dest('./jsx'));
})

gulp.task('sequence', function (callback) {
    return runSequence(
        'compile',
        'jsx',
        callback
    );
});

gulp.task('watch', function () {
    gulp.watch('./*.ts', ['sequence'])
})

これでタスクの実行からgulp: watchを実行すると、コンソール部分が待機状態になり、typescriptに変更があると、コンパイルから1本化までしてくれるようになりました。

あとはこのjsxをestkで開きっぱなしにしていれば、自動で再読み込みしてくれるので、デバッグはestkで行うことができます。

これで面倒な作業が自動化されてラッキー。とはいえ、作成するスクリプトの規模が大きくなるとファイルも増えるので、1本化されるとデバッグがちょっとしんどそう。
gulpプラグインは自分で書くこともできるので、自分に合ったgulpプラグインを書いてみるのもいいかもしれませんし、ぶっちゃけjavascriptなのでtask内を好きなように書いていくというのもありだと思います。

使いまわす

さて、他のスクリプトを書こうと思って、またフォルダを作成して、npm install -yからか、と思いきや。実は一度設定してしまえばあとは結構ラクチン。実はこのpackage.json、tsconfig.json、そしてgulpfile.jsをとっておき、新しい空のプロジェクトフォルダにこのファイルをコピーしたのちに、コマンドラインでフォルダに移動した後にnpm installを実行すると、package.jsonに含まれる内容のモジュールを勝手にインストールしてくれるのです。継続してvscodeを使用するなら、.vscode/tasks.jsonもとっておくといいかもしれません。
ただし現状ではgulpfile.jsにはコンパイルするファイルなどの名前が、直接書いてあるので、都度書き換える必要があります。

まとめ

いきなりノンプログラマーがこの手法をとるには、難しすぎる気が。
ただし、一度動くように設定してしまえば使いまわせて楽なので、その辺は楽。
同期、非同期、コールバック、メソッドチェーンなど、javascriptでよく出てくるけどAEのスクリプトにはなかなか出てこない構文があるので、javascriptに詳しい人が近くにいるか、社内にプログラマーがいる等、聞ける人が身近にいると何か問題があったとき等によいと思います。

とにかく補完が便利。補完が利くだけでタイプミスが減るのでAEスクリプト初心者にはおすすめしたい。
しかし設定が難しいという諸刃の剣なので、参考になればと思います。

参考

Adobe ExtendScriptにES2015で現代秩序をもたらす