Dexie.jsで始める

IndexedDB

2018/05/19 #jsfes @himanoa

自己紹介

  • himanoa(ひまのあ)
  • @h1manoa
  • フロントエンド バックエンド
  • JavaScript / TypeScript
  • 職ではVue.jsを書いてます
  • 趣味ではReact  + Redux 等

話すこと

  • IndexedDB #とは
  • IndexedDBつらい話
  • Dexie.jsの紹介
  • Dexie.js で解決すること / しないこと
  • IndexedDBのテスト
  • まとめ

IndexedDB #とは

IndexedDB #とは

  • Webブラウザ内で動くオブジェクト型ストレージ
  • クライアントサイドでの永続化手段の内の一つ
  • データを保存する際にキーを用いるので検索などができる
  • トランザクション
  • 利用用途はオフライン対応等

対応ブラウザ

https://caniuse.com/#feat=indexeddb

LocalStoraeとの比較

InxededDB LocalStorage
容量制限 50MB(無制限) 最大10MB
Index 自動採番
複合キー等
保存時に使うキーのみ
同期 / 非同期 非同期 同期

話すこと

  • IndexedDB #とは
  • IndexedDBつらい話
  • Dexie.jsの紹介
  • Dexie.jsで 解決すること / しないこと
  • IndexedDBのテスト
  • まとめ

IndexedDBつらい話

IndexedDBつらい話

  • I/F
  • ローカルストレージに比べてデータの取得までの手順が多い
  • データベースのIndexの構成変更
let db = indexedDB.open('HimanoaDB', 1);
let result
req.onsuccess = function (evt) {
  db = db.result;
};
req.onerror = function (evt) {
  console.error("openDb:", evt.target.errorCode);
};

req.onupgradeneeded = function (evt) {
  const store = evt.currentTarget.result.createObjectStore(
    'articles', { keyPath: 'id', autoIncrement: true });
  store.createIndex("body", "body", { unique: false })
  store.createIndex("author", "author", { unique: false })

  store.transaction.oncomplete = function(event) {
    const customerObjectStore = db.transaction("articles", "readwrite")
      .objectStore("articles");
    customerObjectStore.add({ title: "タイトル", 
       body: "読者じゃぶじゃぶ課金したくなるような射幸心を煽りまくる説明文章"
     });
  };
};

話すこと

  • IndexedDB #とは
  • IndexedDBつらい話
  • Dexie.jsの紹介
  • Dexie.jsで解決すること / しないこと
  • まとめ

Dexie.jsの紹介

Dexie.js #とは

  • IndexedDBのラッパーライブラリ
  • サーバーサイドでO/Rマッパー越しにDBを触る感覚
  • ドキュメントが豊富
  • 一括挿入などのインターフェースが存在しパフォーマンス👍
  • Promiseで使えるインターフェースを提供している
  • TypeScriptサポート
const db = new Dexie('HimanoDB');

db.version(1).stores({
  // ++ はオートインクリメントされるキー
  articles: '++id, title, body'
});

db.open();
// ES2017 ~
await db.articles.add({ title: "title", body: "body" });

DBの構成更新

db.version(1).stores({
    articles: "++id,title,body"
});

db.version(2).stores({
    artcles: "++id,title,body,summary"
}).upgrade (function (trans) {
    trans.articles.toCollection().modify (function (article) {
        article.summary = 'No summary'
    });
});

話すこと

  • IndexedDB #とは
  • IndexedDBつらい話
  • Dexie.jsの紹介
  • Dexie.jsで解決すること / しないこと
  • IndexedDBのテスト
  • まとめ

Dexie.jsで解決すること

しないこと

  • IndexedDBのローレベルAPI由来の煩雑さの回避
  • ブラウザ側でのデータベース整合性の複雑性は回避できない

話すこと

  • IndexedDB #とは
  • IndexedDBつらい話
  • Dexie.jsの紹介
  • Dexie.jsで解決すること / しないこと
  • IndexedDBのテスト
  • まとめ

IndexedDBのテスト

IndexedDBのテスト

Node環境にはindexedDBの実装が存在しない

$ node
> indexedDB
undefined
>

yarn add --dev fake-indexeddb

or

npm install fake-indexeddb

 

 

テストヘルパーを書く

global.indexedDB = 
  require("fake-indexeddb");
global.IDBCursor = 
  require("fake-indexeddb/lib/FDBCursor");
global.IDBCursorWithValue = 
  require("fake-indexeddb/lib/FDBCursorWithValue");
global.IDBDatabase = 
  require("fake-indexeddb/lib/FDBDatabase");
global.IDBFactory = 
  require("fake-indexeddb/lib/FDBFactory");
global.IDBIndex = 
  require("fake-indexeddb/lib/FDBIndex");
global.IDBKeyRange = 
  require("fake-indexeddb/lib/FDBKeyRange");
global.IDBObjectStore = 
  require("fake-indexeddb/lib/FDBObjectStore");
global.IDBOpenDBRequest = 
  require("fake-indexeddb/lib/FDBOpenDBRequest");
global.IDBRequest = 
  require("fake-indexeddb/lib/FDBRequest");
global.IDBTransaction = 
  require("fake-indexeddb/lib/FDBTransaction");
global.IDBVersionChangeEvent = 
  require("fake-indexeddb/lib/FDBVersionChangeEvent");

JestだとGlobalSetupで実行できるようにする

 

https://gist.github.com/himanoa/e8a143c19606633a79db7d0fd28d25f7

話すこと

  • IndexedDB #とは
  • IndexedDBつらい話
  • Dexie.jsの紹介
  • Dexie.jsで解決すること / しないこと
  • IndexedDBのテスト
  • まとめ

まとめ

  • IndexedDBはIE Edgeでは一部機能を使わなければ使える
  • とはいえIndexedDBを生で使うと本質とは違う苦労を求められる
  • Dexie.jsを使うと↑はある程度回避することが可能
  • それでも マイグレーションの整合性を合わせるなど苦労は
  • 各位やっていきましょう

deck

By himnaoa