Railsはデフォルトでライブラリライセンスを消してしまうという話

はじめに
こんにちは。ウェブアプリエンジニアの @r-kirishima です。
業務では主にRuby on Rails(以下RoR)で開発をしています。
RoRは細かい内部処理を意識せずとも簡単にアプリが作れてしまう素敵フレームワークです。
しかし、時には内部でどのような処理が走っているのかを理解しなければならないこともあります。
今回はコード内にライセンスを明示しておく必要のあるJavascriptのライブラリをRoRアプリで利用しようとした際に、
- ライセンス表示がRoRに消されてしまう可能性があること
- またその問題解決のためにgemの実装について調べたこと
についてお話しします。
ライセンス表示守れていますか?
jQueryを例に
ユーザの多いjQueryのライセンスを例にお話しします。
jQuery foundation - Licenseに以下のような文言があります。
You are free to use the Project in any other project (even commercial projects) as long as the copyright header is left intact.
ざっくり訳すと、以下のようになります。
「jQueryのプロジェクトは商用であれ、他のどんなプロジェクトで使ってくれて構わないよ、ただしコピーライト表示はそのまま残しておいてくれよ!」
ここでいうコピーライト表示とはjQuery 3.5.1の冒頭にある下記のようなコメントのことです。
/\*!
\* jQuery JavaScript Library v3.5.1
\* https://jquery.com/
\*
\* Includes Sizzle.js
\* https://sizzlejs.com/
\*
\* Copyright JS Foundation and other contributors
\* Released under the MIT license
\* https://jquery.org/license
\*
\* Date: 2020-05-04T22:49Z
\*/
ライセンスをあまり気にせずにRoR x jQueryの組み合わせを使っている方は多いと思います。
そういう方は本番環境( RAILS_ENV=production )のアプリのアセットをブラウザから確認してみてください。
もしかしたらライセンス表示が消えてしまっている可能性が高いですよ。
そしてそれは無自覚でもライセンス違反です......
ライセンスはなぜ消えたのか
どうしてライセンス表示が消えてしまったのか?
コメント、長い変数名、インデント、改行などは人間の可読性を上げるためのものです。
一方で実行する機械にとっては基本的に不要なものです。
RoRにおいてはAsset Pipelineが機械にとっての「ゴミ」を取り除いてくれるのですが、
その際に人間にとっては必要なライセンスもまた「ゴミ」として削除されてしまうのです。
Asset PipelineとUglifier
上で少しでてきたAsset Pipelineについて軽く説明します。
Asset PipelineとはJavascript、CSS、画像などのアセットを入力すると、設定に従った加工してくれる仕組みのことです。
詳細はRailsガイドを参照してください。
本記事ではJavascriptから機械にとって不要なものを取り除いてくれるもの、ぐらいに考えてもらえば結構です。
Rails5においてはAsset Pipelineにsprockets-railsというgemを用いています。
また、特にSprocketsはJavascriptの圧縮作業(Compress)にUglifierという別のgemを用いています。
Uglifierのデフォルト設定とSprocketsのデフォルト設定
上述のようにSprocketsはUglifierを利用してJavascriptの圧縮を行っています。
このUglifierのコメントに関するデフォルトの設定はlautis / uglifierを参照すると、
下記のように Copyright というワードの入っているコメントブロックを保持する設定になっています。
DEFAULTS = {
# 中略
:output => {
# 中略
:comments => :copyright, # Preserve comments (:all, :jsdoc, :copyright, :none)
# 中略
def comment\_options
case comment\_setting
when :all, true
true
when :jsdoc
"jsdoc"
when :copyright
encode\_regexp(/(^!)|Copyright/i)
when Regexp
encode\_regexp(comment\_setting)
else
false
end
end
# 中略
一方でSprocketsでは下記のようにコメントを全て削除する設定でinitializeしてしまい、こちらの設定が実際に用いられます。
# 中略
def initialize(options = {})
# Feature detect Uglifier 2.0 option support
if Autoload::Uglifier::DEFAULTS\[:copyright\]
# Uglifier < 2.x
options\[:copyright\] ||= false
else
# Uglifier >= 2.x
options\[:comments\] ||= :none
end
# 中略
参考:ぼっち勉強会 - rails + sprockets + uglifierでCopyrightを残したままcompressする
ライセンスを消させない
参考として挙げたブログ内ではRailsの設定ファイルを下記のように書き換えることで解消できる、とされています。
\- config.assets.js\_compressor = :uglifier
+ config.assets.js\_compressor = Uglifier.new(:comments => :copyright)
# より今時の書き方をすると comments: :copyright
# さらに厳密な書き方をすると output: {comments: :copyright}
しかし、commentsオプションをcopyrightに設定して保護されるのは Copyright と入っているコメントのみです。
上でふれているjQuery-3.5.1のライセンスなどには Copyright と入っていないため保護されません。
Copyrightと入っていなくてもライセンスを消させない
Uglifierのコードを見ると、実はSymbolを用いた指定以外にも正規表現を用いた指定が可能であることがわかります。
以下に抜粋して再掲します。
def comment\_options
case comment\_setting
# 中略
when Regexp
encode\_regexp(comment\_setting)
# 中略
そこで、今回は以下のように jquery.org/license Available for use under the MIT License Licensed MIT
のワードが入っているコメントを残せるようにしてみました!
\- config.assets.js\_compressor = :uglifier
+ config.assets.js\_compressor = Uglifier.new(output: {comments: /jquery.org\\/license|Available for use under the MIT License|Licensed MIT/})
# Rubyにおいてスラッシュ囲みは正規表現リテラルを表します。
増えるたびに正規表現を書くのは大変なので、反応するワードを配列で切り出してみました。
\- config.assets.js\_compressor = :uglifier
+ trigger\_comments = \["jquery.org/license", "Available for use under the MIT License", "Licensed MIT"\]
+ config.assets.js\_compressor = Uglifier.new(output: {comments: /#{trigger\_comments.join('|')}/})
いい感じですね!
おわりに
RoR x jQueryという組み合わせで利用している方も非常に多いと思いますが、
デフォルトでライセンス表示義務違反を犯してしまう罠があるというのはとても驚きです。
ただ闇雲にレールに乗るだけではなく、正しくRoRを理解して使っていきたいですね!
Discussion