4
1

More than 3 years have passed since last update.

node.jsのモジュールをHTMLで読み込む

Posted at

背景

HTMLファイルから3rd Partyのnode.jsのモジュールを利用しようとして、「require is not defined」というエラーにぶち当たった。

そこで、node.jsのモジュールをライブラリとしてHTMLに読み込む方法があるかを調べてみたところ、browserifyというものがあるのを知ったので、試してみた。

ちなみに、HTML用のjsファイルが用意されているモジュールもあるっぽいので、その場合は、それをそのまま読み込めばよいと思う。

「require is not defined」エラーについて

例えば、下記のようなhtmlとjsファイルを作ったとき。

test.html
<!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>
test.js
// 注意:このコードは動作しません。

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');
}

ブラウザで開くと、見た目はこんな感じ。

image.png

「Sign」ボタンを押すと、上のテキストエリアにあるJSON形式のテキストに署名をして、下のテキストエリアに表示しようとしたコード。

実際には、このコードは動かなくて、以下のようなエラーになる。

image.png

まぁ、当たり前なのかもしれないけど、ただの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」は下記のような感じ。

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を以下のように編集して、動作確認。

test.html
<!DOCTYPE html>
<html>
  ...

  <script src="test2.js"></script>

</html>

再度、test.htmlをブラウザで開いてみる。

image.png

「Sign」ボタンを押すと、署名されたっぽい文字列が表示された。

とりあえず、それっぽいものが表示されたけど、何か変な気もする。

このままだと、デバッグしようにも、test.jsを書き換えるたびに、browserifyでファイル生成が必要となる。

やはり「jsonwebtoken」部分だけをライブラリとしてhtmlに読み込んで、test.jsから利用するようにしたい。

node.jsのモジュールをライブラリとしてHTMLで読み込む

ということで、「jsonwebtoken」をライブラリとしてHTMLで読み込める形に出来ないか試してみた。

色々試行錯誤してみたところ、下記のようなjsファイル(jsonwebtoken-wrapper.js)を用意し、browserifyをかけることで、それっぽく動作した。

jsonwebtoken-wrapper.js
(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は、下記のように修正。

test.html
<!DOCTYPE html>
<html>
  ...
 <body>
    <script src="./jsonwebtoken.js"></script>
    ... 
  </body>

  <script src="test.js"></script>

</html>

ライブラリとして、生成したファイルを読み込むようにした。

また、さきほど、test2.jsに変更した部分をtest.jsに戻しておく。

test.jsは以下のように書き換え。

test.js
// var jwt = require('jsonwebtoken'); この行を削除

...

function sign(payload) {
  return jwt_sign(payload, 'secret'); // jwt.sign(..)をjwt_sign(..)に変更
}

ブラウザにtest.htmlを表示して確認。

image.png

とりあえず正しく動作している模様。

ちなみに、「test.html」、「test.js」、「jsonwebtoken.js」の3つだけを適当なフォルダにおいて実行しても、同じように動作した(nodeから切り離された環境でも動作した)。

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1