背景
HTMLファイルから3rd Partyのnode.jsのモジュールを利用しようとして、「require is not defined」というエラーにぶち当たった。
そこで、node.jsのモジュールをライブラリとしてHTMLに読み込む方法があるかを調べてみたところ、browserifyというものがあるのを知ったので、試してみた。
ちなみに、HTML用のjsファイルが用意されているモジュールもあるっぽいので、その場合は、それをそのまま読み込めばよいと思う。
「require is not defined」エラーについて
例えば、下記のようなhtmlとjsファイルを作ったとき。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Test</title>
</head>
<body>
<p>Test</p>
<div>
<textarea id="token" rows="8" cols="120">{hoge: 'hogehoge'}</textarea>
<textarea id="signed" rows="12" cols="120"></textarea>
</div>
<button id="sign">Sign</button>
</body>
<script src="test.js"></script>
</html>
// 注意:このコードは動作しません。
var jwt = require('jsonwebtoken');
document.getElementById("sign").onclick = () => {
const jwt = document.getElementById("token").value;
const signedJwt = sign(jwt);
document.getElementById("signed").innerText = signedJwt;
};
function sign(payload) {
return jwt.sign(payload, 'secret');
}
ブラウザで開くと、見た目はこんな感じ。
「Sign」ボタンを押すと、上のテキストエリアにあるJSON形式のテキストに署名をして、下のテキストエリアに表示しようとしたコード。
実際には、このコードは動かなくて、以下のようなエラーになる。
まぁ、当たり前なのかもしれないけど、ただのhtmlなので、**require('jsonwebtoken')**はエラーになる。
ちなみに、jsonwebtokenはJWTとかに署名できるライブラリで、nodejsであれば「npm install jsonwebtoken」とかでインストール後、上記のような呼び出しで利用できるようになる。
browserifyの利用
ということで、これを動くようにするために、browserifyを使って頑張ってみる。
browserifyは、node.jsのコードをブラウザで動作するようにしてくれるらしい。
最終的にはhtmlとjsだけで動くようにする予定だが、とりあえず、開発にはnode.jsの環境が必要なので環境を作る。
> mkdir browserify
> cd browserify
> yarn init
適当に作ったnode環境のプロジェクト直下に、さきほどのtest.htmlとtest.jsを置く。
続いて、jsonwebtokenをインストール。
> yarn add jsonwebtoken
もちろん、これだけでは状況は変わらない。
ということで、browserifyをインストール。
> yarn global add browserify
browserifyを使って実行してみる。
> browserify test.js -o test2.js
生成された「test2.js」は下記のような感じ。
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;...
... (約3万行)
document.getElementById("sign").onclick = () => {
const jwt = document.getElementById("token").innerText;
const signedJwt = sign(jwt);
document.getElementById("signed").innerText = signedJwt;
};
function sign(payload) {
return jwt.sign(payload, 'secret');
}
},{"jsonwebtoken":208}]},{},[232]);
3万行ぐらいのファイルが生成された。
依存のファイルがすべて一つにまとめられた模様。
test.htmlを以下のように編集して、動作確認。
<!DOCTYPE html>
<html>
...
<script src="test2.js"></script>
</html>
再度、test.htmlをブラウザで開いてみる。
「Sign」ボタンを押すと、署名されたっぽい文字列が表示された。
とりあえず、それっぽいものが表示されたけど、何か変な気もする。
このままだと、デバッグしようにも、test.jsを書き換えるたびに、browserifyでファイル生成が必要となる。
やはり「jsonwebtoken」部分だけをライブラリとしてhtmlに読み込んで、test.jsから利用するようにしたい。
node.jsのモジュールをライブラリとしてHTMLで読み込む
ということで、「jsonwebtoken」をライブラリとしてHTMLで読み込める形に出来ないか試してみた。
色々試行錯誤してみたところ、下記のようなjsファイル(jsonwebtoken-wrapper.js)を用意し、browserifyをかけることで、それっぽく動作した。
(function (factory) {
typeof define === 'function' && define.amd ? define(factory) :
factory();
}((function () { 'use strict';
// 以降に、元のライブラリのI/Fをそのままそのまま呼び出すだけのfuntionを追加
var jwt = require('jsonwebtoken');
function sign(payload, secretOrPrivateKey, options, callback) {
return jwt.sign(payload, secretOrPrivateKey, options, callback);
}
function verify(jwtString, secretOrPublicKey, options, callback) {
return jwt.verify(jwtString, secretOrPublicKey, options, callback);
}
function decode(jjwt, options) {
return jwt.decode(jwt, options);
}
// 以降で外から呼び出せるように定義する。
if (window) {
if (typeof window.define == "function" && window.define.amd) {
window.define("jwt_sign", function() {
return sign;
});
window.define("jwt_verify", function() {
return verify;
});
window.define("jwt_decode", function() {
return decode;
});
} else {
window.jwt_sign = sign;
window.jwt_verify = verify;
window.jwt_decode = decode;
}
}
})));
browserifyを使って、htmlから読み込み可能にしておく。
> browserify jsonwebtoken-wrapper.js -o jsonwebtoken.js
jsonwebtoken.jsというファイルが生成される。
test.htmlは、下記のように修正。
<!DOCTYPE html>
<html>
...
<body>
<script src="./jsonwebtoken.js"></script>
...
</body>
<script src="test.js"></script>
</html>
ライブラリとして、生成したファイルを読み込むようにした。
また、さきほど、test2.jsに変更した部分をtest.jsに戻しておく。
test.jsは以下のように書き換え。
// var jwt = require('jsonwebtoken'); この行を削除
...
function sign(payload) {
return jwt_sign(payload, 'secret'); // jwt.sign(..)をjwt_sign(..)に変更
}
ブラウザにtest.htmlを表示して確認。
とりあえず正しく動作している模様。
ちなみに、「test.html」、「test.js」、「jsonwebtoken.js」の3つだけを適当なフォルダにおいて実行しても、同じように動作した(nodeから切り離された環境でも動作した)。