How can I compile a svelte component into a one line import for a pure HTML application?

1.2k views Asked by At

I have a svelte component that someone else wants to use on their own website, which is pure HTML/JavaScript.

My plan is for them to use a script tag referencing a cdn I host, like this:

<script src="http://examplecdn.com/myfile.js"></script>

Do I need to setup the project in a certain way to facilitate this? How do I find the file for the specific component? I can create a new project with just this component, but don't want to have to convert the code away from svelte.


For some context, for testing I have set up a basic svelte project with:

npm create svelte@latest my-example-module

And have just added this code to test if I can get something simple working:

<script lang="ts">
    let text = "IT IS WORKING"
</script>
<h1>{text}</h1>
<style>
    h1 {font-size: 3rem}
</style>

I ran npm run build, and have a lot of compiled javascript, but am not sure what a next step would be.

2

There are 2 answers

0
Daniel On

The svelte team is really pushing users to use sveltekit, and for a certain type of project that might be the way to go, but IMHO in many cases another approach might be better suited and much simpler.

You can try these steps instead:

start the project using vite and select svelete template

npm init vite

I selected these options

Need to install the following packages:
  create-vite
Ok to proceed? (y) y
√ Project name: ... vite-project
√ Select a framework: » Svelte
√ Select a variant: » JavaScript

Then you need to edit the vite.config.js file and add build options

import { defineConfig } from "vite";
import { svelte } from "@sveltejs/vite-plugin-svelte";
import { resolve } from "path";

export default defineConfig({
  plugins: [svelte()],
  build: {
    rollupOptions: {
      output: {
        format: "iife",
        dir: resolve(__dirname, "./dist"),
        entryFileNames: "main.js",
      },
    },
  },
});

I set to IIFE, but you can use any other format (es, cjs, umd etc) note that the default is setup to use modules, so you need to import it using type="module" :

<script type="module" crossorigin src="/main.js"></script>
0
Nickolay On

It's a bit confusing, but the npm create svelte command (i.e. the create-svelte npm package) creates a SvelteKit app, which (as of 2023-09) does not support your use-case out-of-the-box.

You can instead use a svelte-only template, as suggested by Daniel here or (once you start feeling comfortable with all this) add a custom vite config to a SvelteKit skeleton, as in this recipe for a svelte->webcomponent library.

The way you include svelte components in a pure HTML / vanilla JS page depends on how you build the components:

  • The arguably easier way is to output "web components" (as detailed in this only slightly outdated tutorial:
    • Put <svelte:options customElement="my-card" /> on top of the component's .svelte file
    • Put compilerOptions: { customElement: true, ... wherever they're specified in your setup
    • Include the produced JS bundle in your HTML via <script>
    • Use the custom element in your HTML: <my-card></my-card>
  • In the regular mode svelte produces JS classes which must be bound to the DOM elements manually (Client-side component API)

To elaborate on SvelteKit vs Svelte starter templates:

npm run build in a SvelteKit app builds the site, including the server and client JS for all pages (src/routes/*) (see Project structure).

As the official documentation on packaging puts it:

A component library has the exact same structure as a SvelteKit app, except that src/lib is the public-facing bit, and your root package.json is used to publish the package. src/routes might be a documentation or demo site that accompanies the library, or it might just be a sandbox you use during development.

If you select "Library project" in create-svelte:

create-svelte version 5.0.5

┌  Welcome to SvelteKit!
│
◇  Where should we create your project?
│  test
│
◆  Which Svelte app template?
│  ○ SvelteKit demo app
│  ○ Skeleton project
│  ● Library project (Barebones scaffolding for your new Svelte library)
└

...you'll end up with a slightly different setup, which includes a @sveltejs/package devDependency and a npm run package script, which runs svelte-package to build the components from the src/lib directory to a dist/ folder.

This gives you an npm package you can publish and/or install in other svelte apps, as it still contains .svelte files and relies on the destination app having a build step. There's https://github.com/sveltejs/kit/issues/2572 which proposes to extend svelte-package to produce JS bundle, which can be used in non-svelte apps.

But svelte projects not using the kit (e.g. started using the now-deprecated sveltejs/template or the newer create-vite svelte template) do not even have the "app" part, so their build step is much closer to what you need.