dexie / Dexie.js

A Minimalistic Wrapper for IndexedDB
https://dexie.org
Apache License 2.0
11.69k stars 641 forks source link

compatibility with Node #359

Closed jboulmal closed 7 years ago

jboulmal commented 8 years ago

Hello, Thank you for this awesome work! This is question rather than an issue. Is this Module compatible with the latest version of Node ? Thanks

dfahlander commented 8 years ago

The module is primary for browsers, but should in theory work on node if using indexeddbShim which now shims indexedDB on node using sqlite.

If you mean to build it, it is compatible with node 4 and node 6. I don't see any reason why it shouldn't be compatible with node 7 as well though.

I use node v6.5.0 when building.

$ node --version
v6.5.0
jboulmal commented 8 years ago

While trying Dexie.js with IndexedDBShim. we got some errors :

{ MissingAPIError: indexedDB API not found. If using IE10+, make sure to run your code on a server URL (not locally). If using old Safari versions, make sure to include indexedDB polyfill.
    at new e (~/dist/StorageManager.js:28:6136)
   Error
       at getErrorWithStack (~/node_modules/dexie/dist/dexie.js:309:12)
       at new DexieError (~/node_modules/dexie/dist/dexie.js:420:19)
       at ~/node_modules/dexie/dist/dexie.js:1971:35
       at executePromiseTask (~/node_modules/dexie/dist/dexie.js:930:9)
       at new Promise (~/node_modules/dexie/dist/dexie.js:723:5)
       at Dexie.open (~/node_modules/dexie/dist/dexie.js:1957:45)
erikvold commented 7 years ago

While trying Dexie.js with IndexedDBShim. we got some errors :

this is because dexie by default assumes there will be a global window object (ie that global.window will be defined), so you have to set

require("indexeddbshim").setGlobalVars(global);
global.window = global

Node's global is shared across modules.

There is some information in IndexedDBShim's README about it https://github.com/axemclion/IndexedDBShim/blob/master/README.md#node-set-up

jboulmal commented 7 years ago

Thanks for the support. It has been solved a while ago as you suggested above. I forgot to close the issue. Cheers!

dfahlander commented 7 years ago

Happy that this was solved. However, Dexie does not rely on window to be defined though. You can provide the indexedDB api without putting it onto window.

var Dexie = require('dexie');
Dexie.dependencies.indexedDB = indexedDB;
Dexie.dependencies.IDBKeyRange = IDBKeyRange;
dfahlander commented 7 years ago

Also possible to set it per instance:

var db = new Dexie('dbname', {
    indexedDB: indexedDB,
    IDBKeyRange: IDBKeyRange
});

Also described in http://dexie.org/docs/Dexie/Dexie

jboulmal commented 7 years ago

Thanks for the your last suggestions @dfahlander. However, I got an error :

 Dexie.dependencies.IDBKeyRange = IDBKeyRange;
                                             ^
ReferenceError: IDBKeyRange is not defined
Here is snippet of the code :
...........
import Dexie from 'dexie';
import indexedDB from 'indexeddbshim';

  Dexie.dependencies.indexedDB = indexedDB;
  Dexie.dependencies.IDBKeyRange = IDBKeyRange;

  // global.window= global;
  // setGlobalVars(global.window);
  // window.shimIndexedDB.__useShim();
  // cwindow.shimIndexedDB.__debug(true);

  let storageName = 'cache';

  const db = new Dexie(storageName, {
    indexedDB: indexedDB,
    IDBKeyRange: IDBKeyRange
    // indexedDB: window.indexedDB, // or the shim's version
    // IDBKeyRange: window.IDBKeyRange // or the shim's version.
  });
dfahlander commented 7 years ago

IDBKeyRange must be extracted from the indexedDB module. Don't know what it exports, but in principle :

import {indexedDB, IDBKeyRange} from 'indexeddbshim';
dfahlander commented 7 years ago

Pinging @brettz9 for some help. Brett, is it possible to import {IDBKeyRange} along with indexedDB from indexeddbshim in node?

jboulmal commented 7 years ago

I have tried, I got again the window is not defined error message!

dfahlander commented 7 years ago

Are you getting the error from Dexie or from the shim?

erikvold commented 7 years ago

IDBKeyRange must be extracted from the indexedDB module. Don't know what it exports, but in principle :

import {indexedDB, IDBKeyRange} from 'indexeddbshim';

That would be a nice update imo, I think at the moment we might have to do something like:

var { Dexie } = require("dexie");
var setGlobalVars = require("indexeddbshim");
var thing = {};
setGlobalVars(thing);
var { indexedDB, IDBKeyRange } = thing;

var db = new Dexie("dbname", {
    indexedDB: indexedDB,
    IDBKeyRange: IDBKeyRange
});

We can't easily use indexeddbshim's internal modules directly either because there is a build step.

erikvold commented 7 years ago

Happy that this was solved. However, Dexie does not rely on window to be defined though.

@dfahlander Ah my mistake, thanks for correcting me!

erikvold commented 7 years ago

Note: you'll have to use the master branch of indexeddbshim at the moment, because the latest release doesn't support Node.

jboulmal commented 7 years ago

@dfahlander Are you getting the error from Dexie or from the shim?

The error is from the shim not Dexie. However, I don't have errors! If I define window as global in Node as the following:

let Dexie = require("dexie");
let setGlobalVars = require("indexeddbshim");

 global.window= global;
 setGlobalVars(global.window);
 window.shimIndexedDB.__useShim();
  cwindow.shimIndexedDB.__debug(true);

  let storageName = 'cache';

  const db = new Dexie(storageName, {
      indexedDB: window.indexedDB, // or the shim's version
    IDBKeyRange: window.IDBKeyRange // or the shim's version.
  });

@erikvold I'll try your code!

brettz9 commented 7 years ago

Will try to take a look as I have a chance--trying to wrap up a current PR first...

brettz9 commented 7 years ago

This is now being reported as fixed (per changes in master) at https://github.com/axemclion/IndexedDBShim/issues/259 .

Regarding the ideal export syntax for IndexedDBShim, I sympathize with that and added issue https://github.com/axemclion/IndexedDBShim/issues/283 . Note, however, that our current approach allows us to define the properties as non-enumerable, etc. as is expected by W3C tests.

icodeforlove commented 7 years ago

I was struggling with this as well.

This is what worked for me.

const db = (name => {
    require('indexeddbshim')(global);

    let Dexie = require('dexie');
    global.shimIndexedDB.__useShim();
    global.shimIndexedDB.__setConfig({checkOrigin: false});

    return new Dexie(name, {
        indexedDB: global.indexedDB,
        IDBKeyRange: global.IDBKeyRange
    });
})('cache');

This did not require me to define window as global, also i was getting origin errors when doing a db.open so i had to disable shimIndexedDB's checkOrigin

aral commented 6 years ago

A quick cut/paste example, based on the responses above:

const setGlobalVars = require('indexeddbshim')
const Dexie = require('dexie')

//
// Configure Dexie to use the IndexedDB shim.
//
// The intermediary shim object is required so we can pull out the objects
// we need to configure Dexie without needing to pollute the global namespace.
//
// checkOrigin:false is required to avoid  SecurityError Cannot open
// an IndexedDB database from an opaque origin.
//
const shim = {}
setGlobalVars(shim, {checkOrigin: false})
const { indexedDB, IDBKeyRange } = shim
Dexie.dependencies.indexedDB = indexedDB
Dexie.dependencies.IDBKeyRange = IDBKeyRange

// Test Dexie
const db = new Dexie('hellodb')
db.version(1).stores({
  tasks: '++id,date,description,done'
})

db.tasks.bulkPut([
  {date: Date.now(), description: 'First item', done: 0},
  {data: Date.now(), description: 'Second item', done: 1},
  {data: Date.now(), description: 'Third item', done: 0}
]).then(() => {
  db.tasks.where('done').above(0).toArray().then((tasks) => {
    console.log(`Completed tasks: ${JSON.stringify(tasks, 0, 2)}`)
  })
}).catch((e) => {
  console.error(`Error: ${e}`)
})
jmagaram commented 6 years ago

I'm trying to use Jest to test some database stuff using TypeScript. Can't get the shim thing working in TypeScript. So what I did was have a regular .js file with the configuration code and export it as a function called configureDexieForNode. And then I call that function in my Jest tests in a beforeAll method. It works! But how do I reset Dexie in the afterAll so it works in the browser? How to get it back to its regular/normal state when not in the testing environment?

const setGlobalVars = require('indexeddbshim')
const Dexie = require('dexie')

export function configureDexieForNode() {
    const shim = {}
    setGlobalVars(shim, {
        checkOrigin: false
    })
    const {
        indexedDB,
        IDBKeyRange
    } = shim
    Dexie.dependencies.indexedDB = indexedDB
    Dexie.dependencies.IDBKeyRange = IDBKeyRange
}
dfahlander commented 6 years ago

@jmagaram Your function configureDexieForNode() should not run in beforeAll, but once, globally per node process, and never for browser. There's no such thing as resetting it back to normal since we're talking about two different environments requiring different setups. I think you could go for calling configureDexieForNode() using Jest's global setup configuration.