Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(core/biblio-db): Move from indexedDB to idb #2228

Merged
merged 21 commits into from
Aug 3, 2019

Conversation

Swapnilr1
Copy link
Contributor

@Swapnilr1 Swapnilr1 commented Apr 4, 2019

Fixes #1955

I started refactoring few days ago but ran into issues with tests and have not been able to resolve it.
When running the tests in biblio-db-spec.js, I get Error: Script error for "idb", needed by: core/biblio-db and the tests fail.
I even tested after removing almost all code and keeping just

import { openDB } from "idb";
export const name = "core/biblio-db";
export const biblioDB = {};

in biblio-db.js, and I still got the same error Error: Script error for "idb", needed by: core/biblio-db.
I even tried to use the IDB code from xref.js and I still got the same error. 😢

I noticed that the tests for xref include the database creation code:

await new Promise(resolve => require(["deps/idb"], resolve));
const { openDB } = window.idb;
const { IDBKeyVal } = await new Promise(resolve =>
  require(["core/utils"], resolve)
);
const idb = await openDB("xref", 1, {
  upgrade(db) {
    db.createObjectStore("xrefs");
  },
});

So I think I have to make changes to the test files to get idb to be "initialized".

Any guidance is much appreciated.

@Swapnilr1
Copy link
Contributor Author

Swapnilr1 commented Apr 4, 2019

@sidvishnoi Could you have a look and tell me how to resolve Script error in tests (details in description)?

@saschanaz
Copy link
Collaborator

Just tried fixing your error, it should now at least import the package properly.

@Swapnilr1
Copy link
Contributor Author

Swapnilr1 commented Apr 4, 2019

@saschanaz Thanks for your help, though the error still persist. But your changes pointed me to towards the problem: The test is trying to fetch js/idb.js and getting a 404 instead of js/deps/idb.js.
I tried importing idb in some other modules and found that tests fail with the Script error when the test spec includes a require statement like https://github.com/w3c/respec/blob/24bf82b40e2e2ccb9efccc04390264b25252db77/tests/spec/core/biblio-db-spec.js#L42 and work otherwise (though I think you already know this).

So I need to check how to set the correct path for tests. Working on it. Thanks a lot.
EDIT: I see in Developer Tools that idb.js is loaded twice, once from the wrong location giving a 404. But I don't really understand how to debug this.

@Swapnilr1 Swapnilr1 marked this pull request as ready for review April 8, 2019 11:36
@Swapnilr1
Copy link
Contributor Author

Swapnilr1 commented Apr 8, 2019

Finally fixed tests locally. Thank you @marcoscaceres and @saschanaz for help with importing idb correctly.
I have almost completed the refactor, please review it - I think I have wrongly removed the DOMException rejections.
I am looking into why the tests are failing, because they ran well locally in SpecRunner. 😕

@saschanaz
Copy link
Collaborator

I suspect you are using SpecRunner.html? Maybe that's why I was seeing different result...

@Swapnilr1
Copy link
Contributor Author

@saschanaz Yes I am using SpecRunner.html. Thanks for the fix.

