VSCodeで複数のClusterScriptをまとめて一つにしたり、圧縮したりできるようにする(設定編)
「VSCodeで捗らせる!幸せなCluster Script開発」連載記事一覧
-
VSCode、Node.js、Gitをインストールして、各種用語をざっくり確認する
(共通環境構築編)VSCode、Node.js、Gitをインストールする。 -
VSCodeのワークスペースを作って、ClusterScript向けの機能を入れる
(個別環境構築編)VSCodeのワークスペースを作成する。必要なパッケージをnpmでインストールする。 -
VSCodeで複数のClusterScriptを一つにまとめたり、圧縮したりする
(設定編)VSCodeのtasks.json、launch.jsonを作成する。webpackのwebpack.config.jsを作成する。 -
ClusterScriptのファイルを分割したり、$を含めてテストする
(コーディング実践編)型定義ファイルについて。ES Modulesでモジュールを書く。Mocha、Chai、Sinon.JSでテストを書く。$のテストダブルを作る。 - スクリプト共有編 予定
こんにちは!かおもです!
前回は必要な機能のインストールを行い、個別の環境を準備しました。
今回はインストールした機能を、VSCodeから使用できるようにする設定を行い、実際に使ってみます。
以下のような操作がVSCodeで行えるようになり、実際に開発する環境が整います。
- スクリプトファイルを圧縮する。
- 複数に分けたスクリプトファイルを一つにまとめる。
- スクリプトをテストする。
0:執筆時の環境
本記事の内容は、バージョンが変わると動かないという事がありえるので、現環境を記載しておきます。
- VSCode 1.73.1
- Node.js v18.12.1
"@clustervr/cluster-script-types": "^1.0.1",
"chai": "^4.3.7",
"mocha": "^10.1.0",
"sinon": "^14.0.2",
"terser": "^5.15.1",
"terser-webpack-plugin": "^5.3.6",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.0",
"webpack-preprocessor-loader": "^1.2.0"
1:タスクの設定をする
VSCodeのタスクでは何かのプログラムやスクリプトを実行する事ができます。
つまり、前記事でインストールしたwebpack(複数ファイルを1つにまとめる)やTerser(ファイルを圧縮する)などを、タスクで実行することができるようになります。
ここでは、以下の3種類のタスクを設定します。
- テスト用のjsファイルを実行して、テストを行うタスク。
- 特定のファイルを圧縮するだけのタスク。
- 複数のjsファイルを一つにまとめるタスク。
画面左側にエクスプローラーを表示(ctrl+shift+E
)させてください。
work
フォルダ(前記事で言うところの作業フォルダ)以下に.vscode
という名前のフォルダを作成してください。
フォルダ名の先頭のドット.
も必要です。
このフォルダは、VSCodeの各種設定ファイルを保管するための特殊なフォルダになります。
作成した.vscode
フォルダ以下にtasks.json
というファイルを作成し、そのファイルを開いてください。
このような状態になっていればOKです。
このファイルにVSCodeのタスクを設定します。
以下の内容をコピペしてください。
🔴設定するタスクの内容はこちら
長いので、丸ごとコピペして貼り付けてください。
一行目の{
と最終行の}
は漏れやすいので気を付けてください。
黒枠右上の四角が重なっているアイコンを押すとコピーできます。
{
"version": "2.0.0",
"tasks": [
{
"label": "テスト",
"group": {
"kind": "test",
"isDefault": true
},
"type": "shell",
"command": "node_modules/.bin/mocha",
"args": [
"${file}"
],
"problemMatcher": [],
"options": {
"env": {}
}
},
{
"label": "ビルドのみ",
"group": {
"kind": "build",
"isDefault": false
},
"type": "shell",
"command": "node_modules/.bin/webpack",
"problemMatcher": [],
"options": {
"env": {
"MINIMIZE" : "false",
"IN_FILE": "${file}",
"OUT_DIR": "${workspaceFolder:dist}",
"OUT_FILE": "${fileBasenameNoExtension}.js",
"LOGGING": "true",
}
}
},
{
"label": "ビルド+圧縮+log",
"group": {
"kind": "build",
"isDefault": false
},
"type": "shell",
"command": "node_modules/.bin/webpack",
"problemMatcher": [],
"options": {
"env": {
"MINIMIZE" : "true",
"IN_FILE": "${file}",
"OUT_DIR": "${workspaceFolder:dist}",
"OUT_FILE": "${fileBasenameNoExtension}.compress.js",
"LOGGING": "true",
}
}
},
{
"label": "ビルド+圧縮+log無し",
"group": {
"kind": "build",
"isDefault": true
},
"type": "shell",
"command": "node_modules/.bin/webpack",
"problemMatcher": [],
"options": {
"env": {
"MINIMIZE" : "true",
"IN_FILE": "${file}",
"OUT_DIR": "${workspaceFolder:dist}",
"OUT_FILE": "${fileBasenameNoExtension}.compress.js",
"LOGGING": "false",
}
}
},
{
"label": "圧縮(強)",
"group": {
"kind": "build",
"isDefault": false
},
"type": "shell",
"command": "node_modules/.bin/terser",
"args": [
"${file}",
"--compress",
"ecma=2015",
"--mangle",
"--toplevel",
"--output",
"${workspaceFolder:dist}\\${fileBasenameNoExtension}.compress.js"
],
"problemMatcher": [],
"options": {
"env": {}
}
},
{
"label": "圧縮(弱)",
"group": {
"kind": "build",
"isDefault": false
},
"type": "shell",
"command": "node_modules/.bin/terser",
"args": [
"${file}",
"--compress",
"ecma=2015",
"--mangle",
"--output",
"${workspaceFolder:dist}\\${fileBasenameNoExtension}.compress.js"
],
"problemMatcher": [],
"options": {
"env": {}
}
},
]
}
1.1:タスクの詳細を確認する
かなり長いファイルですが、細かく分けて把握していきましょう。
冒頭付近のtasks
以下のブロックが、それぞれのタスクになります。
例えば、一番先頭のタスクは以下のようになります。
このようなタスクが全部で6個設定されています。
{
"label": "テスト",
"group": {
"kind": "test",
"isDefault": true
},
"type": "shell",
"command": "node_modules/.bin/mocha",
"args": [
"${file}"
],
"problemMatcher": [],
"options": {
"env": {}
}
},
各タスクの中で、注目しておきたい項目は以下の4つです。
- label
- command
- args
- option以下のenv
そして各項目は、
labelという名前のタスクは、
commandのプログラムを実行し、
argsやenvでプログラムの処理に必要な情報を渡す、
という関係にあります。
これをふまえて、各タスクの内容を見ていきましょう。
1.2:label:テスト
名前の通り、テストを行うためのタスクです。
node_modules/.bin/mocha
が実行され、${file}
が情報として渡されます。
Mochaは以前の記事で紹介した通り、テストを行う環境を提供する機能です。
具体的には、Mochaの書式に従うことで、JavaScriptでテストの項目を書くことができるようになります。
そしてそのファイルをMochaに渡すことで、書かれたテストの項目が実行され、テストが達成されます。
ここでいうテストとは、関数やクラスが想定している動きになっているかを確認する、というようなイメージで大丈夫です。
${file}
はVSCodeが今開いているファイル名(フルパス)に置き換えられて渡されます。
まとめると、このタスクは、
今開いているテスト項目のテストを実行する、
というタスクになります。
1.3:label:圧縮(強)、圧縮(弱)
このタスクは、圧縮を行うだけのタスクになります。
node_modules/.bin/terser
が実行され、以下の情報が渡されます。
"${file}",
"--compress",
"ecma=2015",
"--mangle",
"--toplevel",
"--output",
"${workspaceFolder:dist}\\${fileBasenameNoExtension}.compress.js"
Terserは以前の記事で紹介した通り、jsファイルを圧縮する機能です。
--output
の後にファイル名を指定することで、圧縮後のファイルの出力先を指定できます。
その他の--compress
等のオプションは、圧縮の方法などを指定しています。
詳しくはこちらなどを参照してください。
${file}
は先の通り、今開いているファイルになります。
${workspaceFolder:dist}
はdist
フォルダ(前記事で言うところのAssets内フォルダ)のフルパスに置き換えられます。
${fileBasenameNoExtension}
は今開いているファイルの、拡張子無しの名前になります(パスも付きません)。
分かりづらいので例を上げると、
-
${file}
がC:\work\source.js
、 -
dist
フォルダがZ:\Unity\Assets\JavaScripts
となっている場合、
上記の${workspaceFolder:dist}\\${fileBasenameNoExtension}.compress.js
は
Z:\Unity\Assets\JavaScripts\source.compress.js
となります。
まとめると、このタスクは、
今開いているファイルを圧縮し、distフォルダに(圧縮されるならcompressを付けて)出力する、
というタスクになります。
1.4:label:ビルドのみ、ビルド+圧縮+log、ビルド+圧縮+log無し
このタスクは、ビルド(ここでは、複数ファイルをまとめて1ファイルにすること)を行うタスクになります。
node_modules/.bin/webpack
が実行され、以下の情報が渡されます。
"MINIMIZE" : "true",
"IN_FILE": "${file}",
"OUT_DIR": "${workspaceFolder:dist}",
"OUT_FILE": "${fileBasenameNoExtension}.compress.js",
"LOGGING": "false",
webpackはは以前の記事で紹介した通り、複数のJavaScriptのファイルをまとめる機能です。
webpackは設定の説明が長くなるので結論から言いますと、このタスクは、
今開いているファイルを元にビルドし、distフォルダに(圧縮されるならcompressを付けて)出力する、
というタスクになります。
例えば、itemGimmick.js
というファイルが、common.js
という共通処理のファイルを参照しているとします。
この時に、itemGimmick.js
を開きながらビルドのタスクを実行すると、distフォルダにcommon.js
の内容を結合したitemGimmick.compress.js
というファイルが出力されます。
1.5:webpackの設定について
webpackは設定が特殊で、渡された情報をそのまま使用していません。
渡された情報をJavaScriptで加工し設定しています。
ここでは、その設定用のJavaScriptファイルを作成します。
work
直下にwebpack.config.js
というファイルを作成し、以下の内容をコピペしてください。
🔴コピペ内容はこちら
最終行の};
はコピペ漏れしやすいので気を付けてください。
const TerserPlugin = require("terser-webpack-plugin");
module.exports = env => {
return {
entry: process.env.IN_FILE,
output: {
path: process.env.OUT_DIR,
filename: process.env.OUT_FILE,
},
mode: 'production',
optimization: {
minimize: process.env.MINIMIZE == "true",
minimizer: [new TerserPlugin({
terserOptions: {
compress: true,
ecma: 2015,
mangle: true,
toplevel: true,
}
})],
},
module: {
rules: [
{
test: /\.[mc]?js$/,
loader: 'webpack-preprocessor-loader',
exclude: /node_modules/,
options: {
directives: {
LOGGING: process.env.LOGGING == "true",
}
}
},
],
},
experiments: {
//全体を囲う即時実行関数式が消える。
outputModule: true
}
}
};
このwebpack.config.js
はwebpack実行時に内部で実行されます。
webpack.config.js
に書かれている関数がオブジェクトを出力するので、それを設定として扱います。
webpack.config.js
内にprocess.env.XXXXXX
と記述されている個所があると思いますが、その個所にタスクから渡される情報が入ります。
順に内容を確認していきましょう。
entry: process.env.IN_FILE,
ファイルの入力に関する設定です。
webpackはentryで指定されたファイルを起点に、他のファイルをまとめます。
output: {
path: process.env.OUT_DIR,
filename: process.env.OUT_FILE,
},
まとめられたファイルの出力に関する設定です。
pathのフォルダに、filenameの名前で出力されます。
mode: 'production',
ファイルのまとめ方に関する設定です。
production
の他にdevelopment
というモードがあります。
development
モードはデバッグに有用な情報を残すようにしてまとめるモードです。
しかしClusterでの開発にはあまり使われないと思うので、production
固定でよいでしょう。
optimization: {
minimize: process.env.MINIMIZE == "true",
minimizer: [new TerserPlugin({
terserOptions: {
compress: true,
ecma: 2015,
mangle: true,
toplevel: true,
}
})],
},
ファイルをまとめる時に行われる最適化に関する設定です。
MINIMIZE
にtrue
を指定することで、Terserを使用した圧縮が行われるような設定になります。
Terserのオプションは圧縮のタスクの内容と同じです。
{
test: /\.[mc]?js$/,
loader: 'webpack-preprocessor-loader',
exclude: /node_modules/,
options: {
directives: {
LOGGING: process.env.LOGGING == "true",
}
}
},
読み込まれるファイルをどう扱うかという設定です。
test
にマッチしたファイルはloader
で読み込まれ、まとめられるという流れになります。
ここでは、.js、.mjs、.cjsのファイルを読み込むときはwebpack-preprocessor-loader
を使うという設定になっています。
webpack-preprocessor-loader
は、プリプロセッサという処理を行う機能です。
ここでは、そのプリプロセッサ用の値LOGGING
を設定しています。
プリプロセッサについてはこの記事内で後述します。
node_modules以下は変に加工しない方がよいので、exclude
で除外しています。
experiments: {
//全体を囲う即時実行関数式が消える。
outputModule: true
}
名前の通り、実験的な機能を設定しています。
ここでは、webpackがファイルをまとめる時に、全体を即時実行関数式(IIFE)というもので囲みますが、それを外す設定をしています。
Clusterでは使用できるメモリに制限がありそうなので、その対策として有効かもと考えて設定しています。
2:実行とデバッグの設定をする
長くなりましたが、次に実行とデバッグの設定を行います。
実行とデバッグの機能は、開発したJavaScriptのコードをVSCode上(Node.js上)で実行したりデバッグしたりする機能です。
Cluster向けのJavaScriptはNode.js上で実行してもあまり意味がなさそうですが、デバッグの方はテストと合わせると効果を発揮しそうなので、設定を行います。
.vscode
フォルダ以下に、launch.json
というファイルを作り、以下の内容をコピペしてください。
一行目の{
と最終行の}
は漏れやすいので気を付けてください。
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "テストデバッグ",
"runtimeExecutable": "${workspaceFolder:work}/node_modules/.bin/mocha",
"program": "${file}"
}
]
}
このファイルも基本的な考え方はtasks.json
と同じです。
work
フォルダにインストールしてあるMochaに、現在開いているファイルを指定して実行する、という内容になります。
3:設定した機能の操作方法を確認する
最後に、ここまで設定してきたタスクやデバッグの機能の操作方法を確認していきます。
3.1:タスクの実行方法を確認する
画面上側メニューからターミナル
>タスクの実行
とクリックしてください。
ターミナル
の表示がない場合は、表示幅が足りずに・・・
の中に入っているかもしれません。
タスクの実行
をクリックすると以下のような画面になり、これまで登録したタスクが表示されます。
この状態から各タスクを選択することで、そのタスクを実行できます(今は実行しないでよいです)。
esc
キーなどで、タスクの一覧の画面は閉じることができます。
3.2:デバッグの開始方法を確認する
画面左側の虫と三角のアイコンをクリックするかctrl+shift+D
を押してください。
すると以下のような画面になり、左上に登録したデバッグの機能が表示されます。
ここで、画面左上のテストデバッグ(work)
の左側にある右向き三角を押すと、デバッグが開始されます(今は開始しないでよいです)。
ctrl+shift+E
などで、画面左側を元のエクスプローラーの画面に戻せますので、戻しておいてください。
3.3:確認用ソースコードを準備する
以下のファイルをwork
フォルダの直下に作成してください。
本来であればフォルダを分けるなどして配置した方がよいですが、確認用なのでそのまま作成します。
ここに登場するファイルの細かい内容については、次の記事で触れていく予定です。
🔴各種確認用ソースコード
ファイル名:scriptableItem01.mjs
const add = (a, b) => {
const result = a + b;
return result;
};
const log = (message) => {
$.log(message);
};
const v = add(1, 2);
log(v);
ファイル名:common.mjs
export const add = (a, b) => {
return a + b;
};
export const log = (message) => {
// #!LOGGING
$.log(message);
};
ファイル名:scriptableItem02.mjs
import { add, log } from './common.mjs';
const v = add(1, 2);
log(v);
ファイル名:common.test.mjs
import { expect } from 'chai';
import { add } from './common.mjs';
describe("add", () => {
it("1と2が足されて3が返される", () => {
const result = add(1, 2);
expect(result).equal(3);
});
});
画面左側のエクスプローラーの構成が、同じようになっていることを確認してください。
3.4:「圧縮(弱)」「圧縮(強)」の操作を確認する
それでは順にタスクを確認していきます。
scriptableItem01.mjs
を開き、タスクの圧縮(弱)
を実行してください。
画面上側メニューからターミナル
>タスクの実行
でタスクは実行できます。
するとこのようにターミナルが自動で表示され、ターミナルはタスクで再利用されます、閉じるには任意のキーを押してください。
と表示し、タスクが終了します。
ターミナルは右上部分のXボタンで消してもよいですし、ターミナルをクリックして何かキーを押して消してもよいです。そのまま残しておいてもよいです。
タスクが終了すると、distフォルダにscriptableItem01.compress.js
というファイルができています。
dist以下にファイルが表示されていない場合は、distをクリックしますと表示が開かれてファイルが見えます。
ファイルの内容は以下のようになっていると思います。
const add=(d,o)=>d+o,log=d=>{$.log(d)},v=add(1,2);log(v);
元のファイルと見比べますと、変数名や空白などが省略されかなり圧縮されているのが分かると思います(160byteが56byteになっています)。
タスクの圧縮(強)
も確認してみましょう。
ファイルの内容は以下のようになっていると思います。
const o=1+2;var a;a=o,$.log(a);
add関数とlog関数が展開されて削除され、さらなる圧縮がなされました(160byteが31byteになりました)。
3.5:「ビルドのみ」の操作を確認する
続いて、複数のファイルを一つにまとめるビルド系のタスクを確認します。
今度はscriptableItem02.mjs
を開いてください。
02のファイルは、01の方にあったadd関数やlog関数がなくなっています。
代わりにcommon.mjs
に書かれているadd関数やlog関数を参照しています。
(この参照方法などについては、次回の記事にて触れる予定ですが、詳細を知りたい方はこちらなどをご覧ください)
それではscriptableItem02.mjs
を開いた状態で、タスクのビルドのみ
を実行してください。
distフォルダに以下のようなscriptableItem02.js
ができていると思います。
var __webpack_exports__ = {};
;// CONCATENATED MODULE: ./common.mjs
const add = (a, b) => {
return a + b;
};
const log = (message) => {
$.log(message);
};
;// CONCATENATED MODULE: ./scriptableItem02.mjs
const v = add(1, 2);
log(v);
元の02のファイルにはなかったadd関数やlog関数が含まれています。
webpackにより、common.mjs
の内容を参照して一つのファイルにまとめられたことが分かると思います。
3.6:「ビルド+圧縮+log無し」の操作を確認する
(ビルド+圧縮+log
の結果は、01のファイルを圧縮(強)
した時と同じになるので割愛します。)
scriptableItem02.mjs
を開き、タスクのビルド+圧縮+log無し
を実行してください。
distフォルダにscriptableItem02.compress.js
ができていると思いますが、中身がないファイルになっていると思います。
これは、圧縮の過程で、なにも実行する必要がないと判断され、このようになりました。
この結果を説明するために、webpackの設定の時に出てきたプリプロセッサについて触れます。
3.7:プリプロセッサの機能について
プリプロセッサは、ビルドなどを行う前に、ソースコードに対して処理を行います。
今回のケースでは、webpackでファイルをまとめる前に、処理を行っています。
webpackの設定の時に作ったwebpack.config.js
には、以下の設定が書かれています。
{
test: /\.[mc]?js$/,
loader: 'webpack-preprocessor-loader',
options: {
directives: {
LOGGING: process.env.LOGGING == "true",
}
}
}
ここに書かれている設定が、プリプロセッサの設定です。
directives
の下にあるLOGGING
に注目してください。
ビルド+圧縮+log無し
のタスクを実行するときはこのLOGGING
がfalse
になります。
これをふまえて、common.mjs
のファイルを確認してください。
export const add = (a, b) => {
return a + b;
};
export const log = (message) => {
// #!LOGGING
$.log(message);
};
5行目に// #!LOGGING
という記述があります。
プリプロセッサは、このような// #!
の行を見つけると、おおよそ以下のような処理を行います。
- LOGGINGの値を確認する>LOGGINGはfalse
- 値がfalseの場合は(1つ下の)行を削除する。
- 値がtrueの場合はなにもしない。
今回は、LOGGING
がfalse
なので、$.log(message);
の行が削除され、webpackに渡されます。
つまり、以下のようなコードが渡されます。
export const add = (a, b) => {
return a + b;
};
export const log = (message) => {
};
さて、ここから圧縮の処理をイメージしてみます。
このlog関数を見ると、何も実行していないことが分かります。
すると、圧縮時にlog関数の定義やlog関数を呼び出しているところが削除されます。
そこでscriptableItem02.mjs
の記述を確認してみると、
add関数の結果はlog関数のみに渡されています。
const v = add(1, 2);
log(v);
すると、log関数が削除されたのであれば、add関数の結果も不要となり、最終的にはadd関数の処理も不要となります。
そして、add関数はここだけ使われているので、add関数の定義も不要となり削除され、圧縮の結果何も残らなくなるのです。
プリプロセッサの詳しい記述方法などはこちらを参照してください。
3.8:「テスト」の操作を確認する
最後のタスクであるテストの操作を確認します。
common.test.mjs
を開いてください。
common.test.mjs
の内容を簡単に説明すると、
describe
はテスト項目のグループで、
it
はテストの項目です。
このit
内でadd関数が呼び出され、expect(result).equals(3);
でadd関数の結果が想定された値かを確認しています。
それではcommon.test.mjs
を開いたまま、タスクのテスト
を実行してください。
以下のように、テストの結果がターミナルに表示されます。
上記のテスト結果の画面は、
add関数についてのテスト項目のグループのうち、
1と2が足されて3が返される
というテスト項目については
テストを通過しました(グリーン表示)
という内容の画面になります。
ClusterのJavaSciprtでは$
が存在してるので、このようなテストを行うには工夫(次の記事で触れる予定です)をするか、場合によってはテストが行えないことがあります(こちらの方が多いと思いますが…)。
とはいえ、特定の処理などが正しく動いていることは、結構な安心感につながると思っています。
ですので積極的にテストが行える環境ができるといいなと思っています。
4:「テストデバッグ」の操作を確認する
最後にデバッグの操作を確認します。
common.test.mjs
を開いてから、ctrl+shift+D
などで画面左側に実行とデバッグ
を表示させます。
このままテストデバッグ(work)
の左側の>マークをクリックしてください。
すると、画面下側のタスクバーが一瞬オレンジになり、青色に戻ります。
この状態でworkのターミナルを開き、デバッグコンソールのタブを見ると、先ほどのテスト結果と同じ出力が見られます。
これだけでは、タスクのテストと差がありません。
ですので、デバッグならではの機能を確認してみます。
common.test.mjs
のコードが表示されている左側に行番号が表示されていると思います。
この行番号にカーソルを合わせると、行番号の左に赤丸が表示されます。
そこで、9行目の行番号にカーソルを合わせ、表示された赤丸をクリックしてください。
すると、カーソルを離しても、以下の画像のように赤丸の表示が残ります。
この状態で再び、画面左上のテストデバッグ(work)
の左側の>マークをクリックしてください。
すると、今度は以下のような画面で静止します。
これは、プログラムの処理が、9行目を実行する直前で止まっている事を示しています。
先ほど付けた赤丸は、ブレークポイントといい、デバッグを実行すると、そのブレークポイントの直前でプログラムの処理が停止します。
これのなにが便利かというと、例えば、8行目のresult
にカーソルを合わせてもらうと、3
と表示されると思います。
つまり、プログラムの途中の状態を確認できるようになります。
普段であれば、$.log
などで途中の状態を出力して確認しているかと思います。
しかし、デバッグで動かすことができるような書き方になっていれば、$.logに頼らずとも途中の状態を確認ができるようになります。
デバッグモードでの操作についてはこちらなどを参照してみてください。
(若干古めの記事ですが、おおよそ同じような動きをしているようなので大丈夫かと思います)
それでは、ブレークポイントで停止しているプログラムを、shift+F5
で終了させてください。
終了させると元の画面に戻ります。
ブレークポイントも、再度赤丸をクリックすると元に戻ります。
5:次回、コーディング実践編
次回は、実際にファイルを複数に分割したりする時に必要な書き方や、デバッグ用に必要な工夫などをまとめていきます。
以上です!よいVSCodeライフを!!
Discussion