Open qupig opened 4 months ago
Try finding out what exact version broke, that might help understand what changes were introduced in that version that could've broken you.
Try finding out what exact version broke, that might help understand what changes were introduced in that version that could've broken you.
Did I not write that clearly? The last version that worked was Svelte v4.2.0, I have tried lot of subsequent versions and the latest version, but they are all broken.
I spent an extra 2 hours checking and testing and finally locked the issue at #9122.
I tested two local builds https://github.com/sveltejs/svelte/compare/6aca6127ca51ec95ea95b420c759f1ea27f4e180...115ea1ff4afc57766f06bb8d9444ec59d00bc0e1 is before and after this PR and confirmed that this is where the problem started.
It looks like this PR fixed a bug but didn't take into account that blocks using module variables are still reactive.
I can fix the error in my project now, but I think this should be handled accordingly in Svelte as well.
If it helps, this is where I found the error being thrown when debugging in the browser:
(Please note the two // ==========>
comments I added)
/node_modules/svelte/src/runtime/internal/scheduler.js
/** @returns {void} */
export function flush() {
// Do not reenter flush while dirty components are updated, as this can
// result in an infinite loop. Instead, let the inner flush handle it.
// Reentrancy is ok afterwards for bindings etc.
if (flushidx !== 0) {
return;
}
const saved_component = current_component;
do {
// first, call beforeUpdate functions
// and update components
try {
while (flushidx < dirty_components.length) {
const component = dirty_components[flushidx];
flushidx++;
set_current_component(component);
update(component.$$);
}
} catch (e) {
// reset dirty state to not end up in a deadlocked state and then rethrow
dirty_components.length = 0;
flushidx = 0;
throw e; // ==========> throw the issue error!!!
}
set_current_component(null);
dirty_components.length = 0;
flushidx = 0;
while (binding_callbacks.length) binding_callbacks.pop()();
// then, once components are updated, call
// afterUpdate functions. This may cause
// subsequent updates...
for (let i = 0; i < render_callbacks.length; i += 1) {
const callback = render_callbacks[i];
if (!seen_callbacks.has(callback)) {
// ...so guard against infinite loops
seen_callbacks.add(callback);
callback();
}
}
render_callbacks.length = 0;
} while (dirty_components.length);
while (flush_callbacks.length) {
flush_callbacks.pop()();
}
update_scheduled = false;
seen_callbacks.clear();
set_current_component(saved_component);
}
/** @returns {void} */
function update($$) {
if ($$.fragment !== null) {
$$.update();
run_all($$.before_update);
const dirty = $$.dirty;
$$.dirty = [-1];
$$.fragment && $$.fragment.p($$.ctx, dirty); // ==========> The actual line of code where the error occurred
$$.after_update.forEach(add_render_callback);
}
}
And I can see that just before the error is thrown, $$.fragment.p
is:
function update(ctx, [dirty]) {
if (moduleVariable) if_block.p(ctx, dirty);
}
And then there is the error message in the console:
Unhandled Promise Rejection: TypeError: undefined is not an object (evaluating 'if_block.p')
Ok, now I know where the problem is, the moduleVariable
is a module variable and since it loses reactivity in PR #9122, the if_block
is not instantiated so it is undefined
.
So the question becomes, if moduleVariable
is not reactive, why is if_block
being updated? You should also eliminate the reactivity and proxies for {#if moduleVariable}
block that use module variables.
Finally able to make a minimal reproduction: StackBlitz-Svelte-4.2.15-Reproduction
It can also be reproduced in Svelte4-REPL, but since it requires a login to share... Please copy the following code yourself:
App.svelte
<script>
import Comp1 from "./Comp1.svelte";
import { writable } from "svelte/store";
const store = writable();
let comp;
function buttonClick() {
comp.test();
$store = 1;
}
</script>
<button on:click={buttonClick}>open console first, then click me</button>
<Comp1 bind:this={comp} {store}/>
Comp1.svelte
<script context="module">
let moduleVariable = false;
</script>
<script>
import Comp2 from "./Comp2.svelte";
export function test() {
moduleVariable = true;
}
export let store;
console.log($store);
</script>
<h1>Hello!</h1>
{#if moduleVariable}
<Comp2 {moduleVariable} />
{/if}
Comp2.svelte
(just a empty file)
Describe the bug
The last
Svelte
version that worked properly was v4.2.0, and after upgrading to later versions including the latest v4.2.12, I encountered the following error:I tried tracing and debugging the error and didn't get any valuable information, I'm not familiar with the internal workings of svelte.
Any help or what I can try to do?
Reproduction
This is a complex project that I can't currently separate and make a minimal reproducible demo, because I can't pinpoint the part where the problem occurs.
If there's some help or guidance, maybe I can isolate or locate that wrong part.
Logs
No response
System Info
Severity
blocking an upgrade