クライアントサイドJavaScriptのライセンス管理

最近シリコンウエハーもらって嬉しかったago(@kyo_ago)です。

このエントリはGREE Advent Calendar 2013 11日目の記事です。

今回はクライアントサイドJavaScriptにおけるライセンス管理の問題を取り上げたいと思います。

ライセンス管理の問題点

「使用しているライブラリのライセンス管理をどうするか」はクライアントサイドJavaScriptにかぎらず発生する問題ですが、クライアントサイドJavaScriptには以下の様な特徴があるため問題が複雑になります。

  • コードが結合、圧縮される場合がある
    クライアントサイドJavaScriptでは読み込みの速度を上げるため、使用しているライブラリの結合、圧縮を行うことがあります。しかし、この時誤ってライセンス文が捨てられてしまうことがあります。
  • ソースが外部に公開される
    クライアントサイドJavaScriptではソースコードは基本的に公開された状態で配布されるため、比較的自由度の高いライセンスであっても権利上問題になることがあります。

ライセンス管理の問題点に対する対応

これらの問題に対しては一般的に以下の様な対応が取られます。

  1. 圧縮前にライセンス文を退避し、圧縮後に退避しておいたライセンス文を追加する
  2. 使用しているライブラリのライセンス文だけを別ファイルに書き出し、htmlやJavaScriptのソース内にコメントでライセンスが書かれたファイルへのURLを記載する
  3. 未圧縮版のソースへのURLをコメントで埋め込む
  4. SourceMapで未圧縮版を配布する

ただ、1, 2の方法は手動での対応が必要になるため自動化が難しいという問題があり、3, 4の方法は本来不要な未圧縮コードを公開する必要があるという問題があります。

圧縮ライブラリ側の対応

この点に関しては圧縮ライブラリ側での対応も行われています。

ここからは各圧縮ライブラリがライセンス文を残すために行っている対応を紹介します。

  • Closure Compiler
    ブロックコメントの先頭を/**で開始して、コメント内に@licenseを記述する

  • mishoo/UglifyJS2
    • commentsオプションを渡して、独立したブロックコメント内に@licenseを記述する(--commentsで残したいコメントの正規表現を指定することも可能)

この中でClosure Compilerは「一度圧縮するとライセンス表記が変わる」という問題があり、そのため2回圧縮するとライセンス表記が消えてしまう点に注意してください。

上記のライセンス表記をClosure Compilerで圧縮すると以下の形式で出力されます(このまま再度圧縮するとライセンス表記が消えてしまいます)

各ライブラリの記述方式

次は比較的メジャーなライブラリを元に、ライセンス文の記述方式を紹介します。

jQuery

まずは未圧縮版jQueryのライセンス表記です。

jQueryのライセンス表記は割と一般的なライセンス表記です。

ただ、この形式でもYUI Compressorでは正しくライセンス表記が残りますが、Closure Compiler、UglifyJS2で圧縮した場合にはライセンス表記が消えてしまいます(UglifyJS2は正規表現で対応可能)

ちなみに、圧縮版は以下の形式になっています。

AngularJS

次は未圧縮版AngularJSのライセンス表記です。

こちらはClosure Compiler、UglifyJS2では正しくライセンス表記が残りますが、YUI Compressorで圧縮した場合にはライセンス表記が消えてしまいます。

ちなみに、圧縮版のライセンス表記は以下のようになっているため、どの圧縮ライブラリで圧縮してもライセンス表記は消えてしまいます。

Underscore.js

Underscore.jsのライセンス表記はラインコメントの組み合わせで出来ています。

この形式はどの圧縮ライブラリでもサポートされておらず、基本的に手動で対応を行う必要があります。

これに関しては、本家Issueにも「/*!で始まる形式に変更してほしい」という要望が挙げられていますが、作者から却下されています。

Use bang comment to preserve license · Issue #1280 · jashkenas/underscore

Underscore.jsは圧縮版、未圧縮版でライセンス表記に違いはありませんでした。

Backbone.js

Backbone.jsのライセンス表記もUnderscore.jsと同じようにラインコメントの組み合わせで出来ています。

しかも最初のコメントの後に改行が入っているため、さらに圧縮ライブラリでの処理が難しくなっています。

Backbone.jsの圧縮版にはライセンス表記はなくなっていますが、SourceMapへの参照が入っています(ファイル末尾)

Zepto.js

Zepto.jsの場合、ライセンス表記は以下のように「ライセンス表記へのURLを記述する」形式になっています。

Underscore.jsは圧縮版、未圧縮版でライセンス表記に違いはありませんでした。

Esprima

Esprimaの場合、ライセンス文は記述されていますが、「License」と言った文字は記載されていないため、圧縮ライブラリでの処理は困難になります。

解決案

ここまで紹介してきたようにクライアントサイドJavaScriptではライセンス管理が非常に煩雑になる可能性があります。

この問題に関して、本来であればライブラリの作者、圧縮ライブラリ双方の対応で解決することがベストだとは思いますが、とりあえず何とかしたいのでいい感じに取得できるgrunt taskを作成しました。

grunt-license-saverの紹介

このgrunt taskはここまで紹介したすべての形式のライセンス文を解析でき、text, Markdown, JavaScript, JSONのいずれかの形式で書き出すことができます。

kyo-ago/grunt-license-saver

使い方

以下のコマンドでinstallします。

Gruntfile.jsに以下の内容を記述します。

以下のコマンドを実行します。

これで以下の様なJSを元にして

以下の様な内容のlicense.textが生成されます。

基本的にはMarkdownやtext形式で書き出して、圧縮後のJS内にコメントとして埋め込むことを推奨します。

ただ、その後複数回圧縮される可能性がある場合、JavaScript形式で書き出してコード内に埋めることを推奨します。(改行等がエスケープ文字列に置き換えられるためライセンス表記の見た目は変わってしまいますが、JavaScriptの変数へ保存する形式で書き出すため再圧縮されてもライセンス文が残ります)

明日は先日社内で開催されたJavaScript hackathonでHaskellの講師をしていただいた@beketaさんです。