fix: hoist snippets above const in same block (#17516)

* fix: hoist snippets above const in same block

* fix: type error
pull/17518/head
Paolo Ricciuti 8 months ago committed by GitHub
parent c1fab8caae
commit d95887deb6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: hoist snippets above const in same block

@ -170,6 +170,7 @@ export function client_component(analysis, options) {
// these are set inside the `Fragment` visitor, and cannot be used until then // these are set inside the `Fragment` visitor, and cannot be used until then
init: /** @type {any} */ (null), init: /** @type {any} */ (null),
consts: /** @type {any} */ (null), consts: /** @type {any} */ (null),
snippets: /** @type {any} */ (null),
let_directives: /** @type {any} */ (null), let_directives: /** @type {any} */ (null),
update: /** @type {any} */ (null), update: /** @type {any} */ (null),
after_update: /** @type {any} */ (null), after_update: /** @type {any} */ (null),

@ -49,6 +49,8 @@ export interface ComponentClientTransformState extends ClientTransformState {
readonly update: Statement[]; readonly update: Statement[];
/** Stuff that happens after the render effect (control blocks, dynamic elements, bindings, actions, etc) */ /** Stuff that happens after the render effect (control blocks, dynamic elements, bindings, actions, etc) */
readonly after_update: Statement[]; readonly after_update: Statement[];
/** Transformed `{#snippets }` declarations */
readonly snippets: Statement[];
/** Transformed `{@const }` declarations */ /** Transformed `{@const }` declarations */
readonly consts: Statement[]; readonly consts: Statement[];
/** Transformed async `{@const }` declarations (if any) and those coming after them */ /** Transformed async `{@const }` declarations (if any) and those coming after them */

@ -1,13 +1,13 @@
/** @import { Expression, Statement } from 'estree' */ /** @import { Expression, Statement } from 'estree' */
/** @import { AST } from '#compiler' */ /** @import { AST } from '#compiler' */
/** @import { ComponentClientTransformState, ComponentContext } from '../types' */ /** @import { ComponentClientTransformState, ComponentContext } from '../types' */
import { TEMPLATE_FRAGMENT, TEMPLATE_USE_IMPORT_NODE } from '../../../../../constants.js';
import * as b from '#compiler/builders'; import * as b from '#compiler/builders';
import { TEMPLATE_FRAGMENT, TEMPLATE_USE_IMPORT_NODE } from '../../../../../constants.js';
import { clean_nodes, infer_namespace } from '../../utils.js'; import { clean_nodes, infer_namespace } from '../../utils.js';
import { transform_template } from '../transform-template/index.js'; import { transform_template } from '../transform-template/index.js';
import { Template } from '../transform-template/template.js';
import { process_children } from './shared/fragment.js'; import { process_children } from './shared/fragment.js';
import { build_render_statement, Memoizer } from './shared/utils.js'; import { build_render_statement, Memoizer } from './shared/utils.js';
import { Template } from '../transform-template/template.js';
/** /**
* @param {AST.Fragment} node * @param {AST.Fragment} node
@ -60,6 +60,7 @@ export function Fragment(node, context) {
const state = { const state = {
...context.state, ...context.state,
init: [], init: [],
snippets: [],
consts: [], consts: [],
let_directives: [], let_directives: [],
update: [], update: [],
@ -150,7 +151,7 @@ export function Fragment(node, context) {
} }
} }
body.push(...state.let_directives, ...state.consts); body.push(...state.snippets, ...state.let_directives, ...state.consts);
if (state.async_consts && state.async_consts.thunks.length > 0) { if (state.async_consts && state.async_consts.thunks.length > 0) {
body.push(b.var(state.async_consts.id, b.call('$.run', b.array(state.async_consts.thunks)))); body.push(b.var(state.async_consts.id, b.call('$.run', b.array(state.async_consts.thunks))));

@ -329,7 +329,7 @@ export function RegularElement(node, context) {
); );
/** @type {typeof state} */ /** @type {typeof state} */
const child_state = { ...state, init: [], update: [], after_update: [] }; const child_state = { ...state, init: [], update: [], after_update: [], snippets: [] };
for (const node of hoisted) { for (const node of hoisted) {
context.visit(node, child_state); context.visit(node, child_state);
@ -441,6 +441,7 @@ export function RegularElement(node, context) {
// Wrap children in `{...}` to avoid declaration conflicts // Wrap children in `{...}` to avoid declaration conflicts
context.state.init.push( context.state.init.push(
b.block([ b.block([
...child_state.snippets,
...child_state.init, ...child_state.init,
...element_state.init, ...element_state.init,
child_state.update.length > 0 ? build_render_statement(child_state) : b.empty, child_state.update.length > 0 ? build_render_statement(child_state) : b.empty,

@ -89,6 +89,6 @@ export function SnippetBlock(node, context) {
context.state.instance_level_snippets.push(declaration); context.state.instance_level_snippets.push(declaration);
} }
} else { } else {
context.state.init.push(declaration); context.state.snippets.push(declaration);
} }
} }

@ -77,7 +77,7 @@ export function SvelteBoundary(node, context) {
/** @type {Statement[]} */ /** @type {Statement[]} */
const statements = []; const statements = [];
context.visit(child, { ...context.state, init: statements }); context.visit(child, { ...context.state, snippets: statements });
const snippet = /** @type {VariableDeclaration} */ (statements[0]); const snippet = /** @type {VariableDeclaration} */ (statements[0]);

@ -333,7 +333,7 @@ export function build_component(node, component_name, loc, context) {
// can be used as props without creating conflicts // can be used as props without creating conflicts
context.visit(child, { context.visit(child, {
...context.state, ...context.state,
init: snippet_declarations snippets: snippet_declarations
}); });
push_prop(b.prop('init', child.expression, child.expression)); push_prop(b.prop('init', child.expression, child.expression));

@ -0,0 +1,5 @@
import { test } from '../../test';
export default test({
test() {}
});

@ -0,0 +1,4 @@
{#if true}
{@const xx = test}
{#snippet test()}{/snippet}
{/if}
Loading…
Cancel
Save