Skip to content

chore: tidy up server exports #10972

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 28, 2024
Merged
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
2 changes: 2 additions & 0 deletions packages/svelte/src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export const TRANSITION_GLOBAL = 1 << 2;
export const TEMPLATE_FRAGMENT = 1;
export const TEMPLATE_USE_IMPORT_NODE = 1 << 1;

export const UNINITIALIZED = Symbol();

/** List of Element events that will be delegated */
export const DelegatedEvents = [
'beforeinput',
Expand Down
54 changes: 30 additions & 24 deletions packages/svelte/src/index-server.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,37 @@
import { current_component_context } from './internal/client/runtime.js';

export {
createEventDispatcher,
flushSync,
getAllContexts,
getContext,
hasContext,
mount,
hydrate,
setContext,
tick,
unmount,
untrack
} from './index-client.js';

/** @returns {void} */
export function onMount() {}
import { current_component } from './internal/server/context.js';
import { noop } from './internal/shared/utils.js';

/** @param {() => void} fn */
export function onDestroy(fn) {
const context = /** @type {import('#client').ComponentContext} */ (current_component_context);
(context.ondestroy ??= []).push(fn);
var context = /** @type {import('#server').Component} */ (current_component);
(context.d ??= []).push(fn);
}

export {
noop as beforeUpdate,
noop as afterUpdate,
noop as onMount,
noop as flushSync,
run as untrack
} from './internal/shared/utils.js';

export function createEventDispatcher() {
return noop;
}

/** @returns {void} */
export function beforeUpdate() {}
export function mount() {
throw new Error('mount(...) is not available on the server');
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously it was possible to use client APIs and its runtime in a server context, assuming the Dom APIs are shimmed. This most likely happens when using test runners. Are we ok with this use case no longer being possible? (The test runner case would need adjustments for export conditions, if that doesn't happen already automatically)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this approach will lead to less confusion in general — if people expect mount to work without any configuration changes to their test runner or whatever, then they will probably expect things like unstate to work (which it won't), and things are very likely to break in future. This way, we force people to do things the right way from the get-go


export function hydrate() {
throw new Error('hydrate(...) is not available on the server');
}

/** @returns {void} */
export function afterUpdate() {}
export function unmount() {
throw new Error('unmount(...) is not available on the server');
}

export async function tick() {}

/**
* @template T
Expand All @@ -38,3 +42,5 @@ export function unstate(value) {
// There's no signals/proxies on the server, so just return the value
return value;
}

export { getAllContexts, getContext, hasContext, setContext } from './internal/server/context.js';
1 change: 0 additions & 1 deletion packages/svelte/src/internal/client/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,4 @@ export const DESTROYED = 1 << 12;
export const IS_ELSEIF = 1 << 13;
export const EFFECT_RAN = 1 << 14;

export const UNINITIALIZED = Symbol();
export const STATE_SYMBOL = Symbol('$state');
2 changes: 1 addition & 1 deletion packages/svelte/src/internal/client/dom/blocks/await.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { is_promise } from '../../../common.js';
import { is_promise } from '../../../shared/utils.js';
import {
current_component_context,
flush_sync,
Expand Down
2 changes: 1 addition & 1 deletion packages/svelte/src/internal/client/dom/blocks/key.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { UNINITIALIZED } from '../../constants.js';
import { UNINITIALIZED } from '../../../../constants.js';
import { block, branch, pause_effect } from '../../reactivity/effects.js';
import { safe_not_equal } from '../../reactivity/equality.js';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { noop } from '../../../common.js';
import { noop } from '../../../shared/utils.js';
import { effect } from '../../reactivity/effects.js';
import { current_effect, untrack } from '../../runtime.js';
import { raf } from '../../timing.js';
Expand Down
7 changes: 1 addition & 6 deletions packages/svelte/src/internal/client/dom/legacy/lifecycle.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { run_all } from '../../../common.js';
import { run, run_all } from '../../../shared/utils.js';
import { user_pre_effect, user_effect } from '../../reactivity/effects.js';
import {
current_component_context,
Expand All @@ -9,11 +9,6 @@ import {
untrack
} from '../../runtime.js';

/** @param {Function} fn */
function run(fn) {
return fn();
}

/**
* Legacy-mode only: Call `onMount` callbacks and set up `beforeUpdate`/`afterUpdate` effects
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/svelte/src/internal/client/dom/task.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { run_all } from '../../common.js';
import { run_all } from '../../shared/utils.js';

let is_task_queued = false;
let is_raf_queued = false;
Expand Down
16 changes: 9 additions & 7 deletions packages/svelte/src/internal/client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,15 +120,10 @@ export {
hasContext
} from './runtime.js';
export {
add_snippet_symbol,
validate_component,
validate_dynamic_component,
validate_dynamic_element_tag,
validate_each_keys,
validate_prop_bindings,
validate_snippet,
validate_store,
validate_void_dynamic_element
validate_store
} from './validate.js';
export { raf } from './timing.js';
export { proxy, unstate } from './proxy.js';
Expand All @@ -140,4 +135,11 @@ export {
$window as window,
$document as document
} from './dom/operations.js';
export { noop } from '../common.js';
export { noop } from '../shared/utils.js';
export {
add_snippet_symbol,
validate_component,
validate_dynamic_element_tag,
validate_snippet,
validate_void_dynamic_element
} from '../shared/validate.js';
3 changes: 2 additions & 1 deletion packages/svelte/src/internal/client/proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import {
} from './utils.js';
import { add_owner, check_ownership, strip_owner } from './dev/ownership.js';
import { mutable_source, source, set } from './reactivity/sources.js';
import { STATE_SYMBOL, UNINITIALIZED } from './constants.js';
import { STATE_SYMBOL } from './constants.js';
import { updating_derived } from './reactivity/deriveds.js';
import { UNINITIALIZED } from '../../constants.js';

/**
* @template T
Expand Down
2 changes: 1 addition & 1 deletion packages/svelte/src/internal/client/reactivity/effects.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
ROOT_EFFECT
} from '../constants.js';
import { set } from './sources.js';
import { noop } from '../../common.js';
import { noop } from '../../shared/utils.js';
import { remove } from '../dom/reconciler.js';

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/svelte/src/internal/client/reactivity/sources.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
current_effect,
current_untracked_writes,
current_untracking,
flush_sync,
get,
is_batching_effect,
is_runes,
Expand All @@ -18,7 +17,8 @@ import {
untrack
} from '../runtime.js';
import { equals, safe_equals } from './equality.js';
import { CLEAN, DERIVED, DIRTY, BRANCH_EFFECT, UNINITIALIZED } from '../constants.js';
import { CLEAN, DERIVED, DIRTY, BRANCH_EFFECT } from '../constants.js';
import { UNINITIALIZED } from '../../../constants.js';

/**
* @template V
Expand Down
18 changes: 9 additions & 9 deletions packages/svelte/src/internal/client/reactivity/store.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { subscribe_to_store } from '../../../store/utils.js';
import { noop } from '../../common.js';
import { UNINITIALIZED } from '../constants.js';
import { noop } from '../../shared/utils.js';
import { UNINITIALIZED } from '../../../constants.js';
import { get, untrack } from '../runtime.js';
import { effect } from './effects.js';
import { mutable_source, set } from './sources.js';
Expand All @@ -10,7 +10,7 @@ import { mutable_source, set } from './sources.js';
* signal that will be updated when the store is. The store references container is needed to
* track reassignments to stores and to track the correct component context.
* @template V
* @param {import('#client').Store<V> | null | undefined} store
* @param {import('#shared').Store<V> | null | undefined} store
* @param {string} store_name
* @param {import('#client').StoreReferencesContainer} stores
* @returns {V}
Expand Down Expand Up @@ -46,7 +46,7 @@ export function store_get(store, store_name, stores) {
* Unsubscribe from a store if it's not the same as the one in the store references container.
* We need this in addition to `store_get` because someone could unsubscribe from a store but
* then never subscribe to the new one (if any), causing the subscription to stay open wrongfully.
* @param {import('#client').Store<any> | null | undefined} store
* @param {import('#shared').Store<any> | null | undefined} store
* @param {string} store_name
* @param {import('#client').StoreReferencesContainer} stores
*/
Expand All @@ -65,7 +65,7 @@ export function store_unsub(store, store_name, stores) {

/**
* @template V
* @param {import('#client').Store<V> | null | undefined} store
* @param {import('#shared').Store<V> | null | undefined} store
* @param {import('#client').Source<V>} source
*/
function connect_store_to_signal(store, source) {
Expand All @@ -80,7 +80,7 @@ function connect_store_to_signal(store, source) {
/**
* Sets the new value of a store and returns that value.
* @template V
* @param {import('#client').Store<V>} store
* @param {import('#shared').Store<V>} store
* @param {V} value
* @returns {V}
*/
Expand Down Expand Up @@ -116,7 +116,7 @@ export function unsubscribe_on_destroy(stores) {

/**
* Updates a store with a new value.
* @param {import('#client').Store<V>} store the store to update
* @param {import('#shared').Store<V>} store the store to update
* @param {any} expression the expression that mutates the store
* @param {V} new_value the new store value
* @template V
Expand All @@ -127,7 +127,7 @@ export function mutate_store(store, expression, new_value) {
}

/**
* @param {import('#client').Store<number>} store
* @param {import('#shared').Store<number>} store
* @param {number} store_value
* @param {1 | -1} [d]
* @returns {number}
Expand All @@ -138,7 +138,7 @@ export function update_store(store, store_value, d = 1) {
}

/**
* @param {import('#client').Store<number>} store
* @param {import('#shared').Store<number>} store
* @param {number} store_value
* @param {1 | -1} [d]
* @returns {number}
Expand Down
3 changes: 1 addition & 2 deletions packages/svelte/src/internal/client/runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -1055,8 +1055,7 @@ export function push(props, runes = false, fn) {
l1: [],
l2: source(false),
// update_callbacks
u: null,
ondestroy: null
u: null
};

if (DEV) {
Expand Down
2 changes: 1 addition & 1 deletion packages/svelte/src/internal/client/timing.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { noop } from '../common.js';
import { noop } from '../shared/utils.js';

const is_client = typeof window !== 'undefined';

Expand Down
8 changes: 1 addition & 7 deletions packages/svelte/src/internal/client/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import type { Store } from '#shared';
import { STATE_SYMBOL } from './constants.js';
import type { Effect, Source, Value } from './reactivity/types.js';

type EventCallback = (event: Event) => boolean;
export type EventCallbackMap = Record<string, EventCallback | EventCallback[]>;

export type Store<V> = {
subscribe: (run: (value: V) => void) => () => void;
set(value: V): void;
};

// For all the core internal objects, we use single-character property strings.
// This not only reduces code-size and parsing, but it also improves the performance
// when the JS VM JITs the code.
Expand Down Expand Up @@ -43,8 +39,6 @@ export type ComponentContext = {
/** onMount callbacks */
m: Array<() => any>;
};
// TODO move this to a separate server component context object
ondestroy: null | Array<() => void>;
};

export type Equals = (this: Value, value: unknown) => boolean;
Expand Down
56 changes: 0 additions & 56 deletions packages/svelte/src/internal/client/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,27 +42,6 @@ export function validate_dynamic_component(component_fn) {
}
}

/**
* @param {() => string} tag_fn
* @returns {void}
*/
export function validate_void_dynamic_element(tag_fn) {
const tag = tag_fn();
if (tag && is_void(tag)) {
// eslint-disable-next-line no-console
console.warn(`<svelte:element this="${tag}"> is self-closing and cannot have content.`);
}
}

/** @param {() => unknown} tag_fn */
export function validate_dynamic_element_tag(tag_fn) {
const tag = tag_fn();
const is_string = typeof tag === 'string';
if (tag && !is_string) {
throw new Error('<svelte:element> expects "this" attribute to be a string.');
}
}

/**
* @param {() => any} collection
* @param {(item: any, index: number) => string} key_fn
Expand Down Expand Up @@ -103,41 +82,6 @@ export function loop_guard(timeout) {
};
}

const snippet_symbol = Symbol.for('svelte.snippet');

/**
* @param {any} fn
*/
export function add_snippet_symbol(fn) {
fn[snippet_symbol] = true;
return fn;
}

/**
* Validate that the function handed to `{@render ...}` is a snippet function, and not some other kind of function.
* @param {any} snippet_fn
*/
export function validate_snippet(snippet_fn) {
if (snippet_fn && snippet_fn[snippet_symbol] !== true) {
throw new Error(
'The argument to `{@render ...}` must be a snippet function, not a component or some other kind of function. ' +
'If you want to dynamically render one snippet or another, use `$derived` and pass its result to `{@render ...}`.'
);
}
return snippet_fn;
}

/**
* Validate that the function behind `<Component />` isn't a snippet.
* @param {any} component_fn
*/
export function validate_component(component_fn) {
if (component_fn?.[snippet_symbol] === true) {
throw new Error('A snippet must be rendered with `{@render ...}`');
}
return component_fn;
}

/**
* @param {Record<string, any>} $$props
* @param {string[]} bindable
Expand Down
Loading