-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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
Generate custom elements #797
Comments
Are there implications for svelte component npm package developers? Will we distribute more bundles so that there is an es and cjs version of both the webcomponent and non-webcomponent versions? |
Good q. Thinking out loud — we should probably have some templates and 'official' guidelines for distributable components, but basically what I envisage is something like this:
Then you could use it like so: // as a standalone component in a non-Svelte app
import MyThing from 'my-thing';
new MyThing({...}); <!-- as a component in a Svelte app (deduplicates helpers etc) -->
<MyThing/>
<script>
import MyThing from 'my-thing';
export default {
components: { MyThing }
};
</script> // as a standalone custom element in a non-Svelte app
import 'my-thing/custom-element.mjs'; // or .js
document.body.innerHTML = `<my-thing/>`; <!-- as a custom element in a Svelte app -->
<my-thing/>
<script>
import 'my-thing';
</script> The last of those is probably the most confusing. Basically your app's build config would need to specify that some of your components needed to be compiled as custom elements: // rollup.config.js
import svelte from 'rollup-plugin-svelte';
// as an alternative to having two separate instances of the plugin,
// the app could just do `import 'my-thing/custom-element.mjs';` —
// it would just mean missing out on the deduplication
export default {
// ...
plugins: [
svelte({
include: 'node_modules/**',
customelement: true
}),
svelte({
exclude: 'node_modules/**',
customelement: false
})
]
}; I think that covers all the bases. Basically it should 'just work' with that structure, with opt-in further optimisations for Svelte apps. |
Directory structure dependent modules are pretty mean to my obsessive brain. The svelte component distribution model has been nice to me, since // awkward since no value is needed, and there's no way to determine what to shake, right?
import { ThingWebComponent } from 'thing' // Seems like this should work out
import { Thing } from 'thing' // regular component
import 'thing' // web component |
That wouldn't really work, because the custom element could never get shaken out (because |
Closing this as #811 has been merged, and Svelte 1.37 supports compiling to custom elements |
Oh right. Fortunately, I just had an alternate idea I'm less opposed to. Build to import 'thing/web-component' I'll just think of |
After taking a look at the Svelte 1.37 option, I have a request. Given the requirement that the tag name be provided to the compiler, it's not clear to me if it's possible to later register the resulting custom element under a different user defined tag name. If not, this is important--it's becoming a best practice for web components to allow users the option to register the element with any tag name they want. The reason being that custom elements exist in the global HTML namespace--you can't register the same tag name twice (or the same constructor). Being able to control when and how an element is registered provides a way to solve naming conflicts and adds flexibility around situations where you can't de-duplicate different versions of a component. Since these component based UIs are highly compositional it won't be uncommon to run into these types of situations. |
@morewry thanks — could you open a separate issue with that comment please, so it doesn't get lost? Totally get where you're coming from. My main concern was that it would become unreasonably burdensome for app developers to name each component, and I think that generally these sorts of collisions of will be rare. You can control the tag name by passing one to the compiler... compiled = svelte.compile(source, {
customElement: { tag: 'custom-name' }
}); ...but that doesn't really work if you're using the compiler via a bundler plugin. So it would be good to figure out a better solution (perhaps passing |
@morewry do you have other examples where folks are renaming their elements in this way? You mentioned it becoming a best practice but I've only ever heard of one other team attempting to do this |
@robdodson I actually thought I'd read it in something you'd written! Apparently that's not the case; poked around in some saved material from various sources, but couldn't find it. My guess is my memory mashed together two unrelated things, but I'll keep an eye out in case it was something relevant. So scratch that; I should make sure to verify before saying something so general. As I haven't had an opportunity to use web components in production, I've made static It doesn't come from nowhere, though, but rather as a result of our having run into situations with Angular 1.x directives (which we tried to make in ways heavily influenced by WCs, and of which you also can't have two of anything with the same name) where not being able to just give the gosh-darned thing a custom name and use two different versions of the directive got in our way. It came up often enough and for enough underlying reasons that I was keeping it in mind. But I hadn't realized until recently that there was a restriction on registering the same constructor twice; so while this might help ease transition in occasional and specific cases, such as different versions with breaking changes, it's not the general panacea as a pattern that I previously thought. So, @Rich-Harris, if it's alright, I'll make that issue if I have anything more productive, as of now I retract what I said. ;-) |
I may have floated the idea on a GH thread once. A while back I was thinking something similar but then folks pointed out that it doesn't help you because you still need to rename all the usage of those tags in your transitive deps. My concern with using two of the same custom element is that it's inherently going to bloat the bundle that you send to the client. Personally I'm wondering if we could get to a place where client side code gets deduped down to just 1 version of everything, and build tools/ |
@robdodson I get you on the flattening. I'm old-school and am constantly pushing for us to avoid bloat when minimal effort allows us to do so. But the experiences I have from both before and after Node.js got all everywhere is the reason I'm looking for ways to make the options we have for working with WCs versus JS-land solutions like React Components more similar. Not because, in either case, we shouldn't try to dedupe, but rather because of the reality of day to day operations with second and third party dependencies and what I find my coworkers who come from more Node-ish backgrounds tend to find frustrating. It's something I could easily blather on about, but as you say, out of scope for this thread. |
Any ideas on how one would go about implementing a library of web-components written in Svelte in something like Storybook? This would allow us to write standardized web-components that are possible to just "drop-in" to any frontend project regardless of framework. We have a need for this at my company, we're currently using StencilJS but would like to switch to Svelte. |
Since this issue is closed, perhaps there should be another one for discussion of the broader notion of Svelte as a tool to emit a set of web components for consumption elsewhere. Beyond just the ability to do it for folks who are adjusting their own compiler set up, but full out-of-the-box support, bundles that load eagerly or lazily as desired, polyfill loading if desired, etc. Currently Stencil does a great job of all that stuff, for example. I can't think of any reason why a Svelte couldn't bring a similar developer experience. |
Yeah, that's exactly what I'm after. Svelte looks like a much nicer developer experience than Stencil has to offer. But the automatic bundling of web components is worth so much. |
Stencil was created with web components in mind. |
Did you find a solution? |
No, sorry, we're all in on Stencil and it's been alright. |
There are lots of ways to use Storybook with web components. IIRC, I've used:
But I don't think those particular modules are especially necessary to effectively use Storybook as a development environment or as a styleguide/documentation tool for web components. @storybook/react can support web components the same as any React app. Knobs work fine. Quality and speed of live reloading is entirely situational. Events and setting DOM properties takes a little wiring. |
I'd thought of this as a 'one day' feature, since custom elements aren't universally supported and we already have svelte-custom-elements. But then I started building an Electron app (where custom elements are supported), and started building a UI kit for it (because the nearest thing I could find, photonkit, appears to be abandoned and pertains to an older version of Electron), and it's one of those cases where custom elements really would be quite nice.
svelte-custom-elements sort of works, but it's suboptimal because
So I think we should add one of the following:
Maybe a component should be able to specify its own name, and
customelement: true
means 'use the component's self-declared name, or error if it doesn't have one', andcustomelement: 'x-foo'
means 'register this component is<x-foo>
whatever it calls itself'.Differences in input/output that I can think of:
<style>
tag need to get attached to every single instance's shadow DOM?)<slot>
elements would get rendered, andoptions.slots
would be ignored (because there would be nooptions
)fire
might need to wrapdispatchEvent
? Not sure if we'd want to mergeon
andaddEventListener
(i.e. mix DOM events together with component events). I think we might have to so that<my-thing on:myEvent='doSomething()'>
works. I guess we'd just disable bubbling by default, so that things don't get too wackyA few nice things that would come out of this:
set
,get
,observe
shared: true
so there'd be very little overheadAny thoughts?
The text was updated successfully, but these errors were encountered: