diff --git a/.changeset/red-kings-draw.md b/.changeset/red-kings-draw.md new file mode 100644 index 0000000000..56ce4afff3 --- /dev/null +++ b/.changeset/red-kings-draw.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +feat: more efficient code generation when referencing globals diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js index 98b9a3d7ec..57cdae0c66 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js @@ -4,7 +4,7 @@ import { get_rune } from '../../scope.js'; import * as e from '../../../errors.js'; import { get_parent, unwrap_optional } from '../../../utils/ast.js'; -import { is_known_safe_call, is_safe_identifier } from './shared/utils.js'; +import { is_pure, is_safe_identifier } from './shared/utils.js'; /** * @param {CallExpression} node @@ -150,7 +150,7 @@ export function CallExpression(node, context) { break; } - if (context.state.expression && !is_known_safe_call(node.callee, context)) { + if (context.state.expression && !is_pure(node.callee, context)) { context.state.expression.has_call = true; context.state.expression.has_state = true; } diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/MemberExpression.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/MemberExpression.js index 633275b63a..245a164c71 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/MemberExpression.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/MemberExpression.js @@ -1,7 +1,7 @@ /** @import { MemberExpression } from 'estree' */ /** @import { Context } from '../types' */ import * as e from '../../../errors.js'; -import { is_safe_identifier } from './shared/utils.js'; +import { is_pure, is_safe_identifier } from './shared/utils.js'; /** * @param {MemberExpression} node @@ -15,7 +15,7 @@ export function MemberExpression(node, context) { } } - if (context.state.expression) { + if (context.state.expression && !is_pure(node, context)) { context.state.expression.has_state = true; } diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/TaggedTemplateExpression.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/TaggedTemplateExpression.js index b079b67512..eacb8a342a 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/TaggedTemplateExpression.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/TaggedTemplateExpression.js @@ -1,13 +1,13 @@ /** @import { TaggedTemplateExpression, VariableDeclarator } from 'estree' */ /** @import { Context } from '../types' */ -import { is_known_safe_call } from './shared/utils.js'; +import { is_pure } from './shared/utils.js'; /** * @param {TaggedTemplateExpression} node * @param {Context} context */ export function TaggedTemplateExpression(node, context) { - if (context.state.expression && !is_known_safe_call(node.tag, context)) { + if (context.state.expression && !is_pure(node.tag, context)) { context.state.expression.has_call = true; context.state.expression.has_state = true; } diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/utils.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/utils.js index 2980ac3cbe..963882d396 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/utils.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/shared/utils.js @@ -4,7 +4,7 @@ /** @import { Scope } from '../../../scope' */ /** @import { NodeLike } from '../../../../errors.js' */ import * as e from '../../../../errors.js'; -import { extract_identifiers } from '../../../../utils/ast.js'; +import { extract_identifiers, object } from '../../../../utils/ast.js'; import * as w from '../../../../warnings.js'; /** @@ -167,24 +167,23 @@ export function is_safe_identifier(expression, scope) { } /** - * @param {Expression | Super} callee + * @param {Expression | Super} node * @param {Context} context * @returns {boolean} */ -export function is_known_safe_call(callee, context) { - // String / Number / BigInt / Boolean casting calls - if (callee.type === 'Identifier') { - const name = callee.name; - const binding = context.state.scope.get(name); - if ( - binding === null && - (name === 'BigInt' || name === 'String' || name === 'Number' || name === 'Boolean') - ) { - return true; - } +export function is_pure(node, context) { + if (node.type !== 'Identifier' && node.type !== 'MemberExpression') { + return false; } - // TODO add more cases + const left = object(node); + if (!left) return false; + + if (left.type === 'Identifier') { + const binding = context.state.scope.get(left.name); + if (binding === null) return true; // globals are assumed to be safe + } + // TODO add more cases (safe Svelte imports, etc) return false; } diff --git a/packages/svelte/tests/runtime-runes/samples/effect-tracking/main.svelte b/packages/svelte/tests/runtime-runes/samples/effect-tracking/main.svelte index bb48958880..1e2ea446a5 100644 --- a/packages/svelte/tests/runtime-runes/samples/effect-tracking/main.svelte +++ b/packages/svelte/tests/runtime-runes/samples/effect-tracking/main.svelte @@ -1,5 +1,5 @@ + +

{Math.max(min, Math.min(max, number))}

+

{location.href}

+ +