Uncaught Error: ‘target’ is a required option – Svelte

Total
4
Shares

I’m building an NPM package for Svelte. With this package I export a couple of simple components:

import SLink from './SLink.svelte';
import SView from './SView.svelte';

export { SLink, SView };

This is before bundling them to a minified version using rollup.

Rollup config:

module.exports = {
    input: 'src/router/index.ts',
    output: {
        file: pkg.main,
        format: 'umd',
        name: 'Router',
        sourcemap: true,
    },
    plugins: [
        svelte({
            format: 'umd',
            preprocess: sveltePreprocess(),
        }),
        resolve(),
        typescript(),
        terser(),
    ],
};

package.json (minus unnecessary info):

{
    "name": "svelte-dk-router",
    "version": "0.1.29",
    "main": "dist/router.umd.min.js",
    "scripts": {
        "lib": "rollup -c lib.config.js",
    },
    "peerDependencies": {
        "svelte": "^3.0.0"
    },
    "files": [
        "dist/router.umd.min.js"
    ],
}

When I publish the package and test it, I get this error:

Uncaught Error: 'target' is a required option
    at new SvelteComponentDev (index.mjs:1642)
    at new Home (App.svelte:5)
    at Z (router.umd.min.js:1)
    at N (router.umd.min.js:1)
    at new t.SView (router.umd.min.js:1)
    at create_fragment (App.svelte:5)
    at init (index.mjs:1476)
    at new App (App.svelte:5)
    at main.js:7
    at main.js:9

Which seems to be something to do with mounting the component as target is used to mount:

const app = new App({ target: document.body })

The odd thing is, SLink on it’s own works fine, mounts as it should etc., it’s just SView that doesn’t work.

SLink:

<script lang="ts">
    import { writableRoute, changeRoute } from '../logic';

    export let name: string = undefined,
        path: string = undefined,
        query: Record<string, string> = undefined,
        params: Record<string, string> = undefined;

    let routerActive: boolean;

    writableRoute.subscribe(newRoute => {
        if (newRoute.path === '*') return;
        const matches = (path && path.match(newRoute.regex)) || newRoute.name === name;
        routerActive = matches ? true : false;
    });
</script>

<div
    on:click={() => changeRoute({ name, path, query, params })}
    class={routerActive ? 'router-active' : ''}>
    <slot />
</div>

SView:

<script lang="ts">
    import { writableRoute } from '../logic';

    let component: any;

    writableRoute.subscribe(newRoute => (component = newRoute ? newRoute.component : null));
</script>

<svelte:component this={component} />

I’ve tried the components uncompiled, as per these docs, but then the imports don’t work.

Anyone have any idea how I can work around this issue?


Solution

All components in a Svelte tree need to be compiled with the same Svelte compiler (i.e. same node_modules/svelte) all at once. This includes components from external libs like what you are trying to achieve. This is what is explained in the docs you’ve linked.

The main field of the package.json will expose the compiled components, for usage in a non Svelte app.

You also need a svelte field to expose the uncompiled version of the components, for consumption by a Svelte app. You can still export multiple Svelte components from a .js file.

package.json

{
    "name": "svelte-dk-router",
    "version": "0.1.29",
    "main": "dist/router.umd.min.js",

    "svelte": "src/index.js",

    "scripts": {
        "lib": "rollup -c lib.config.js",
    },
    "peerDependencies": {
        "svelte": "^3.0.0"
    },
    "files": [
        "dist/router.umd.min.js"
    ],
}

src/index.js

import SLink from './SLink.svelte';
import SView from './SView.svelte';

export { SLink, SView };

rollup-plugin-svelte will pick up the svelte field in your lib’s package.json, so that import of Svelte components resolve correctly.

Leave a Reply

Your email address will not be published. Required fields are marked *