Svelte: Svelte component bundled with outros throws at runtime

Created on 20 Nov 2019  路  9Comments  路  Source: sveltejs/svelte

Describe the bug
When bundling a Svelte component into a module, then loading it dynamically, the outros function is missing and this causes a runtime error when the component is scheduled to unload.

To Reproduce
I created a live demo here:
https://practical-bartik-9883e1.netlify.com

The source is here:
https://github.com/caqu/import-svelte/tree/master/src
https://github.com/caqu/import-svelte/blob/master/rollup.config.js

The issue I see is rooted here on the generated code:
https://practical-bartik-9883e1.netlify.com/build/child_with_fade.js

...
let outros;
function transition_in(block, local) {
    if (block && block.i) {
        outroing.delete(block);
        block.i(local);
    }
}
const null_transition = { duration: 0 };
function create_out_transition(node, fn, params) {
    let config = fn(node, params);
    let running = true;
    let animation_name;
    const group = outros;                       // <------ Outros is undefined
    group.r += 1;

Logs

index.mjs:762 Uncaught (in promise) TypeError: Cannot read property 'r' of undefined
    at create_out_transition (index.mjs:762)
    at Object.o (index.mjs:51)
    at G (index.mjs:691)
    at Object.p (App.svelte:47)
    at q (index.mjs:638)
    at P (index.mjs:612)
create_out_transition @ index.mjs:762
o @ index.mjs:51
G @ index.mjs:691
p @ App.svelte:47
q @ index.mjs:638
P @ index.mjs:612
Promise.then (async)
V @ index.mjs:591
(anonymous) @ index.mjs:1337
remove_child_with_fade @ App.svelte:18

Expected behavior
I'm relatively new to Svelte and Rollup, so it's possible there's a config error in my Rollup file.

Severity
This seems to be an issue that's impacting many developers using dynamic imports and routing. I believe it may also be the root cause of:
https://github.com/sveltejs/svelte/issues/3448
https://github.com/sveltejs/svelte/issues/3165

Additional Context
The issue seems to appear when adding a < slot / > to the child component.

question

Most helpful comment

I just opened an old project, updated it to 3.18.1 (latest) and bumped into this.

A buggy version of npm is doing funky things and installing duplicate versions of Svelte all over the place. It had nothing to do with the Svelte version.


Stacktrace

Uncaught (in promise) TypeError: Cannot read property 'c' of undefined
    at transition_out (modules.js?hash=574e2833e0bc262823d4387523c68d3252981b3b:30598)
    at Object.outro [as o] (modules.js?hash=574e2833e0bc262823d4387523c68d3252981b3b:7980)
    at transition_out (index.mjs:717)
    at Object.outro [as o] (PageCreateProfile.svelte:77)
    at transition_out (index.mjs:717)
    at Object.outro [as o] (Nav.svelte:10)
    at transition_out (index.mjs:717)
    at Object.outro [as o] (PageCreateProfile.svelte:77)
    at transition_out (index.mjs:717)
    at Object.update [as p] (PageSignup.svelte:9)


Breaking code

function transition_out(block, local, detach, callback) {
    if (block && block.o) {
        if (outroing.has(block))
            return;
        outroing.add(block);
        outros.c.push(() => {  // <---- outros is undefined
            outroing.delete(block);
            if (callback) {
                if (detach)
                    block.d(1);
                callback();
            }
        });
        block.o(local);
    }
}

In my case, the error is thrown if the Svelte component imported from a package uses another components from the same package internally.

Well, it seems this pattern of including another component within the same package does bring out the bug, but it was still only caused by buggy npm installing duplicate versions of Svelte all over the place.

Nuking node_modules, downgrading npm and re-installing helped.

All 9 comments

I just opened an old project, updated it to 3.18.1 (latest) and bumped into this.

A buggy version of npm is doing funky things and installing duplicate versions of Svelte all over the place. It had nothing to do with the Svelte version.


Stacktrace

Uncaught (in promise) TypeError: Cannot read property 'c' of undefined
    at transition_out (modules.js?hash=574e2833e0bc262823d4387523c68d3252981b3b:30598)
    at Object.outro [as o] (modules.js?hash=574e2833e0bc262823d4387523c68d3252981b3b:7980)
    at transition_out (index.mjs:717)
    at Object.outro [as o] (PageCreateProfile.svelte:77)
    at transition_out (index.mjs:717)
    at Object.outro [as o] (Nav.svelte:10)
    at transition_out (index.mjs:717)
    at Object.outro [as o] (PageCreateProfile.svelte:77)
    at transition_out (index.mjs:717)
    at Object.update [as p] (PageSignup.svelte:9)


Breaking code

function transition_out(block, local, detach, callback) {
    if (block && block.o) {
        if (outroing.has(block))
            return;
        outroing.add(block);
        outros.c.push(() => {  // <---- outros is undefined
            outroing.delete(block);
            if (callback) {
                if (detach)
                    block.d(1);
                callback();
            }
        });
        block.o(local);
    }
}

In my case, the error is thrown if the Svelte component imported from a package uses another components from the same package internally.

Well, it seems this pattern of including another component within the same package does bring out the bug, but it was still only caused by buggy npm installing duplicate versions of Svelte all over the place.

Nuking node_modules, downgrading npm and re-installing helped.

Just hit this problem after moving our shared components out into its own modules. During development we're using npm link but webpack is getting two copies of svelte.

Found this writeup

https://medium.com/@penx/managing-dependencies-in-a-node-package-so-that-they-are-compatible-with-npm-link-61befa5aaca7

The TLDR; is, if you're using webpack and npm linking your components in, get them to resolve to the same version of svelte by adding this to your webpack config. This worked for me.

const path = require("path");

{
// usual webpack config +
resolve: { 
  alias:{
    "svelte":path.resolve(__dirname, "node_modules/svelte"),
    }
  }
}

In production we would just npm install the modules so they resolve svelte from the host project. The above change shouldn't break anything in the host project as that's where it'd look for svelte anyway.

I came across this issue, and I have been looking after it. I don't get the reason for the error yet.

I have checked all the possibilities pointed here and none of them helped.

  • resolve alias
  • nuking node_modules
  • only have 1 svelte version installed

I have wrote a lib @daniloster/svelte-i18n which is getting this error when is being consumed inside an if block.

{#if isOpen}
  <CustomComponent />
{/if}

CustomComponent.svelte

<div>
  <Literal {namespace} path="create"/>
</div>

When isOpen get value changed to false, the "outros"is undefined. No transitions (svelte/transition) have been added.

May I have some help with it, please?

I have checked the thread comment https://github.com/sveltejs/svelte/issues/3448#issuecomment-541386356

And I have changed the library to publish only babel transpilation + svelte file. This way, compilation will happen in the end-app.

Thanks everyone.

I've made a tiny component to use into project. (https://github.com/lagden/svelte-btn)
I found the same problems above, but I realized some interesting behavior.

In my case, the error only happens if I use a svelte component as child.
https://svelte.dev/repl/be4907a42a3f491b92e577c42fb7fb3a?version=3.22.2

REPL fragment code BtnDyn.svelte

<script>
  import Btn from '@tadashi/svelte-btn/dist/index.mjs'
  //... code stuff
</script>

<Btn class="{cssTheme} {className}" {...filtered} on:click>
  {#if icoName}
    <Icon name="ico_{icoName}" class="{_icon} {value ? _icon_margin : ''}" />
  {/if}
</Btn>

If you replace by pure HTML, the component will work!

<Btn class="{cssTheme} {className}" {...filtered} on:click>
  {#if icoName}
    <svg class="{_icon} {value ? _icon_margin : ''}">
      <use xlink:href="#residencial_ico_{icoName}" />
    </svg>
  {/if}
</Btn>

I think it's a bug, because the component and your children are render.
This should be analyzed. IMO.


Obs.:

If use import Btn from '@tadashi/svelte-btn will work because the main file in package.json is src/index.svelte

https://github.com/lagden/svelte-btn/blob/master/package.json#L24-L25

I can also confirm that this issues happens, in my case is by using svelte-routing with if conditions.
with Svelte 3.20.1 everything works but it fails with the changes added in Svelte 3.21.0.

Possible duplicated from https://github.com/sveltejs/svelte/issues/3448

@Egnus

The svelte-routing works fine and it's not a problem with if-statements!
This problem occurs when you use a svelte component (compiled) into slot.

Make a simple test, replace the content of if-statements by simple one:

{#if}
  <p>test</p>
{/if}

Is there anything going on here that's different from the many other issues that have been opened about problems that happen when there are two copies of the Svelte internals bundled into an app? This sounds to me like just another occurrence of that. You need to make sure the published component has a svelte field in it, and you need to make sure that the bundler is deduping instances of the svelte package so that there's only one copy of svelte/internals.

_Just a late night idea_: would be sweet, if Svelte had (at least in dev mode) a mechanism to detect multiple instances of Svelte's internals.

That would:

a) Reduce the amount of weird and non-existent bugs due to having two runtimes present
b) Prevent apps from breaking when accidentally shipping two runtimes for whatever reason

Was this page helpful?
0 / 5 - 0 ratings

Related issues

AntoninBeaufort picture AntoninBeaufort  路  3Comments

1u0n picture 1u0n  路  3Comments

matt3224 picture matt3224  路  3Comments

sskyy picture sskyy  路  3Comments

robnagler picture robnagler  路  3Comments