timstuyckens/chromeextensions-knockoutjs

KO is undefined while using ECMA imports

Closed this issue · 2 comments

Hello!

I have a knockout SPA with es6/ECMA module imports (basically all modules have import ko from "knockout"), no window.ko available.
Because of this, I suspect knockout is not found by an extension scripts (first of its pages/js/devtools.js) since they rely on availability of ko solely in global namespace:

var ko = window.ko;

Inspecting through chromium (v107.0.5304.87) devTools of any knockout component with document-wide applied bindings results in:

knockout.js is not used in the page (ko is undefined). Maybe you are using iFrames, if so, browse to the url of the frame and try again.

I understand that I could just throw in ko into global namespace under window. but it does not seem as any good practice.

Are there any plans on supporting this type of modular imports?
Thank you.

Hi,

I'm not sure but I guess it can be supported in a simular way requireJS (define function instead of import) is supported
Maybe another fallback can be added when getting the knockout object (eg : devtools line 10-24, copy tweak to line 26)
var isDefinedAvailable = typeof window.require.defined === 'function';

PR are welcome.

Kind regards,

Tim

Thank you for your response.
So the issue by the looks of it was me using any non-global-scoped instance of KO which results in such behavior because of architectural business-logic behind unique ko-instance identifier where all ko's service/vm attributes are stored.

To put it simply:
knockout/src/utils.domData.js which is a backend for ko.datafor/ko.contextFor, is an IIFE module, once its called:

var dataStoreKeyExpandoPropertyName = "__ko__" + (new Date).getTime(); 

generates UUIDv1-like (algorithmically impovised) unique string bound to its creation time. This string then is used for all encapsulated ko's service attributes inside which are placed all defined through public API viewmodel's attributes and context.

And since I was importing another instance of KO, it already had more rescent dataStoreKeyExpandoPropertyName generated during it's first IIFE initialisation of factory function in mentioned above module, so it could not find any of its own ko-attributes since they originally belonged to another KO instance, whose bindings were applied.

Considering all of the above I currently think there're 2 possible solutions:

  1. Add a disclaimer, the simplest throw Error(...)/returning a string like one in an issue when no window.ko is found, making availability of ko at global scope an explicit requirement with a 1-2 step guide of adding at any VM window.ko = ko (considering ko is imported through import { ko } from "knockout").
  2. Create helper-function, which extracts exact DOM Element's attibute created with dataStoreKeyExpandoPropertyName during KO-instance's first initialisation; and reserse-engineering some functionality of knockout/src/utils.domData.js making ko.data/ko.contextFor or their alternatives capable of searching __ko__... attribute from any older (any other) instances, although there will always be a single instance of KO, since its responsible for applying bindings.

For a current solution I think 1st variant is a good-enough, since there's no tempering with ko's service attributes. I may open up a PR with a fix, or at least herein the cause is more-or-less documented.

Thank you for your time.

P.S. it may be a good idea to add current extension to https://github.com/dnbard/awesome-knockout since it works fine with latest stable version of knockout (3.5.1 at the time of writing)