Greasemonkeyやブラウザの拡張を書く際にも、既存のnpmモジュールを使った方が簡単なことが多いです。 しかし、Greasemonkeyはデフォルトではnpmモジュールを読み込む方法が用意されていません。

そのため、webpackParcelなどのbundlerを使えば、Greasemonkeyスクリプトでもnpmモジュールが利用できます。 (bundleしたものがスクリプトの配布サイトのレビューを通らない場合もありますが、今回はGitHubで配布するので気にしないです)

codemirror-anywhereではwebpackを使ったのですが、webpackは設定をしないといけないのがGreasemonkeyの手軽さを壊してしまうため、Parcelを使ってできないかと考えました。

Parcelは設定が不要ですが、Greasemonkey特有のヘッダーコメントを扱う方法がなかったため、parcel-plugin-greasemonkeyというParcel pluginを書きました。

メモ: 一般的に次のようなコメントがファイルの先頭にあると、minifyによって消されたり、別の場所に移動されてしまったりする。(/*! ライセンスコメントだとヘッダとして認識されない可能性がある)

// ==UserScript==
// @name        codemirror-anywhere
// @namespace   http://efcl.info/
// @description codemirror-anywhere
// @include     http://*
// @include     https://*
// @version     ${version}
// @grant       none
// ==/UserScript==

parcel-plugin-greasemonkey

parcel-plugin-greasemonkeyはものすごく単純で、bundleしたファイルの先頭にGreasemonkeyのヘッダコメントを加えるプラグインです。

parcelとともにインストールして、ヘッダファイルの準備をするだけで後の設定は不要です。

使い方

次のようなファイル構造を例にします。

├── greasemonkey.header
├── yourscript.user.js
└── package.json

まず最初にgreasemonkey.headerという名前のファイルをプロジェクトルートに作成します。 greasemonkey.headerにはGreasemonkeyの先頭に入れたいメタデータを書きます。 (今思いましたが、このファイルをjsとして読み込めるようにした方が柔軟性が高そうな気がしました)

// ==UserScript==
// @name user-script
// @namespace info.efcl
// @match https://*
// @grant none
// ==/UserScript==

次に、parcelとともにparcel-plugin-greasemonkeyをインストールします。

npm install parcel-bundler parcel-plugin-greasemonkey --save-dev

後はparcelでビルドするだけです。 このときに、parcelのエントリポイントを .user.js のファイルにしてください。 .user.jsのファイルのみにヘッダコメントを入れるプラグインなので、.jsだと何も行いません。

また、Greasemonkeyだと---no-source-maps --no-content-hashをつけてビルドすれば、SourceMapなし かつ ファイル名のハッシュ値を除外できます。

parcel build ---no-source-maps --no-content-hash ./yourscript.user.js --out-dir ./dist

これで ./dist/yourscript.user.jsファイルが生成されます。 後はインストールするだけです。

メモ: parcel watchを使えばファイル監視してビルドも可能です。

おわりに

Parcelは設定なしで大体普通に動いてくれるので、プロトタイピング的な用途だったり、とにかくザクッと作りたいときに便利です。 webpackだと、Angular CLICreate React appsVue CLI 3などフレームワークなどに合わせた形になっていることが多いです。 わざわざこのようなものをwebpackで作るのはコスト的に大変なので、Parcelプラグインでザクッとできたのは良かったです。

また、ParcelのPlugins APIはほとんどイベントがないため、できることはあまり多くないです。

このプラグインでも、ファイルを書き換えるという結構むりやりな実装をしているので、そのような細かい柔軟性が欲しい人はAssetとして実装するか、webpackを使うなどをした方がよさそうです。