webpackでhighlight.jsをビルドする際にハマった

# 概要
`highlight.js`が`webpack`とあまり相性が良くない。
[本系](https://highlightjs.org/download/)からダウンロードしてきたのをそのままwebpackでビルドするとエラーになる。
単純に`script`タグでインクルードすれば使えるけど、
せっかくなので`webpack`の知識も深めるという意味でなんとか対応してみた話。

# 現象

フォルダ構成

![folder](http://s5.postimg.org/q6zsy857b/0folder.png)

`html`はこんな感じ

```html
<!DOCTYPE html>
<html lang="jp">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>testing highlight with webpack</title>
    <link rel="stylesheet" href="./github.css">
</head>
<body>
    <div>
        <pre><code>
angular.module('myApp').service('AwesomeService', ['$http',
    function($http) {
        var i = 1;

        this.yo = function() {
            return 'AwesomeService:' + new Date().getTime();
        };

        this.name = 'AwesomeService';
        this.ts = new Date().getTime();

        this.up = function() {
            i = i + 1;
        };
    }
]);
        </code></pre>
    </div>

    <script src="../lib/js/jquery.min.js"></script>
    <script src="http://localhost:3010/assets/hl.bundle.js"></script>
</body>
</html>
```

普通に`require`する

```js
/* globals jQuery: true */

(function( undefined ) {

    var $, hljs;
    $ = require( 'jquery' );

    // autoreload for html
    require( 'raw!./hl.html' );

    hljs = require( './highlight.pack' );

    $(function() {

        $( document ).ready(function() {

            $( 'pre code' ).each(function( i, block ) {

                hljs.highlightBlock( block );
            });
        });
    });
})();
```

これだけだと`hljs`が見つからないとのこと、もちろんハイライトもされない

![error](http://s5.postimg.org/tvujutljr/2error_sc.png)

ダウンロードしてきた`highlight.pack.js`を整形して見てみると
モジュール化したあとで言語を登録している模様。

![highlight.js](http://s5.postimg.org/f8tld5mxj/3abouthljs.png)

この状態では`global`で普通にインクルードする時はこれで動くが
`webpack`でビルドすると`highlight.pack.js`が読み込まれた時点で`hljs`が存在しないから当然エラーになる。
	
# 解決策
モジュールと言語登録処理を分割し、言語登録処理でモジュールをインクルードしてそれを返せば良い。
使うときはモジュールファイルではなく言語登録ファイルをインクルードする。
こうすれば両方のファイルをインクルードする必要もなくなる。

### 手順

 1. `highlight.js`を**カスタムパッケージ無し**の状態でダウンロードする。
 2. ダウンロードしてきたピュアな`highlight.pack.js`のファイル名を`highlight.min.js`（`hljs.js`と略称）に変更。
 1. それから空の新たな`highlight.pack.js`（`pack.js`と略称）を用意。
 1. この`pack.js`が実際にインクルードされるライブラリーとなる。

`pack.js`の中に`hljs.js`をインクルードし言語登録をしてあげる

![fixed](http://s5.postimg.org/5o4wt5r9z/4newhljs.png)

13行目のようにファクトリーを実行する際に`hljs.js`を依存モジュールとしてインクルードして渡す。
`script`タグのインクルードされる際は`window`の`hljs`を渡す。

# CommonJSモジュールの考え方
`CommonJS`形式で`require`する際、依存先のモジュールの関数を呼出して値をセットすることはできるが、依存先モジュールをそのまま返すことはできない。
`CommonJS`は`exports`にメンバーを追加することでそれが`require`先で使えるようになる（理解が正しいかわからん）。

ということは`pack.js`の中で`hljs.js`を`return`で返しても何も受け取れない。
使い方が少し変わってしまうがこれを解決するために27行目のように`exports`オブジェクトに`hljs`プロパティとしてモジュールをセットしてあげる。

`require`先では下記のようにプロパティから取得すればOK。

```js
hljs = require( './highlight.pack' ).hljs;
```

これでも新たな言語を追加したい場合は`pack.js`に登録処理を追加して上げる必要があるという問題が残る。

# 結果
これでちゃんとハイライトされ、エラーも出ずに全てが丸く収まる

![success](http://s5.postimg.org/yggq9r593/5success.png)

## 言語登録コマンド

highlight.jsは様々な言語を対応しており、それぞれのハイライト定義ファイルが別に用意されている。
対象言語だけをビルドする[コマンド][build]が`node`とブラウザー用に言語登録の用意されている。
それで試して見てもがやはりうまくいかないので上記の対策をせざるの得なかった。

[build]:http://highlightjs.readthedocs.org/en/latest/building-testing.html#building