Skip to content

RFC: Convention for packaged components to export uncompiled templates #604

Closed
@Rich-Harris

Description

@Rich-Harris

#586 and #603 highlight an interesting question. If a component nests another component that was compiled with a previous version of Svelte...

<Widget/>

<script>
  // node_modules/some-component-library/[pkg.main].js is precompiled
  import { Widget } from 'some-component-library';

  export default {
    components: { Widget }
  };
</script>

...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...

import { Widget } from 'some-component-library';

const widget = new Widget({
  target: document.querySelector('.widget-container')
});

...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:

{
  "main": "dist/some-component-library.umd.js",
  "module": "dist/some-component-library.esm.js",
  "svelte": "src/index.js",
  ...
}

A module-aware bundler (e.g. Rollup or Webpack) would import the pkg.module, a bundler like Browserify would import pkg.main.

But an app that was already using Svelte could import pkg.svelte, and any components re-exported from index.js would be compiled by the app's build process. This would be trivial to implement in rollup-plugin-svelte (just need to add a resolveId hook), and I assume it's possible in svelte-loader.

We could also resolve imports like this...

// resolves to node_modules/some-component-library/src/Widget.html
import Widget from 'some-component-library/Widget.html';

...by adding a "svelte.root": "src" property, analogous to "modules.root" in this document. (If the app author imported some-component-library/src/Widget.html directly, it would still work, assuming that the resolution logic saw that src/src/Widget.html didn't exist and fell back to not using pkg['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?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions