nw.js上でdexieを使う

公開:2015-06-21 20:55
更新:2020-02-15 04:37
カテゴリ:nw.js,javascript,ブログ,html5

ブログシステムのコードを書き始めた。ダッシュボード・テンプレート SB Admin2 をベースに少しずつUIを作り替えていく作戦で始めた。実装はHubPressを参考にする。

HubPressでは設定情報を保存するデータストアとしてIndexedDBを使用している。IndexedDBはDBライクに操作できるdexieというライブラリを経由してアクセスする。私もこれに倣うことにする。

軽く下記のようなコードを書いてみると、これが動作しない。

var dexie = require('dexie');
var db = new dexie('sfblog');
db.version(1).stores({
github: "username,password,apikey"
});
db.open();
db.transaction('rw', db.github, function () {
db.github.add({ username: 'sfpgmr', password: 'pass', apikey: 'aaaaa' });
db.github.add({ username: 'sfpgmr3', password: 'pass', apikey: 'aaaaa' });
});
db.github.each(function (r) {
console.log(r);
});
db.close();
view raw dexietest.js hosted with ❤ by GitHub

調べてみると以下のことが分かった。dexie.jsのコードの外枠は以下のようになっている。

(function (global, publish, undefined) {
// dexie の中身(省略)
// Export Dexie to window or as a module depending on environment.
publish("Dexie", Dexie);
}).apply(null,
// AMD:
typeof define === 'function' && define.amd ?
[self || window, function (name, value) { define(name, function () { return value; }); }] :
// CommonJS:
typeof global !== 'undefined' && typeof module !== 'undefined' && module.exports ?
[global, function (name, value) { module.exports = value; }]
// Vanilla HTML and WebWorkers:
: [self || window, function (name, value) { (self || window)[name] = value; }]);
view raw dexietest2.js hosted with ❤ by GitHub

これはAMDとCommonJS、それとブラウザで動かす時によく書かれるコードである。nw.jsはglobalもwindowも両方持っているので、require()すると上記のコードだとCommonJS対応部分が有効となり、globalオブジェクトがグローバルオブジェクトとして関数の引数に設定される。

それで、IndexedDBのラップする部分のコードを見てみると以下のようであった。

//
// Dependencies
//
// These will automatically work in browsers with indexedDB support, or where an indexedDB polyfill has been included.
//
// In node.js, however, these properties must be set "manually" before instansiating a new Dexie(). For node.js, you need to require indexeddb-js or similar and then set these deps.
//
var idbshim = global.idbModules && global.idbModules.shimIndexedDB ? global.idbModules : {};
Dexie.dependencies = {
// Required:
// NOTE: The "_"-prefixed versions are for prioritizing IDB-shim on IOS8 before the native IDB in case the shim was included.
indexedDB: idbshim.shimIndexedDB || global.indexedDB || global.mozIndexedDB || global.webkitIndexedDB || global.msIndexedDB,
IDBKeyRange: idbshim.IDBKeyRange || global.IDBKeyRange || global.webkitIDBKeyRange,
IDBTransaction: idbshim.IDBTransaction || global.IDBTransaction || global.webkitIDBTransaction,
// Optional:
Error: global.Error || String,
SyntaxError: global.SyntaxError || String,
TypeError: global.TypeError || String,
DOMError: global.DOMError || String,
localStorage: ((typeof chrome !== "undefined" && chrome !== null ? chrome.storage : void 0) != null ? null : global.localStorage)
};
view raw dexietest3.js hosted with ❤ by GitHub

コメントに書いてある通りだが、node.jsで使用するときはindexeddb-jsを事前にrequireしておかなくてはいけないようだ。

しかしnw.jsはwindowオブジェクトも持っており、IndexedDBもサポートしている。だけどglobalオブジェクトが渡されるのでpolyfillが必要になってしまうのだ。windowオブジェクトのIndexedDBを使わせるにはどうしたらよいかと少し考えたが、ベタな方法で回避することにした。require('dexie')する前に以下のコードを書くのである。

global.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
view raw dexietest4.js hosted with ❤ by GitHub

ちょっと不細工な方法だが、とりあえずこれで進めることにした。