前回の記事【解決】モジュール化したExtendScriptを自動で1つにまとめたい!(1)にて、複数ファイルに分割したJavaScriptから1つのExtendScript(.jsx)ファイルを生成できるようになりました。もしまだ手順がよくわかっていない場合は、該当記事のどうやって生成するの?の部分を改めてご参照ください。
第2回のこの記事では、package.jsonやrollup.config.jsの設定内容を中心にお送りします。何が何を制御しているかを理解し、自分でも改造できるようにしましょう。
目次
package.jsonには何が書いてあるの?
sttk3/sample-build-extendscript-rollupをZIPとしてダウンロードするなどして作ったExtendScript開発専用フォルダを、プロジェクトフォルダと呼ぶとします。
package.jsonは、そのプロジェクトフォルダ全体の設定が書いてあります。例えばプロジェクト名やバージョン、それからインストールするライブラリ一覧などです。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
{ "name": "sample-build-extendscript-rollup", "version": "1.0.0", "private": true, "type": "module", "scripts": { "build": "rollup -c", "watch": "rollup -c -w" }, "devDependencies": { "@babel/cli": "^7.28.0", "@babel/core": "^7.28.0", "@babel/preset-env": "^7.28.0", "@rollup/plugin-babel": "^6.0.4", "rollup": "^4.45.1" } } |
nameがプロジェクト名、versionがプロジェクトのバージョンです。ユーザーのあなたが自由に変更できます。後述するrollup.config.jsにて、name/versionを生成されるスクリプトに反映させています。
privateは、プロジェクトをnpmに公開するかどうかを制御します。ExtendScriptの個人開発なら、プロジェクト自体を全世界に公開する理由はないでしょう。trueで固定と考えてください。
typeは、拡張子.jsのJavaScriptファイルをESModules/CommonJSのどちらとみなすかを制御します。現在はESModulesが主流なのでmoduleで固定と考えてください。
scriptsは、npm run [スクリプト] の形式で実行できるプロジェクトフォルダ専用コマンドを定義している部分です。ExtendScriptの書き出しのとき使うbuildとwatchコマンドはここで作っています。つまりrollup -c、rollup -c -wというコマンド実行にそれぞれ別名をつけているわけですね。
devDependenciesには、ExtendScriptの変換に必要なライブラリ一覧が書いてあります。インストールの際にはここの設定が参照され自動で進行します。複数ありますがすべてRollupとBabelです。
頭にdevのつくdevDependenciesは、成果物に一緒につける必要のないライブラリ一覧を書くのに使います。ライブラリを成果物に同梱したい場合は、頭にdevのつかないdependenciesのほうに書きます。
rollup.config.jsには何が書いてあるの?
rollup.config.jsは、RollupでJavaScriptの変換などの処理をどのようにするかの設定が書いてあります。BebalをRollupのプラグインとして使うこともこの中で指定しています。
細かい解説はソースコード中のコメントを見ていただくとして、ポイントをかいつまんで説明しましょう。
基本的には、inputで指定したJavaScriptファイルを始点として、そこからimportしている外部ファイルを収集してoutput > fileで指定したパスに変換したJavaScriptを生成する、という流れになっています。BabelでExtendScript用の古いJavaScriptバージョン(ES3)に変換することを指定しているのは、plugins > babel > presets > targets: {ie: '8'} の部分です。
そこの部分以外は、開発や生成されるスクリプトをより便利にするためのおまけくらいに考えて構いません。
例えば「import packageInfo from…」の部分は、package.jsonに書いたnameやversionをファイル名やコメントとして再利用するための操作です。ここはNode.jsのバージョンによって書きかたが異なるので、エラーが起こって生成できない場合はコメントの通り変更してください。必要ならpackage.jsonの記述の再利用を諦めてrollup.config.jsに直接書くこともできます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
// Babelのプラグインをインポートする import babel from '@rollup/plugin-babel' ; // package.jsonの情報をオブジェクトとして取得する。Node.js v20あたりを想定。 // もしここでエラーが出る場合は、その下のコードに変更 import packageInfo from './package.json' assert { type: 'json' } ; // v18-21 // import packageInfo from './package.json' with { type: 'json' } ; // v22- // 生成されたコードを後から置換する、したたか企画製処理集をインポートする。 // 開発作業やExtendScript実行結果を改善させるものだが、必須ではない import { tripleQuoteReplace, consoleReplace, avoidMemoryLeak, } from './rollup-plugin-sttk3-replace.js' ; // 設定本体 export default { // メイン(始点・エントリーポイント)のJavaScript input: 'src/index.js', // JavaScript書き出し設定 output: { // 書き出し先。package.jsonのnameを流用する設定にしてある file: `dist/${packageInfo.name}.jsx`, // 単体で実行可能なJavaScript (即時関数)に変換する設定にしてある。 // (function() {...})(); のような形式で出力される format: 'iife', // 本番用書き出しではセキュリティを考慮してfalseにするのが一般的 sourcemap: false, /* できるjsxファイルの先頭につけるコメント。 targetengineなどExtendScriptのPreprocessor directiveは ソースコードから消えるので、指定するならここで書く必要がある */ banner: `/** * @file ファイル説明 * @version ${packageInfo.version} * @author 作者名 * @copyright © 2026 example.com */ //@target 'illustrator' //@targetengine 'エンジン名' ` }, // プラグイン処理設定 plugins: [ // rollup-plugin-sttk3-replace.jsに由来する、生成されたコードへの後処理。 // このプラグイン処理を実行する tripleQuoteReplace(), consoleReplace(), avoidMemoryLeak(), // Babelの設定 babel({ babelHelpers: 'bundled', // 同梱するJavaScriptパターン extensions: ['.js'], include: ['src/**/*'], // 同梱しないJavaScriptパターン exclude: 'node_modules/**', // 変換プリセットをInternet Explorer 8にすることで、間接的にECMAScriptバージョン(ES3)を指定する presets: [ [ '@babel/preset-env', { targets: {ie: '8'}, modules: false, loose: true, }, ], ] }) ] } ; |
output > banner は、生成するExtendScript(.jsx)ファイルの先頭にコメントをつけるのに使っています。
//@targetengineなどのPreprocessor directiveは、ExtendScriptにとっては重要な意味があります。しかしRollupやBabelにとっては、単なるコメントであり削除対象です。そのため、つけるならbanner設定を利用するなどしてわざわざ後づけする必要があります。
見本では//@target 'illustrator'の記述でIllustrator用スクリプトにしてあるので、適宜変更/削除するなどしてご利用ください。
pluginsのtripleQuoteReplace・consoleReplace・avoidMemoryLeakは、したたか企画が書いたExtendScript用特別処理です。rollup-plugin-sttk3-replace.jsに処理内容が書いてあります。次の項目で説明します。
rollup-plugin-sttk3-replace.jsには何が書いてあるの?
Rollup/Babelで生成されるソースコードを丸ごとテキストとして置換することで、開発やスクリプトを便利にする処理が書いてあります。
tripleQuoteReplace
ExtendScriptでは'''および"""を使うことで、複数行のテキストを改行を活かしたまま書けます。ただRollup/Babelではそれを文法エラーとみなすので、この処理でバッククォート「`」に置換してbuildできるようにします。
つまり、ExtendScriptでそういった'''と改行つき文字列を含む既存の処理が書いてあり、それを流用したいときなどに便利です。
見ての通り単純に置換しているだけで、クォーテーションがペアになっているか、エスケープしてあるかなどは考慮していません。それで十分な状況でのみ有効にしてください。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
export function tripleQuoteReplace() { return { name: 'tripleQuoteReplace', transform(code) { // ''' """ → ` に置換(正規表現で終了側も対応などの丁寧なことはしない) const replacedCode = code.replace(/(?:'''|""")/g, '`') ; return { code: replacedCode, map: null, } ; } } ; } |
consoleReplace
console.logなどはExtendScriptには存在せず、実行時エラーで止まります。それを$.writelnに置換して実行できるようにします。
|
1 2 3 4 5 6 7 8 9 10 11 12 |
export function consoleReplace() { return { name: 'consoleReplace', renderChunk(code) { const replacedCode = code.replace(/console\.(?:error|worn|log)\(/g, '$.writeln(') ; return { code: replacedCode, map: null, } ; } } ; } |
avoidMemoryLeak
ExtendScriptでは、function文の中にさらにfunction定義があるとそのfunction(変数)がいつまでも消えずに残り続けて、動作に干渉したりMRAPエラーを招くことがありました。例えばこういう状態で不具合が起こります。
|
1 2 3 4 5 6 |
(function () { // ▼ function内にfunction function doSomething() { // ... } })(); |
Illustrator CC 2018からはかなり改善しましたが、念の為スクリプトの最後に手動でnullにしてGarbage Collectionを実行する処理を入れておくと、不具合を予防できます。avoidMemoryLeakはそのように加工する処理です。
|
1 2 3 4 5 6 7 8 |
(function () { // ▼ function内にfunction function doSomething() { // ... } })(); doSomething = null; $.gc(); |
これも丁寧に発生するすべてのケースをカバーしているわけではないので、状況に応じて変更・更新などしてご利用ください。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
export function avoidMemoryLeak() { return { name: 'avoidMemoryLeak', renderChunk(code) { const patternFunctonName = /^ {2,}function ([^\(]+)(?=\()/mg ; const matchList = Array.from(code.matchAll(patternFunctonName)) ; const functionNames = matchList.map((matchObj) => { return matchObj[1] ; }) ; const command = `${functionNames.join(' = ')} = null ; $.gc() ;` ; const replacedCode = `${code}\n${command}\n` ; return { code: replacedCode, map: null, } ; } } ; } |
さて、ここまで理解したらもう自分のExtendScript生成のための改造ができるはずです。これで大規模スクリプトでも頭すっきりで開発できますね!
これでまた少し仕事が速くなりました。今日もさっさと仕事を切り上げて好きなことをしましょう!
参考にした記事
- Node.js で ExtendScript する話(パート3) ES6 の Javascript 記述を使いたい | my notebook
- Babel + rollup.js で ES3環境向けトランスパイル #JavaScript | Qiita
- [ExtendScript] After Effects用のScriptをTypescriptで開発する | Zenn
- CEP上のExtendScriptをモダンな環境で開発する(Webpack + TypeScript + Babel) | Just Diary
作者に感謝を伝えたい!
Buy me a coffeeは、クレジットカード払いなどでクリエイターにコーヒーをおごれるサービスです。ツール・情報が役に立った! 感謝の気持ちを表現したい! というかた、おごっていただけましたら嬉しいです☕️



