From 4b1b886855553baf8d9fd156606f931036628349 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 30 Jul 2024 20:50:57 -0400 Subject: [PATCH] chore: make `dev` state globally available (#12669) * make `dev` state globally available * tidy up --- .../3-transform/client/transform-client.js | 20 +++++----- .../phases/3-transform/client/utils.js | 16 ++++---- .../client/visitors/javascript-runes.js | 17 ++++----- .../3-transform/client/visitors/template.js | 38 ++++++++----------- .../compiler/phases/3-transform/css/index.js | 7 ++-- .../3-transform/server/transform-server.js | 10 ++--- .../3-transform/server/visitors/ClassBody.js | 6 +-- .../server/visitors/RegularElement.js | 6 +-- .../server/visitors/SvelteElement.js | 7 ++-- .../src/compiler/phases/3-transform/utils.js | 3 +- packages/svelte/src/compiler/state.js | 10 ++++- 11 files changed, 69 insertions(+), 71 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js index dbc7cd5ca8..c6ac88b0de 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js @@ -12,7 +12,7 @@ import { javascript_visitors_runes } from './visitors/javascript-runes.js'; import { javascript_visitors_legacy } from './visitors/javascript-legacy.js'; import { serialize_get_binding } from './utils.js'; import { render_stylesheet } from '../css/index.js'; -import { filename } from '../../../state.js'; +import { dev, filename } from '../../../state.js'; /** * This function ensures visitor sets don't accidentally clobber each other @@ -164,7 +164,7 @@ export function client_component(source, analysis, options) { store_setup.push( b.const( binding.node, - options.dev + dev ? b.thunk( b.sequence([ b.call('$.validate_store', store_reference, b.literal(name.slice(1))), @@ -210,7 +210,7 @@ export function client_component(source, analysis, options) { getter, b.set(alias ?? name, [b.stmt(b.assignment('=', expression, b.id('$$value')))]) ]; - } else if (!options.dev) { + } else if (!dev) { return b.init(alias ?? name, expression); } } @@ -238,7 +238,7 @@ export function client_component(source, analysis, options) { (binding.kind === 'prop' || binding.kind === 'bindable_prop') && !name.startsWith('$$') ); - if (analysis.runes && options.dev) { + if (dev && analysis.runes) { const exports = analysis.exports.map(({ name, alias }) => b.literal(alias ?? name)); /** @type {ESTree.Literal[]} */ const bindable = []; @@ -300,12 +300,12 @@ export function client_component(source, analysis, options) { ) ) ); - } else if (options.dev) { + } else if (dev) { component_returned_object.push(b.spread(b.call(b.id('$.legacy_api')))); } const push_args = [b.id('$$props'), b.literal(analysis.runes)]; - if (options.dev) push_args.push(b.id(analysis.name)); + if (dev) push_args.push(b.id(analysis.name)); const component_block = b.block([ ...store_setup, @@ -345,10 +345,10 @@ export function client_component(source, analysis, options) { } const should_inject_context = + dev || analysis.needs_context || analysis.reactive_statements.size > 0 || - component_returned_object.length > 0 || - options.dev; + component_returned_object.length > 0; if (should_inject_context) { component_block.body.unshift(b.stmt(b.call('$.push', ...push_args))); @@ -462,7 +462,7 @@ export function client_component(source, analysis, options) { body.push(b.export_default(component)); } - if (options.dev) { + if (dev) { if (filename) { // add `App[$.FILENAME] = 'App.svelte'` so that we can print useful messages later body.unshift( @@ -498,7 +498,7 @@ export function client_component(source, analysis, options) { ) ) ); - } else if (options.dev) { + } else if (dev) { component_block.body.unshift(b.stmt(b.call('$.check_target', b.id('new.target')))); } diff --git a/packages/svelte/src/compiler/phases/3-transform/client/utils.js b/packages/svelte/src/compiler/phases/3-transform/client/utils.js index 529318d4fc..825452fec8 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/utils.js @@ -16,6 +16,7 @@ import { PROPS_IS_RUNES, PROPS_IS_UPDATED } from '../../../../constants.js'; +import { dev } from '../../../state.js'; /** * @template {ClientTransformState} State @@ -212,7 +213,7 @@ export function serialize_set_binding(node, context, fallback, prefix, options) assignment.right = private_state.kind === 'frozen_state' ? b.call('$.freeze', value) - : serialize_proxy_reassignment(value, private_state.id, state); + : serialize_proxy_reassignment(value, private_state.id); return assignment; } } @@ -225,7 +226,7 @@ export function serialize_set_binding(node, context, fallback, prefix, options) should_proxy_or_freeze(value, context.state.scope) ? private_state.kind === 'frozen_state' ? b.call('$.freeze', value) - : serialize_proxy_reassignment(value, private_state.id, state) + : serialize_proxy_reassignment(value, private_state.id) : value ); } @@ -249,7 +250,7 @@ export function serialize_set_binding(node, context, fallback, prefix, options) assignment.right = public_state.kind === 'frozen_state' ? b.call('$.freeze', value) - : serialize_proxy_reassignment(value, public_state.id, state); + : serialize_proxy_reassignment(value, public_state.id); return assignment; } } @@ -317,7 +318,7 @@ export function serialize_set_binding(node, context, fallback, prefix, options) context.state.analysis.runes && !options?.skip_proxy_and_freeze && should_proxy_or_freeze(value, context.state.scope) - ? serialize_proxy_reassignment(value, left_name, state) + ? serialize_proxy_reassignment(value, left_name) : value ); } else if (binding.kind === 'frozen_state') { @@ -340,7 +341,7 @@ export function serialize_set_binding(node, context, fallback, prefix, options) !options?.skip_proxy_and_freeze && should_proxy_or_freeze(value, context.state.scope) && binding.kind === 'bindable_prop' - ? serialize_proxy_reassignment(value, left_name, state) + ? serialize_proxy_reassignment(value, left_name) : value ); } else { @@ -435,10 +436,9 @@ export function serialize_set_binding(node, context, fallback, prefix, options) /** * @param {Expression} value * @param {PrivateIdentifier | string} proxy_reference - * @param {ClientTransformState} state */ -export function serialize_proxy_reassignment(value, proxy_reference, state) { - return state.options.dev +export function serialize_proxy_reassignment(value, proxy_reference) { + return dev ? b.call( '$.proxy', value, diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/javascript-runes.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/javascript-runes.js index f24514a8f9..e8b8a20de4 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/javascript-runes.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/javascript-runes.js @@ -14,6 +14,7 @@ import { } from '../utils.js'; import { extract_paths } from '../../../../utils/ast.js'; import { regex_invalid_identifier_chars } from '../../../patterns.js'; +import { dev } from '../../../../state.js'; /** @type {ComponentVisitors} */ export const javascript_visitors_runes = { @@ -148,11 +149,7 @@ export const javascript_visitors_runes = { 'set', definition.key, [value], - [ - b.stmt( - b.call('$.set', member, serialize_proxy_reassignment(value, field.id, state)) - ) - ] + [b.stmt(b.call('$.set', member, serialize_proxy_reassignment(value, field.id)))] ) ); } @@ -170,7 +167,7 @@ export const javascript_visitors_runes = { ); } - if ((field.kind === 'derived' || field.kind === 'derived_call') && state.options.dev) { + if (dev && (field.kind === 'derived' || field.kind === 'derived_call')) { body.push( b.method( 'set', @@ -188,7 +185,7 @@ export const javascript_visitors_runes = { body.push(/** @type {MethodDefinition} **/ (visit(definition, child_state))); } - if (state.options.dev && public_state.size > 0) { + if (dev && public_state.size > 0) { // add an `[$.ADD_OWNER]` method so that a class with state fields can widen ownership body.push( b.method( @@ -248,7 +245,7 @@ export const javascript_visitors_runes = { /** @type {Expression[]} */ const args = [b.id('$$props'), b.array(seen.map((name) => b.literal(name)))]; - if (state.options.dev) { + if (dev) { // include rest name, so we can provide informative error messages args.push(b.literal(declarator.id.name)); } @@ -287,7 +284,7 @@ export const javascript_visitors_runes = { /** @type {Expression[]} */ const args = [b.id('$$props'), b.array(seen.map((name) => b.literal(name)))]; - if (state.options.dev) { + if (dev) { // include rest name, so we can provide informative error messages args.push(b.literal(/** @type {Identifier} */ (property.argument).name)); } @@ -474,7 +471,7 @@ export const javascript_visitors_runes = { BinaryExpression(node, { state, visit, next }) { const operator = node.operator; - if (state.options.dev) { + if (dev) { if (operator === '===' || operator === '!==') { return b.call( '$.strict_equals', diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js index fb995b4e90..dacb810b47 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js @@ -53,7 +53,7 @@ import { regex_is_valid_identifier } from '../../../patterns.js'; import { javascript_visitors_runes } from './javascript-runes.js'; import { sanitize_template_string } from '../../../../utils/sanitize_template_string.js'; import { walk } from 'zimmerframe'; -import { locator } from '../../../../state.js'; +import { dev, locator } from '../../../../state.js'; import is_reference from 'is-reference'; /** @@ -780,18 +780,14 @@ function serialize_inline_component(node, component_name, context, anchor = cont } else if (attribute.type === 'BindDirective') { const expression = /** @type {Expression} */ (context.visit(attribute.expression)); - if ( - expression.type === 'MemberExpression' && - context.state.options.dev && - context.state.analysis.runes - ) { + if (dev && expression.type === 'MemberExpression' && context.state.analysis.runes) { context.state.init.push(serialize_validate_binding(context.state, attribute, expression)); } if (attribute.name === 'this') { bind_this = attribute.expression; } else { - if (context.state.options.dev) { + if (dev) { binding_initializers.push( b.stmt(b.call(b.id('$.add_owner_effect'), b.thunk(expression), b.id(component_name))) ); @@ -894,9 +890,7 @@ function serialize_inline_component(node, component_name, context, anchor = cont push_prop( b.init( 'children', - context.state.options.dev - ? b.call('$.wrap_snippet', b.id(context.state.analysis.name), slot_fn) - : slot_fn + dev ? b.call('$.wrap_snippet', b.id(context.state.analysis.name), slot_fn) : slot_fn ) ); @@ -968,7 +962,7 @@ function serialize_inline_component(node, component_name, context, anchor = cont b.block([ ...binding_initializers, b.stmt( - context.state.options.dev + dev ? b.call('$.validate_dynamic_component', b.thunk(prev(b.id('$$anchor')))) : prev(b.id('$$anchor')) ) @@ -1696,7 +1690,7 @@ export const template_visitors = { */ const add_template = (template_name, args) => { let call = b.call(get_template_function(namespace, state), ...args); - if (context.state.options.dev) { + if (dev) { call = b.call( '$.add_locations', call, @@ -1837,7 +1831,7 @@ export const template_visitors = { // we need to eagerly evaluate the expression in order to hit any // 'Cannot access x before initialization' errors - if (state.options.dev) { + if (dev) { state.init.push(b.stmt(b.call('$.get', declaration.id))); } } else { @@ -1871,7 +1865,7 @@ export const template_visitors = { // we need to eagerly evaluate the expression in order to hit any // 'Cannot access x before initialization' errors - if (state.options.dev) { + if (dev) { state.init.push(b.stmt(b.call('$.get', tmp))); } @@ -1987,7 +1981,7 @@ export const template_visitors = { /** @type {SourceLocation} */ let location = [-1, -1]; - if (context.state.options.dev) { + if (dev) { const loc = locator(node.start); if (loc) { location[0] = loc.line; @@ -2370,7 +2364,7 @@ export const template_visitors = { const get_tag = b.thunk(/** @type {Expression} */ (context.visit(node.tag))); - if (context.state.options.dev && context.state.metadata.namespace !== 'foreign') { + if (dev && context.state.metadata.namespace !== 'foreign') { if (node.fragment.nodes.length > 0) { context.state.init.push(b.stmt(b.call('$.validate_void_dynamic_element', get_tag))); } @@ -2395,7 +2389,7 @@ export const template_visitors = { ).body ); - const location = context.state.options.dev && locator(node.start); + const location = dev && locator(node.start); context.state.init.push( b.stmt( @@ -2614,7 +2608,7 @@ export const template_visitors = { // we need to eagerly evaluate the expression in order to hit any // 'Cannot access x before initialization' errors - if (context.state.options.dev) { + if (dev) { declarations.push(b.stmt(getter)); } @@ -2641,7 +2635,7 @@ export const template_visitors = { declarations.push(b.let(node.index, index)); } - if (context.state.options.dev && (flags & EACH_KEYED) !== 0) { + if (dev && (flags & EACH_KEYED) !== 0) { context.state.init.push( b.stmt(b.call('$.validate_each_keys', b.thunk(collection), key_function)) ); @@ -2834,7 +2828,7 @@ export const template_visitors = { // we need to eagerly evaluate the expression in order to hit any // 'Cannot access x before initialization' errors - if (context.state.options.dev) { + if (dev) { declarations.push(b.stmt(getters[name])); } } @@ -2848,7 +2842,7 @@ export const template_visitors = { /** @type {Expression} */ let snippet = b.arrow(args, body); - if (context.state.options.dev) { + if (dev) { snippet = b.call('$.wrap_snippet', b.id(context.state.analysis.name), snippet); } @@ -2908,7 +2902,7 @@ export const template_visitors = { type === 'AwaitBlock' || type === 'KeyBlock' )) && - context.state.options.dev && + dev && context.state.analysis.runes ) { context.state.init.push( diff --git a/packages/svelte/src/compiler/phases/3-transform/css/index.js b/packages/svelte/src/compiler/phases/3-transform/css/index.js index ef9c61b79f..0b88a481a0 100644 --- a/packages/svelte/src/compiler/phases/3-transform/css/index.js +++ b/packages/svelte/src/compiler/phases/3-transform/css/index.js @@ -5,11 +5,11 @@ import MagicString from 'magic-string'; import { walk } from 'zimmerframe'; import { is_keyframes_node, regex_css_name_boundary, remove_css_prefix } from '../../css.js'; import { merge_with_preprocessor_map } from '../../../utils/mapped_code.js'; +import { dev } from '../../../state.js'; /** * @typedef {{ * code: MagicString; - * dev: boolean; * hash: string; * selector: string; * keyframes: string[]; @@ -31,7 +31,6 @@ export function render_stylesheet(source, analysis, options) { /** @type {State} */ const state = { code, - dev: options.dev, hash: analysis.css.hash, selector: `.${analysis.css.hash}`, keyframes: analysis.css.keyframes, @@ -60,7 +59,7 @@ export function render_stylesheet(source, analysis, options) { merge_with_preprocessor_map(css, options, css.map.sources[0]); - if (options.dev && options.css === 'injected' && css.code) { + if (dev && options.css === 'injected' && css.code) { css.code += `\n/*# sourceMappingURL=${css.map.toUrl()} */`; } @@ -122,7 +121,7 @@ const visitors = { Rule(node, { state, next, visit }) { // keep empty rules in dev, because it's convenient to // see them in devtools - if (!state.dev && is_empty(node)) { + if (!dev && is_empty(node)) { state.code.prependRight(node.start, '/* (empty) '); state.code.appendLeft(node.end, '*/'); escape_comment_close(node, state.code); diff --git a/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js b/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js index 2cc8a5b975..70d8c6c8be 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js @@ -6,7 +6,7 @@ import { walk } from 'zimmerframe'; import { set_scope } from '../../scope.js'; import { extract_identifiers } from '../../../utils/ast.js'; import * as b from '../../../utils/builders.js'; -import { filename } from '../../../state.js'; +import { dev, filename } from '../../../state.js'; import { render_stylesheet } from '../css/index.js'; import { AssignmentExpression } from './visitors/AssignmentExpression.js'; import { AwaitBlock } from './visitors/AwaitBlock.js'; @@ -269,10 +269,10 @@ export function server_component(analysis, options) { .../** @type {Statement[]} */ (template.body) ]); - let should_inject_context = analysis.needs_context || options.dev; + let should_inject_context = dev || analysis.needs_context; if (should_inject_context) { - component_block.body.unshift(b.stmt(b.call('$.push', options.dev && b.id(analysis.name)))); + component_block.body.unshift(b.stmt(b.call('$.push', dev && b.id(analysis.name)))); component_block.body.push(b.stmt(b.call('$.pop'))); } @@ -358,7 +358,7 @@ export function server_component(analysis, options) { ), b.export_default(b.id(analysis.name)) ); - } else if (options.dev) { + } else if (dev) { body.push( component_function, b.stmt( @@ -383,7 +383,7 @@ export function server_component(analysis, options) { body.push(b.export_default(component_function)); } - if (options.dev && filename) { + if (dev && filename) { // add `App[$.FILENAME] = 'App.svelte'` so that we can print useful messages later body.unshift( b.stmt( diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/ClassBody.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/ClassBody.js index 97484f71bc..27524b92a7 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/ClassBody.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/ClassBody.js @@ -1,6 +1,7 @@ /** @import { ClassBody, Expression, MethodDefinition, PropertyDefinition } from 'estree' */ /** @import { Context } from '../types.js' */ /** @import { StateField } from '../../client/types.js' */ +import { dev } from '../../../../state.js'; import * as b from '../../../../utils/builders.js'; import { get_rune } from '../../../scope.js'; @@ -92,10 +93,7 @@ export function ClassBodyRunes(node, context) { // get foo() { return this.#foo; } body.push(b.method('get', definition.key, [], [b.return(b.call(member))])); - if ( - (field.kind === 'derived' || field.kind === 'derived_call') && - context.state.options.dev - ) { + if (dev && (field.kind === 'derived' || field.kind === 'derived_call')) { body.push( b.method( 'set', diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js index 975038f3ac..0c5f81ae13 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js @@ -2,7 +2,7 @@ /** @import { RegularElement, Text } from '#compiler' */ /** @import { ComponentContext, ComponentServerTransformState } from '../types.js' */ /** @import { Scope } from '../../../scope.js' */ -import { locator } from '../../../../state.js'; +import { dev, locator } from '../../../../state.js'; import * as b from '../../../../utils/builders.js'; import { VoidElements } from '../../../constants.js'; import { clean_nodes, determine_namespace_for_children } from '../../utils.js'; @@ -55,7 +55,7 @@ export function RegularElement(node, context) { context.visit(node, state); } - if (state.options.dev) { + if (dev) { const location = /** @type {Location} */ (locator(node.start)); state.template.push( b.stmt( @@ -99,7 +99,7 @@ export function RegularElement(node, context) { state.template.push(b.literal(``)); } - if (state.options.dev) { + if (dev) { state.template.push(b.stmt(b.call('$.pop_element'))); } } diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/SvelteElement.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/SvelteElement.js index 35fda98235..ac30178ab0 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/SvelteElement.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/SvelteElement.js @@ -1,6 +1,7 @@ /** @import { BlockStatement, Expression } from 'estree' */ /** @import { SvelteElement } from '#compiler' */ /** @import { ComponentContext } from '../types.js' */ +import { dev } from '../../../../state.js'; import * as b from '../../../../utils/builders.js'; import { determine_namespace_for_children } from '../../utils.js'; import { serialize_element_attributes } from './shared/element.js'; @@ -18,7 +19,7 @@ export function SvelteElement(node, context) { tag = b.id(tag_id); } - if (context.state.options.dev) { + if (dev) { if (node.fragment.nodes.length > 0) { context.state.init.push(b.stmt(b.call('$.validate_void_dynamic_element', b.thunk(tag)))); } @@ -34,7 +35,7 @@ export function SvelteElement(node, context) { serialize_element_attributes(node, { ...context, state }); - if (context.state.options.dev) { + if (dev) { context.state.template.push(b.stmt(b.call('$.push_element', tag, b.id('$$payload')))); } @@ -53,7 +54,7 @@ export function SvelteElement(node, context) { ) ); - if (context.state.options.dev) { + if (dev) { context.state.template.push(b.stmt(b.call('$.pop_element'))); } } diff --git a/packages/svelte/src/compiler/phases/3-transform/utils.js b/packages/svelte/src/compiler/phases/3-transform/utils.js index d55c481f1f..11bd0acef2 100644 --- a/packages/svelte/src/compiler/phases/3-transform/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/utils.js @@ -14,6 +14,7 @@ import { extract_identifiers } from '../../utils/ast.js'; import check_graph_for_cycles from '../2-analyze/utils/check_graph_for_cycles.js'; import is_reference from 'is-reference'; import { set_scope } from '../scope.js'; +import { dev } from '../../state.js'; /** * @param {Node} node @@ -424,7 +425,7 @@ export function transform_inspect_rune(node, context) { const { state, visit } = context; const as_fn = state.options.generate === 'client'; - if (!state.options.dev) return b.unary('void', b.literal(0)); + if (!dev) return b.unary('void', b.literal(0)); if (node.callee.type === 'MemberExpression') { const raw_inspect_args = /** @type {CallExpression} */ (node.callee.object).arguments; diff --git a/packages/svelte/src/compiler/state.js b/packages/svelte/src/compiler/state.js index 459c9a56c3..13b6f95545 100644 --- a/packages/svelte/src/compiler/state.js +++ b/packages/svelte/src/compiler/state.js @@ -20,6 +20,12 @@ export let filename; */ export let source; +/** + * True if compiling with `dev: true` + * @type {boolean} + */ +export let dev; + export let locator = getLocator('', { offsetLine: 1 }); /** @type {NonNullable} */ @@ -61,13 +67,15 @@ export function reset_warning_filter(fn = () => true) { /** * @param {string} _source - * @param {{ filename?: string, rootDir?: string }} options + * @param {{ dev?: boolean; filename?: string; rootDir?: string }} options */ export function reset(_source, options) { source = _source; const root_dir = options.rootDir?.replace(/\\/g, '/'); filename = options.filename?.replace(/\\/g, '/'); + dev = !!options.dev; + if ( typeof filename === 'string' && typeof root_dir === 'string' &&