Closed Rich-Harris closed 3 years ago
I think it'd make more sense to just make the entire mounting/destroying API stable between versions. I'm sure there's some downsides to that though.
Yep, we should certainly strive to minimise breaking changes. #592 is a case where the current behaviour is buggy though, and we're offered a choice between fixing that bug or preventing breakage in edge cases involving precompiled components. And there's more surface area to consider than just unmount/destroy — #586 was about something unrelated.
So I definitely agree, but I think we have to have a strategy that allows for some flexibility in implementation details, and allowing packages to expose uncompiled components has that plus the additional size/performance benefits.
I like this idea.
I love Svelte for allowing me to publish a vanilla-JS component without charging a high framework-byte-size tax to anyone who wants to pull it into their Angular/React/whatever app.
On the other hand, I do feel slightly bad to be charging the few extra bytes for the folks who are bundling a Svelte app and want to minimize duplicating shared functions.
So, this is pretty great.
My only real contribution besides happiness is: you may want to respect pkg.engines.svelte
(see pkg.engines
) to allow folks to specify "svelte": "^3.0.0"
or whatever when they know their component isn't compatible with older versions.
Initial reactions:
NPM documentation seems to encourage us to do as much preprocessing as possible before publishing a package, basically to reduce the burden on the client. I believe this is why distributing, say, TypeScript source via NPM is often discouraged in favor of compiled JavaScript plus type definitions. So with regard to our component framework, I prefer to keep Svelte completely as an implementation detail and not bother the client with it at all if possible.
In some cases, our components require additional preprocessing (LESS, for example) before we hand the source off to Svelte to compile. This additional preprocessing is achieved through Webpack loaders. Most of the time, the client probably will be using Svelte, but usually its application components will not require all of the preprocessing that the framework components do. So it would be kind of unfortunate for the client to have to configure multiple Webpack loaders to compile our .html
source. Hopefully this makes sense.
But aside from these points, I actually would consider the interaction between Svelte components as more than an implementation detail. It is OK if the interaction changes, but to me they are public API and somehow must be detected so that we can properly version our components. But even at that, we still need the component package to be able to tell the client what versions of Svelte will emit code compatible with the component's API...almost like a peer dependency, except optional.
I'll have my colleague review this issue when he returns from vacation next week and see if he has any ideas to offer, and of course I'll also keep noodling on it myself. Otherwise, I'd suggest maybe we keep this issue open but wait on implementing a solution until we have more input...
Thanks guys and @Rich-Harris you da man!
Now that I think of it, one really big reason to distribute the original .svelte
files is so that you can use other renderers such as SSR.
Indeed I don't think we have to go out of the way to exclude the source or anything like that, but I think the NPM docs linked above are just trying to encourage us to reduce client burden.
As of version 2, rollup-plugin-svelte respects pkg.svelte
and pkg['svelte.root']
(README). Version mismatch warning and pkg.engines
support etc is on the TODO list.
A note regarding Webpack: I don't think svelte-loader requires any modification; rather, the Webpack configuration will need to specify "svelte"
in the resolve.mainFields
setting and avoid excluding node_modules
in the rule that applies svelte-loader.
Will webpack 4+ module types affect this? (svelte module type all the way up)
Sorry if this ancient issue isn't the place for this, but I couldn't find anything else open that discussed it — am I correct in thinking that there's currently no way of distributing compiled Svelte components? I think this is a dangerous step backwards in DX for distributed components/component libraries. As a basic example, I've authored a few Svelte components using typescript (both in the component and utils in .ts
files), which would now require every consumer of the component to setup both Svelte's typescript support and an ability to import typescript files.
No other large ecosystem that I know of on the web forces the bundling and tooling support onto the consumer. Seems like a big gotcha for authoring reusable Svelte components.
Pointers to issues related: https://github.com/sveltejs/component-template/issues/8 https://github.com/sveltejs/component-template/pull/31
We hope to address this with svelte/kit
.
Excellent to hear svelte/kit
will address this!
That would hopefully pave the way for more idiomatic usage of compiled svelte components in the wider ecosystem, assuming that whatever mechanism svelte/kit
uses is adaptable in other contexts?
As an aside, would svelte/kit
allow the use of webpack as a prod bundler for snowpack, since webpack/rollup are just plugins for snowpack? Because I've had nothing but trouble with rollup as an app bundler (as opposed to library bundler, which it excels at), and being forced to use it could be a dealbreaker for a lot of people. Something as simple as handling font files in CSS was a massive pain in rollup, and a one liner in Webpack.
I'm going to close this as implemented: https://kit.svelte.dev/docs#packaging
pkg.svelte
could possibly be referenced in the SvelteKit docs. Right now I only see it in https://github.com/sveltejs/rollup-plugin-svelte#pkgsvelte
586 and #603 highlight an interesting question. If a component nests another component that was compiled with a previous version of Svelte...
...it's more likely that changed internal implementation details (that are not considered, rightly or wrongly, part of the public API) will result in breakage.
At the same time, using precompiled components prevents us from sharing code effectively, resulting in larger bundles with functions that take longer to warm up.
So while it's certainly useful for
some-component-library
to ship precompiled components so that people can do this in non-Svelte apps......it would be great if bundler plugins could avoid precompiled code where possible.
Proposal:
pkg.svelte
Suppose the author of
some-component-library
included the following in her package.json:A module-aware bundler (e.g. Rollup or Webpack) would import the
pkg.module
, a bundler like Browserify would importpkg.main
.But an app that was already using Svelte could import
pkg.svelte
, and any components re-exported fromindex.js
would be compiled by the app's build process. This would be trivial to implement in rollup-plugin-svelte (just need to add aresolveId
hook), and I assume it's possible in svelte-loader.We could also resolve imports like this...
...by adding a
"svelte.root": "src"
property, analogous to"modules.root"
in this document. (If the app author importedsome-component-library/src/Widget.html
directly, it would still work, assuming that the resolution logic saw thatsrc/src/Widget.html
didn't exist and fell back to not usingpkg['svelte.root']
.Breaking changes
This wouldn't eliminate the possibility of breaking changes causing havoc — if a Svelte 3 app imported a Svelte 1 component which contained some long-since-deprecated syntax, the compilation would fail. But it gives us the opportunity to anticipate that breakage (the bundler plugin could compare the versions of Svelte that the app and the imported component depended on) and handle it at compile time with a helpful error message, rather than at runtime with a cryptic one.
Does this sound like a good idea? Is there anything obvious that I'm overlooking?