src/core/biblio-db.js Outdated Show resolved Hide resolved
src/core/biblio-db.js Outdated Show resolved Hide resolved
src/core/biblio-db.js Outdated Show resolved Hide resolved
src/core/biblio-db.js Outdated Show resolved Hide resolved
src/core/biblio-db.js Outdated Show resolved Hide resolved
return Array.from(aliasesAndRefs[type]).map(details =>
await this.add(type, details)
return Array.from(aliasesAndRefs[type]).map(
async details => await this.add(type, details)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is redundant because the return type is still Promise, and it's expected.

@@ -222,7 +221,7 @@ export const biblioDB = {
const storeNames = [...ALLOWED_TYPES];
const stores = await db.transaction(storeNames, "readwrite");
const clearStorePromises = storeNames.map(name => {
return stores.objectStore(name).clear();
return await stores.objectStore(name).clear();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is redundant too. It still returns a Promise anyway.

Copy link
Contributor

@marcoscaceres marcoscaceres left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of quick suggestions... not sure all apply.

src/core/biblio-db.js Show resolved Hide resolved
});
const objectStore = db.transaction([type], "readonly").objectStore(type);
const range = IDBKeyRange.only(id);
return !!(await objectStore.openCursor(range));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this was in the original, but it's still a bit ugly... maybe we can do?

Suggested change
return !!(await objectStore.openCursor(range));
const result = await objectStore.openCursor(range);
return result ? true : false;

Same with other one below...

Copy link
Collaborator

@saschanaz saschanaz Apr 9, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

? true : false? It doesn't look JavaScript-y for me... Maybe !!result?

(Because result ? part already coerces result into a boolean.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

!!result wfm

.transaction(["alias"], "readonly")
.objectStore("alias");
const range = IDBKeyRange.only(id);
return !!(await objectStore.openCursor(range));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above...

});
const store = db.transaction([type], "readwrite").objectStore(type);
// update or add, depending of already having it in db
const request = isInDB ? store.put(details) : store.add(details);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should do:
Maybe just:

Suggested change
const request = isInDB ? store.put(details) : store.add(details);
return isInDB ? await store.put(details) : await store.add(details);

@Swapnilr1
Copy link
Contributor Author

Swapnilr1 commented Apr 9, 2019

I have implemented the changes, but I am not able to run tests either by SpecRunner.html or by karma. SpecRunner gives SyntaxError: import declarations may only appear at top level of a module while the karma tests simply time out (locally as well as on Travis)

@saschanaz
Copy link
Collaborator

Investigation incoming...

@saschanaz
Copy link
Collaborator

saschanaz commented Apr 10, 2019

The problem is that currently the ES module system does not support resolving by package name. After #2241, karma wants to load idb as a dependency of core/biblio-db.js, which fails because the module system does not know what idb is.

We can replace idb with ../../node_modules/idb/build/esm/index.js as a workaround. It's not pretty, but anyway...

@marcoscaceres
Copy link
Contributor

Yeah, this is why copydeps.js exists :( and what’s nice about webpack is that it handles this. I’m still not sure how we overcome copydeps.js in a modules only world. We probably can’t as those files have to live somewhere.

@Swapnilr1
Copy link
Contributor Author

Swapnilr1 commented Apr 10, 2019

We can replace idb with ../../node_modules/idb/build/esm/index.js as a workaround.

@saschanaz This breaks everything else except the karma tests. This is because index.js is served directly to the browser and browsers do not support import. I think reverting to import { openDB } from "idb"; and adding a shim would solve the issue, but I am not sure where to add the shim.

@saschanaz
Copy link
Collaborator

Browsers do support imports, but yes, it will break requirejs compatibility... 🤔

@Swapnilr1
Copy link
Contributor Author

Browsers do support imports, ...

Oh, I thought browsers not supporting imports was the reason SpecRunner.html was failing, but I believe browsers require a type="module" attribute which RequireJS does not provide. I need help with configuring shims.

@saschanaz
Copy link
Collaborator

Seems we are kind of locked. Maybe we should do #1975 first?

@marcoscaceres
Copy link
Contributor

Now that SpecRunner is gone, @Swapnilr1 what’s blocking this?

@Swapnilr1
Copy link
Contributor Author

@marcoscaceres SpecRunner wasn't really blocking this (it doesn't run on Travis anyway) - SpecRunner would not work after #2241 so I had just made a comment regarding that.
The blocker is karma tests. Using import { openDB } from "idb"; (which loads the IIFE build) leads to TypeError: Failed to resolve module specifier "idb". when running karma tests. (Most likely because we require a shim - though I am not sure if it can be done).

Switching to import { openDB } from "../../node_modules/idb/build/esm/index.js"; as suggested by @saschanaz fixes the issue with karma tests but will break everything else. This is because index.js has import/export declarations, and unlike other modules won't be compiled by Babel before being served to the browser. The browser then complains of import declarations in a non-module because RequireJS does not serve it as an ES Module.

[Extremely sorry for any technical inaccuracy; I am not very well versed with ES6 modules].

@marcoscaceres
Copy link
Contributor

Hhmm... should we complain upstream? This doesn’t sound good and no other module exhibits this kind of problem?

@Swapnilr1
Copy link
Contributor Author

@marcoscaceres Yes, perhaps we can ask for RequireJS compatibility without needing shims - though I am not completely certain if this will fix the problem.

@saschanaz
Copy link
Collaborator

saschanaz commented Apr 25, 2019

This is because karma now consumes ES modules and this PR tries consuming a non-ES module (or ES module without an actual path) in an ES module. Webpack and requirejs somehow can deal with it but karma need import-maps support from browsers (to map "idb" to the actual path).

@marcoscaceres
Copy link
Contributor

this PR tries consuming a non-ES module (or ES module without an actual path) in an ES module

Ok, but that seems like a bug upstream, no? The maintainer has shipped something non-conforming. We could ask them to ship an actual ES module, instead of whatever this is.

@saschanaz
Copy link
Collaborator

No, idb itself is good, what happens here is we cannot just import * from "idb" because the native ES module system does not support non-path import. It's okay for marked and hyperhtml because they are not directly imported from karma (as generally tests just uses the compiled full ReSpec), but here we want to directly import a module and write a unit test for it.

@marcoscaceres
Copy link
Contributor

No, idb itself is good, what happens here is we cannot just import * from "idb" because the native ES module system does not support non-path import.

That makes sense :)

It's okay for marked and hyperhtml because they are not directly imported from karma (as generally tests just uses the compiled full ReSpec), but here we want to directly import a module and write a unit test for it.

This doesn't make sense to me (and probably where I'm getting confused). We should be testing the idb that is compiled into ReSpec. Additionally, shouldn't we just use use copydeps.js to copy idb over to deps?

copydeps.js can be removed once we fully transition to some packager.

@saschanaz
Copy link
Collaborator

saschanaz commented Apr 25, 2019

We should be testing the idb that is compiled into ReSpec.

We have tests that directly imports biblio-db as a module, which now depends on idb in this PR.

shouldn't we just use use copydeps.js to copy idb over to deps?

Currently copydeps is only used for requirejs mapping, otherwise TypeScript type system breaks (as they only knows package name to type).

It doesn't help here anyway, if we copy cjs then ES module breaks, or we copy esm then requirejs breaks, so 🤷‍♀️

@marcoscaceres
Copy link
Contributor

Yay! module systems 💃. Ok, we hold I guess until we kill RequiresJS.

@saschanaz
Copy link
Collaborator

until we kill RequiresJS.

Or until we get import maps on Firefox. I hope Mozillians get some push for this new feature.

@marcoscaceres
Copy link
Contributor

I believe this is appropriate?:

Screenshot 2019-04-25 13 02 43

😂

@sidvishnoi
Copy link
Member

What's blocking this one? Why can't we use idb the way we used in xref.js and xref-spec.js?

@saschanaz
Copy link
Collaborator

What's blocking this one? Why can't we use idb the way we used in xref.js and xref-spec.js?

Because Karma is using ES module, some tests there want to import core/biblio-db, and then the ES module system doesn't know where idb maps to. core/xref is not directly imported within karma, however.

Using the actual path for ES module version of idb will solve the problem and then will break RequireJS because it doesn't support ES module.

@saschanaz
Copy link
Collaborator

Okay, the tests now pass. Now time to review again! @marcoscaceres @sidvishnoi

Copy link
Contributor

@marcoscaceres marcoscaceres left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a small nit.

@@ -81,7 +45,8 @@ export const biblioDB = {
if (await this.isAlias(id)) {
id = await this.resolveAlias(id);
}
return this.get("reference", id);
const result = this.get("reference", id);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably want to await this.get, then return the result.

@marcoscaceres
Copy link
Contributor

@saschanaz, it shows you as having requested changes? I guess that’s from an old review?

Copy link
Collaborator

@saschanaz saschanaz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Sorry for the loooong delay and thank you for this PR @Swapnilr1!

@saschanaz saschanaz merged commit f05ad79 into speced:develop Aug 3, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Refactor biblio-db with idb dependency
4 participants