-
-
Notifications
You must be signed in to change notification settings - Fork 20
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
On Demand Definitions Support #31
Comments
This is great — thank you for writing it up! I have no arguments with the content presented — it all seems sound to me. Works now: Initialization typesJust thinking aloud, this is possible in is-land v5 with the new initialization types API (you can change the default behavior by assigning a Island.addInitType("default", async (target) => {
const defineAttr = target.getAttribute('define');
if (!defineAttr) return;
const mod = await import(target.getAttribute("import");
const clazz = mod[defineAttr];
if (!clazz) throw new Error(`Did not export ${defineAttr}`);
if (!('define' in clazz)) throw new Error('Class does not implement On-Demand Definitions.');
clazz.define();
}); For non-default types, you would need to associate it with the island with the However, Line 200 in 3461982
Currently there is no way to assign multiple initialization types to a specific island. Works now: bundler friendlyFor the bundler specific question, it might be beneficial to have more a static analysis friendly dynamic import, but that means a init type will be limited to one specific element, e.g. Island.addInitType("define:my-foo", async (target) => {
const defineAttr = target.getAttribute('define');
if (!defineAttr) return;
const mod = await import("./my-foo.js");
const clazz = mod[defineAttr];
if (!clazz) throw new Error(`Did not export ${defineAttr}`);
if (!('define' in clazz)) throw new Error('Class does not implement On-Demand Definitions.');
clazz.define();
}); I don’t really like the above as it’s way too verbose. Idea: support multiplesWhat if we added support for multiple types that run sequentially? e.g. // This doesn’t currently work
Island.addInitType("my-foo", async (target) => {
// return object reassigns `mod` param for next type
return import("./my-foo.js");
});
Island.addInitType("define", (target, mod) => {
const defineAttr = target.getAttribute('define');
if (!defineAttr) return;
const clazz = mod[defineAttr];
if (!clazz) throw new Error(`Did not export ${defineAttr}`);
if (!('define' in clazz)) throw new Error('Class does not implement On-Demand Definitions.');
clazz.define();
}); How do you feel about these options? Do they feel better than diving deeper into more complex |
Thanks @zachleat! As you mention though, it is a bit verbose, and asking every usage of 1. Implicit definition in
|
Context
The On-Demand Definitions Web Components Community Protocol
Problem
<is-land import="...">
effectively requires the imported module to define any relevant custom elements in the top-level scope of the provided module. This requires developers to follow a specific convention:This top-level side effect has a few negative consequences:
<is-land import="...">
anyways).<is-land>
, and instead may implicitly define some of them as transitive dependencies. If those transitive dependencies are ever changed, theimport
may fail to define all the components originally expected by the developer and lead to unintended bugs.An example of problem 2.:
<is-land>
only imports./my-foo.js
, but takes advantage of that to define both<my-foo>
and<my-bar>
. Ifmy-foo.js
were refactored to no longer depend on<my-bar>
, it might look like:The
import="./my-foo.js"
now no longer defines<my-bar>
, therefore the rendered element is a no-op and has no functionality.Proposal
Use On-Demand Definitions to implicitly define any components which are referenced by
import
. Consider a newdefine
attribute which references exported symbols from theimport
attribute and calls.define
on them.A pseudo-code implementation might look like:
Then consumers would use it like so:
This would work for any component which implements On-Demand Definitions, meaning
MyFoo
would need to look something like:This provides a more direct association between an
<is-land>
instance and the component classes it depends upon. This requires the defined class to be exported from the given module, meaning it is not a random implementation detail of top-level side-effects triggered by importing that module. And if the class is ever moved or renamed, users will get a clear error message about their mistake.Other Considerations
Bundlers
Using this feature allows developers to write their code without top-level side-effects in all their components, which makes their code generally friendlier to bundlers and easier to work with (see the problems listed here.) The motivating example provided above is admittedly an edge case, however if there ever becomes a good story for using
<is-land>
with bundlers (maybe one already exists I'm unaware of), then this feature becomes even more valuable as it would allow tree-shaking unused components in a much more natural fashion.Multiple Components
As my motivating example uses, it is possible for an
<is-land>
to load multiple components, therefore it probably makes sense to support multiple component names in adefine
attribute. I think separating them by a space seems reasonable, given that spaces cannot appear in JavaScript identifiers, so one could write:This approach does require that both symbols are exported from the same module, which might not necessarily be a safe assumption and require developers to produce an otherwise unnecessary
my-components.js
file solely for re-exporting these two components. However I think this is somewhat of an existing issue withimport
and applies even withoutdefine
.An alternative syntax might be something like:
I'm not sure if a space is entirely appropriate there given that URLs can have spaces (escaped to
%20
) and that#
does have existing meaning in URLs which may or not be desirable in this context. However this approach can support importing specific symbols from distinct modules and avoid the need for a re-export module. Just one consideration.Since I happen to be particularly invested in finding use cases for On-Demand Definitions and pushing that proposal forward, I'd be happy to put together a PR adding support to
<is-land>
. Alternatively if you have any particular concerns with the design of the proposal, I'd also be interested in hearing any feedback or suggestions on how to improve it and how applicable it is to<is-land>
in particular.The text was updated successfully, but these errors were encountered: