Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/two-frogs-hammer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"svelte": patch
---

feat: add support for svelte inspector
2 changes: 1 addition & 1 deletion packages/svelte/src/compiler/phases/2-analyze/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { DelegatedEvents, namespace_mathml, namespace_svg } from '../../../const
import { should_proxy_or_freeze } from '../3-transform/client/utils.js';
import { analyze_css } from './css/css-analyze.js';
import { prune } from './css/css-prune.js';
import { hash } from './utils.js';
import { hash } from '../../utils.js';
import { warn_unused } from './css/css-warn.js';
import { extract_svelte_ignore } from '../../utils/extract_svelte_ignore.js';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,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 { getLocator } from 'locate-character';

/**
* This function ensures visitor sets don't accidentally clobber each other
Expand Down Expand Up @@ -47,6 +48,7 @@ export function client_component(source, analysis, options) {
scopes: analysis.template.scopes,
hoisted: [b.import_all('$', 'svelte/internal/client')],
node: /** @type {any} */ (null), // populated by the root node
source_locator: getLocator(source, { offsetLine: 1 }),
// these should be set by create_block - if they're called outside, it's a bug
get before_init() {
/** @type {any[]} */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
import type { Namespace, SvelteNode, ValidatedCompileOptions } from '#compiler';
import type { TransformState } from '../types.js';
import type { ComponentAnalysis } from '../../types.js';
import type { Location } from 'locate-character';

export interface ClientTransformState extends TransformState {
readonly private_state: Map<string, StateField>;
Expand All @@ -28,6 +29,10 @@ export interface ComponentClientTransformState extends ClientTransformState {
readonly options: ValidatedCompileOptions;
readonly hoisted: Array<Statement | ModuleDeclaration>;
readonly events: Set<string>;
readonly source_locator: (
search: string | number,
index?: number | undefined
) => Location | undefined;

/** Stuff that happens before the render effect(s) */
readonly before_init: Statement[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,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 { hash } from '../../../../utils.js';

/**
* @param {import('#compiler').RegularElement | import('#compiler').SvelteElement} element
Expand Down Expand Up @@ -959,6 +960,17 @@ function serialize_bind_this(bind_this, context, node) {
return b.call('$.bind_this', ...args);
}

/**
* @param {import("estree").Expression[]} args
* @param {import("../types.js").ComponentClientTransformState} state
*/
function construct_append_method(args, state) {
if (state.options.dev && state.options.filename) {
args.push(b.literal(state.options.filename), b.literal('sloc' + hash(state.options.filename)));
}
return b.stmt(b.call('$.append', b.id('$$anchor'), ...args));
}

/**
* Creates a new block which looks roughly like this:
* ```js
Expand Down Expand Up @@ -1050,7 +1062,11 @@ function create_block(parent, name, nodes, context) {
);

body.push(b.var(id, b.call(template_name)), ...state.before_init, ...state.init);
close = b.stmt(b.call('$.append', b.id('$$anchor'), id));

/** @type {import('estree').Expression[]} */
const anchor_args = [id];

close = construct_append_method(anchor_args, state);
} else if (is_single_child_not_needing_template) {
context.visit(trimmed[0], state);
body.push(...state.before_init, ...state.init);
Expand All @@ -1071,7 +1087,11 @@ function create_block(parent, name, nodes, context) {
});

body.push(b.var(id, b.call('$.text', b.id('$$anchor'))), ...state.before_init, ...state.init);
close = b.stmt(b.call('$.append', b.id('$$anchor'), id));

/** @type {import('estree').Expression[]} */
const args = [id];

close = construct_append_method(args, state);
} else {
/** @type {(is_text: boolean) => import('estree').Expression} */
const expression = (is_text) =>
Expand Down Expand Up @@ -1107,7 +1127,10 @@ function create_block(parent, name, nodes, context) {

body.push(...state.before_init, ...state.init);

close = b.stmt(b.call('$.append', b.id('$$anchor'), id));
/** @type {import('estree').Expression[]} */
const args = [id];

close = construct_append_method(args, state);
}
} else {
body.push(...state.before_init, ...state.init);
Expand Down Expand Up @@ -1991,6 +2014,16 @@ export const template_visitors = {
serialize_class_directives(class_directives, node_id, context, is_attributes_reactive);
serialize_style_directives(style_directives, node_id, context, is_attributes_reactive);

if (context.state.options.dev && context.state.options.filename) {
const start = context.state.source_locator(node.start);

if (start) {
context.state.template.push(
` sloc${hash(context.state.options.filename)}="${start.line}:${start.column}"`
);
}
}

context.state.template.push('>');

/** @type {import('../types').ComponentClientTransformState} */
Expand Down
2 changes: 1 addition & 1 deletion packages/svelte/src/compiler/phases/3-transform/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function transform_component(analysis, source, options) {

const program =
options.generate === 'server'
? server_component(analysis, options)
? server_component(source, analysis, options)
: client_component(source, analysis, options);

const js_source_name = get_source_name(options.filename, options.outputFilename, 'input.svelte');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import { DOMBooleanAttributes, HYDRATION_END, HYDRATION_START } from '../../../.
import { escape_html } from '../../../../escaping.js';
import { sanitize_template_string } from '../../../utils/sanitize_template_string.js';
import { BLOCK_CLOSE, BLOCK_CLOSE_ELSE } from '../../../../internal/server/hydration.js';
import { getLocator } from 'locate-character';
import { hash } from '../../../utils.js';

export const block_open = t_string(`<!--${HYDRATION_START}-->`);
export const block_close = t_string(`<!--${HYDRATION_END}-->`);
Expand Down Expand Up @@ -1326,6 +1328,17 @@ const template_visitors = {

context.state.template.push(t_string(`<${node.name}`));
const body_expression = serialize_element_attributes(node, context);

if (context.state.options.dev && context.state.options.filename) {
const start = context.state.source_locator(node.start);

if (start) {
context.state.template.push(
t_string(` sloc${hash(context.state.options.filename)}="${start.line}:${start.column}"`)
);
}
}

context.state.template.push(t_string('>'));

/** @type {import('./types').ComponentServerTransformState} */
Expand Down Expand Up @@ -2091,18 +2104,20 @@ function serialize_style_directives(style_directives, style_attribute, context)
}

/**
* @param {string} source
* @param {import('../../types').ComponentAnalysis} analysis
* @param {import('#compiler').ValidatedCompileOptions} options
* @returns {import('estree').Program}
*/
export function server_component(analysis, options) {
export function server_component(source, analysis, options) {
/** @type {import('./types').ComponentServerTransformState} */
const state = {
analysis,
options,
scope: analysis.module.scope,
scopes: analysis.template.scopes,
hoisted: [b.import_all('$', 'svelte/internal/server')],
source_locator: getLocator(source, { offsetLine: 1 }),
legacy_reactive_statements: new Map(),
// these should be set by create_block - if they're called outside, it's a bug
get init() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type { SvelteNode, Namespace, ValidatedCompileOptions } from '#compiler';
import type { TransformState } from '../types.js';
import type { ComponentAnalysis } from '../../types.js';
import type { StateField } from '../client/types.js';
import type { Location } from 'locate-character';

export type TemplateExpression = {
type: 'expression';
Expand Down Expand Up @@ -47,6 +48,11 @@ export interface ComponentServerTransformState extends ServerTransformState {

readonly hoisted: Array<Statement | ModuleDeclaration>;

readonly source_locator: (
search: string | number,
index?: number | undefined
) => Location | undefined;

/** The SSR template */
readonly template: Template[];
readonly metadata: {
Expand Down
38 changes: 37 additions & 1 deletion packages/svelte/src/internal/client/dom/template.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { current_effect } from '../runtime.js';
import { TEMPLATE_FRAGMENT, TEMPLATE_USE_IMPORT_NODE } from '../../../constants.js';
import { effect } from '../reactivity/effects.js';
import { is_array } from '../utils.js';
import { DEV } from 'esm-env';

/**
* @template {import("#client").TemplateNode | import("#client").TemplateNode[]} T
Expand Down Expand Up @@ -33,6 +34,32 @@ export function push_template_node(
return dom;
}

/**
* @param {string} filename
* @param {import("#client").TemplateNode} target
* @param {string} filename_hash
*/
function attach_inspector_metadata(filename, target, filename_hash) {
const nodes = /** @type {Element} */ (target.parentElement).querySelectorAll(
`*[${filename_hash}]`
);
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
const loc = node.getAttribute(filename_hash)?.split(':');
node.removeAttribute(filename_hash);
if (loc) {
// @ts-expect-error
node.__svelte_meta = {
loc: {
file: filename,
line: loc[0],
column: loc[1]
}
};
}
}
}

/**
* @param {string} content
* @param {number} flags
Expand Down Expand Up @@ -258,9 +285,18 @@ export const comment = template('<!>', TEMPLATE_FRAGMENT);
* and insert the elements into the dom (in client mode).
* @param {Text | Comment | Element} anchor
* @param {import('#client').Dom} dom
* @param {string} [filename]
* @param {string} [filename_hash]
*/
export function append(anchor, dom) {
export function append(anchor, dom, filename, filename_hash) {
if (!hydrating) {
anchor.before(/** @type {Node} */ (dom));
}
if (DEV && filename && filename_hash) {
const target = hydrating ? (is_array(dom) ? dom[0] : dom) : anchor;

effect(() => {
attach_inspector_metadata(filename, target, filename_hash);
});
}
}
6 changes: 4 additions & 2 deletions packages/svelte/tests/runtime-legacy/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,14 +254,16 @@ async function run_test_variant(
}

if (variant === 'ssr') {
const html_without_loc_attributes = target.innerHTML.replace(/\s?sloc-?\S*\=\"\d*:\d*"/g, '');

if (config.ssrHtml) {
assert_html_equal_with_options(target.innerHTML, config.ssrHtml, {
assert_html_equal_with_options(html_without_loc_attributes, config.ssrHtml, {
preserveComments:
config.withoutNormalizeHtml === 'only-strip-comments' ? false : undefined,
withoutNormalizeHtml: !!config.withoutNormalizeHtml
});
} else if (config.html) {
assert_html_equal_with_options(target.innerHTML, config.html, {
assert_html_equal_with_options(html_without_loc_attributes, config.html, {
preserveComments:
config.withoutNormalizeHtml === 'only-strip-comments' ? false : undefined,
withoutNormalizeHtml: !!config.withoutNormalizeHtml
Expand Down
6 changes: 5 additions & 1 deletion playgrounds/demo/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';

export default defineConfig({
plugins: [svelte()],
plugins: [
svelte({
inspector: true
})
],
optimizeDeps: {
// svelte is a local workspace package, optimizing it would require dev server restarts with --force for every change
exclude: ['svelte']
Expand Down