はじめに
nw.jsにおいて、require()したモジュールにDOMを使わせる方法。
※どうしてもrequire()
でDOMを使わせたいというこだわりがなければ、素直にHTML上で<script>
タグで読み込ませるほうが簡単である。そうすればWindowコンテキストで動作するのでDOM前提のモジュールはきちんと動作する。普通はそうするよね。。
やり方
require()
する前にglobalオブジェクトにDOMオブジェクトと同名のプロパティを作り、そこにDOMプロパティを代入する。
※起動時はWindowコンテキストで動作していることが前提。
Differences of JavaScript contexts · nwjs/nw.js Wiki
global.document = window.document;
global.navigator = window.navigator;
// DOMを使うモジュールのロード
var ko = require('knockout');
var jquery = require('jquery');
なぜこんなことをしないといけないか
例えばknockoutだとモジュールの実装が下記となっている。
(function(){
var DEBUG=true;
(function(undefined){
// (0, eval)('this') is a robust way of getting a reference to the global object
// For details, see http://stackoverflow.com/questions/14119988/return-this-0-evalthis/14120023#14120023
var window = this || (0, eval)('this'),
document = window['document'],
navigator = window['navigator'],
jQueryInstance = window["jQuery"],
JSON = window["JSON"];
.
.
.
もうひとつ。jqueryでの実装。
(function( global, factory ) {
if ( typeof module === "object" && typeof module.exports === "object" ) {
// For CommonJS and CommonJS-like environments where a proper `window`
// is present, execute the factory and get jQuery.
// For environments that do not have a `window` with a `document`
// (such as Node.js), expose a factory as module.exports.
// This accentuates the need for the creation of a real `window`.
// e.g. var jQuery = require("jquery")(window);
// See ticket #14549 for more info.
module.exports = global.document ?
factory( global, true ) :
function( w ) {
if ( !w.document ) {
throw new Error( "jQuery requires a window with a document" );
}
return factory( w );
};
} else {
factory( global );
}
// Pass this if window is not defined yet
}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
.
.
nw.jsの場合require()
したときはNodeコンテキストで動作するのでグローバルオブジェクトはglobalである。そのため上のthis
にはglobalオブジェクトが入り、うまく動作しない。事前にglobalオブジェクトにDOMプロパティを入れておくことでNodeコンテキストでもうまく動かすことができるようになる。
jqueryの場合はglobal.window = window
としても動作するね。そのほうがいいかもしれない。
さいごに
この方法は十分に検証したわけではなく、自分が使いたいモジュールがたまたまこの方法で動いているだけかもしれないので気をつけること。万能かどうかはわかりません。。