chore: move option under experimental

pull/18058/head
paoloricciuti 5 months ago
parent f91c2fd6d8
commit b4cf3d0a71

@ -28,7 +28,11 @@ export function compile(source, options) {
let parsed = _parse(source); let parsed = _parse(source);
const { customElement: customElementOptions, ...parsed_options } = parsed.options || {}; const {
customElement: customElementOptions,
customRenderer,
...parsed_options
} = parsed.options || {};
/** @type {ValidatedCompileOptions} */ /** @type {ValidatedCompileOptions} */
const combined_options = { const combined_options = {
@ -36,7 +40,11 @@ export function compile(source, options) {
...parsed_options, ...parsed_options,
customElementOptions, customElementOptions,
css: 'css' in parsed_options ? () => parsed_options.css ?? 'external' : validated.css, css: 'css' in parsed_options ? () => parsed_options.css ?? 'external' : validated.css,
runes: 'runes' in parsed_options ? () => parsed_options.runes : validated.runes runes: 'runes' in parsed_options ? () => parsed_options.runes : validated.runes,
experimental: {
...validated.experimental,
...(customRenderer !== undefined ? { customRenderer } : {})
}
}; };
if (parsed.metadata.ts) { if (parsed.metadata.ts) {

@ -60,7 +60,7 @@ export function Attribute(node, context) {
} }
// we can't delegate event handlers in a non dom environment // we can't delegate event handlers in a non dom environment
if (!context.state.options.customRenderer) { if (!context.state.options.experimental.customRenderer) {
node.metadata.delegated = node.metadata.delegated =
parent?.type === 'RegularElement' && can_delegate_event(node.name.slice(2)); parent?.type === 'RegularElement' && can_delegate_event(node.name.slice(2));
} }

@ -112,7 +112,7 @@ export function RegularElement(node, context) {
// We mark the subtree as dynamic so parent elements properly include the child init code // We mark the subtree as dynamic so parent elements properly include the child init code
if ( if (
(is_customizable_select_element(node) || node.name === 'selectedcontent') && (is_customizable_select_element(node) || node.name === 'selectedcontent') &&
!context.state.options.customRenderer !context.state.options.experimental.customRenderer
) { ) {
// Mark the element's own fragment as dynamic so it's not treated as static // Mark the element's own fragment as dynamic so it's not treated as static
node.fragment.metadata.dynamic = true; node.fragment.metadata.dynamic = true;

@ -139,12 +139,10 @@ const visitors = {
}; };
/** /**
* @param {string} custom_renderer_module * @param {string | undefined} custom_renderer_module
*/ */
function custom_renderer_imports(custom_renderer_module) { function custom_renderer_imports(custom_renderer_module) {
const imports = [ const imports = [b.import_all('$', 'svelte/internal/client')];
b.import_all('$', 'svelte/internal/client'),
]
if (custom_renderer_module) { if (custom_renderer_module) {
imports.push(b.imports([['$renderer', '$renderer', true]], custom_renderer_module)); imports.push(b.imports([['$renderer', '$renderer', true]], custom_renderer_module));
} }
@ -165,7 +163,8 @@ export function client_component(analysis, options) {
scopes: analysis.module.scopes, scopes: analysis.module.scopes,
is_instance: false, is_instance: false,
hoisted: [ hoisted: [
...custom_renderer_imports(options.customRenderer), ...analysis.instance_body.hoisted ...custom_renderer_imports(options.experimental.customRenderer),
...analysis.instance_body.hoisted
], ],
node: /** @type {any} */ (null), // populated by the root node node: /** @type {any} */ (null), // populated by the root node
legacy_reactive_imports: [], legacy_reactive_imports: [],
@ -407,7 +406,7 @@ export function client_component(analysis, options) {
); );
} }
if (options.customRenderer) { if (options.experimental.customRenderer) {
component_block.body.unshift( component_block.body.unshift(
b.var('$$pop_renderer', b.call('$.push_renderer', b.id('$renderer'))) b.var('$$pop_renderer', b.call('$.push_renderer', b.id('$renderer')))
); );
@ -586,7 +585,7 @@ export function client_component(analysis, options) {
// disclose version attach the svelte version to `window` which is not guaranteed // disclose version attach the svelte version to `window` which is not guaranteed
// to be a thing in custom renderers environments // to be a thing in custom renderers environments
if (options.discloseVersion && !options.customRenderer) { if (options.discloseVersion && !options.experimental.customRenderer) {
body.unshift(b.imports([], 'svelte/internal/disclose-version')); body.unshift(b.imports([], 'svelte/internal/disclose-version'));
} }

@ -36,7 +36,7 @@ function build_locations(nodes) {
*/ */
export function transform_template(state, namespace, flags = 0) { export function transform_template(state, namespace, flags = 0) {
// custom renderers needs a tree to work because there's no template element we can use // custom renderers needs a tree to work because there's no template element we can use
const tree = state.options.fragments === 'tree' || !!state.options.customRenderer; const tree = state.options.fragments === 'tree' || !!state.options.experimental.customRenderer;
const expression = tree ? state.template.as_tree() : state.template.as_html(); const expression = tree ? state.template.as_tree() : state.template.as_html();

@ -41,7 +41,7 @@ export function RegularElement(node, context) {
const is_html = const is_html =
context.state.metadata.namespace === 'html' && context.state.metadata.namespace === 'html' &&
node.name !== 'svg' && node.name !== 'svg' &&
!context.state.options.customRenderer; !context.state.options.experimental.customRenderer;
const name = is_html ? node.name.toLowerCase() : node.name; const name = is_html ? node.name.toLowerCase() : node.name;
context.state.template.push_element(name, node.start, is_html); context.state.template.push_element(name, node.start, is_html);
@ -51,7 +51,8 @@ export function RegularElement(node, context) {
} }
// we never treat elements as custom element in custom renderers, since we don't want to apply special handling to them (e.g. class merging) // we never treat elements as custom element in custom renderers, since we don't want to apply special handling to them (e.g. class merging)
const is_custom_element = is_custom_element_node(node) && !context.state.options.customRenderer; const is_custom_element =
is_custom_element_node(node) && !context.state.options.experimental.customRenderer;
// cloneNode is faster, but it does not instantiate the underlying class of the // cloneNode is faster, but it does not instantiate the underlying class of the
// custom element until the template is connected to the dom, which would // custom element until the template is connected to the dom, which would
@ -257,7 +258,7 @@ export function RegularElement(node, context) {
if (name !== 'class' || value) { if (name !== 'class' || value) {
context.state.template.set_prop(attribute.name, value === true ? '' : value); context.state.template.set_prop(attribute.name, value === true ? '' : value);
} }
} else if (name === 'autofocus' && !context.state.options.customRenderer) { } else if (name === 'autofocus' && !context.state.options.experimental.customRenderer) {
let { value } = build_attribute_value(attribute.value, context); let { value } = build_attribute_value(attribute.value, context);
context.state.init.push(b.stmt(b.call('$.autofocus', node_id, value))); context.state.init.push(b.stmt(b.call('$.autofocus', node_id, value)));
} else if (name === 'class') { } else if (name === 'class') {
@ -279,7 +280,7 @@ export function RegularElement(node, context) {
name, name,
value, value,
attributes, attributes,
!!context.state.options.customRenderer !!context.state.options.experimental.customRenderer
); );
(has_state ? context.state.update : context.state.init).push(b.stmt(update)); (has_state ? context.state.update : context.state.init).push(b.stmt(update));
@ -356,7 +357,7 @@ export function RegularElement(node, context) {
const empty_string = value.type === 'Literal' && value.value === ''; const empty_string = value.type === 'Literal' && value.value === '';
if (!empty_string) { if (!empty_string) {
if (context.state.options.customRenderer) { if (context.state.options.experimental.customRenderer) {
// custom renderers need to use the method to invoke the renderer // custom renderers need to use the method to invoke the renderer
context.state.template.push_text([ context.state.template.push_text([
{ {
@ -376,7 +377,10 @@ export function RegularElement(node, context) {
); );
} }
} }
} else if (is_customizable_select_element(node) && !context.state.options.customRenderer) { } else if (
is_customizable_select_element(node) &&
!context.state.options.experimental.customRenderer
) {
// For <option>, <optgroup>, or <select> elements with rich content, we need to branch based on browser support. // For <option>, <optgroup>, or <select> elements with rich content, we need to branch based on browser support.
// Modern browsers preserve rich HTML in options, older browsers strip it to text only. // Modern browsers preserve rich HTML in options, older browsers strip it to text only.
// We create a separate template for the rich content and append it to the element. // We create a separate template for the rich content and append it to the element.

@ -83,7 +83,7 @@ export function process_children(nodes, initial, is_element, context) {
if (has_state && !within_bound_contenteditable) { if (has_state && !within_bound_contenteditable) {
context.state.update.push(update); context.state.update.push(update);
} else { } else {
if (context.state.options.customRenderer) { if (context.state.options.experimental.customRenderer) {
// custom renderers need to use the method to invoke the renderer // custom renderers need to use the method to invoke the renderer
context.state.init.push(update); context.state.init.push(update);
} else { } else {

@ -110,7 +110,10 @@ export function RegularElement(node, context) {
const [attributes, ...rest] = prepare_element_spread_object(node, context, optimiser.transform); const [attributes, ...rest] = prepare_element_spread_object(node, context, optimiser.transform);
if (is_customizable_select_element(node) && !context.state.options.customRenderer) { if (
is_customizable_select_element(node) &&
!context.state.options.experimental.customRenderer
) {
rest.push(b.true); rest.push(b.true);
} }
@ -157,7 +160,10 @@ export function RegularElement(node, context) {
const [attributes, ...rest] = prepare_element_spread_object(node, context, optimiser.transform); const [attributes, ...rest] = prepare_element_spread_object(node, context, optimiser.transform);
if (is_customizable_select_element(node) && !context.state.options.customRenderer) { if (
is_customizable_select_element(node) &&
!context.state.options.experimental.customRenderer
) {
rest.push(b.true); rest.push(b.true);
} }
@ -195,7 +201,7 @@ export function RegularElement(node, context) {
if ( if (
(name === 'optgroup' || name === 'select') && (name === 'optgroup' || name === 'select') &&
is_customizable_select_element(node) && is_customizable_select_element(node) &&
!context.state.options.customRenderer !context.state.options.experimental.customRenderer
) { ) {
state.template.push(b.literal('<!>')); state.template.push(b.literal('<!>'));
} }

@ -136,10 +136,6 @@ export interface CompileOptions extends ModuleCompileOptions {
* @since 5.33 * @since 5.33
*/ */
fragments?: 'html' | 'tree'; fragments?: 'html' | 'tree';
/**
* Path to a module that exports the custom renderer to use. When this is truthy templating mode will also be automatically set to `functional`
*/
customRenderer?: string;
/** /**
* Set to `true` to force the compiler into runes mode, even if there are no indications of runes usage. * Set to `true` to force the compiler into runes mode, even if there are no indications of runes usage.
* Set to `false` to force the compiler into ignoring runes, even if there are indications of runes usage. * Set to `false` to force the compiler into ignoring runes, even if there are indications of runes usage.
@ -242,6 +238,10 @@ export interface ModuleCompileOptions {
* @since 5.36 * @since 5.36
*/ */
async?: boolean; async?: boolean;
/**
* Path to a module that exports the custom renderer to use. When this is truthy templating mode will also be automatically set to `functional`
*/
customRenderer?: string;
}; };
} }

@ -44,7 +44,8 @@ const common_options = {
warningFilter: fun(() => true), warningFilter: fun(() => true),
experimental: object({ experimental: object({
async: boolean(false) async: boolean(false),
customRenderer: string(undefined)
}) })
}; };
@ -97,8 +98,6 @@ const component_options = {
immutable: deprecate(w.options_deprecated_immutable, boolean(false)), immutable: deprecate(w.options_deprecated_immutable, boolean(false)),
customRenderer: string(undefined),
legacy: removed( legacy: removed(
'The legacy option has been removed. If you are using this because of legacy.componentApi, use compatibility.componentApi instead' 'The legacy option has been removed. If you are using this because of legacy.componentApi, use compatibility.componentApi instead'
), ),

@ -54,8 +54,11 @@ async function common_setup(cwd: string, config: CustomRendererTest) {
generate: 'client', generate: 'client',
rootDir: cwd, rootDir: cwd,
runes: true, runes: true,
customRenderer: renderer_path, ...config.compileOptions,
...config.compileOptions experimental: {
...config.compileOptions?.experimental,
customRenderer: renderer_path
}
}; };
await compile_directory(cwd, 'client', compile_options); await compile_directory(cwd, 'client', compile_options);

@ -1093,10 +1093,6 @@ declare module 'svelte/compiler' {
* @since 5.33 * @since 5.33
*/ */
fragments?: 'html' | 'tree'; fragments?: 'html' | 'tree';
/**
* Path to a module that exports the custom renderer to use. When this is truthy templating mode will also be automatically set to `functional`
*/
customRenderer?: string;
/** /**
* Set to `true` to force the compiler into runes mode, even if there are no indications of runes usage. * Set to `true` to force the compiler into runes mode, even if there are no indications of runes usage.
* Set to `false` to force the compiler into ignoring runes, even if there are indications of runes usage. * Set to `false` to force the compiler into ignoring runes, even if there are indications of runes usage.
@ -1199,6 +1195,10 @@ declare module 'svelte/compiler' {
* @since 5.36 * @since 5.36
*/ */
async?: boolean; async?: boolean;
/**
* Path to a module that exports the custom renderer to use. When this is truthy templating mode will also be automatically set to `functional`
*/
customRenderer?: string;
}; };
} }
/** /**
@ -3168,10 +3168,6 @@ declare module 'svelte/types/compiler/interfaces' {
* @since 5.33 * @since 5.33
*/ */
fragments?: 'html' | 'tree'; fragments?: 'html' | 'tree';
/**
* Path to a module that exports the custom renderer to use. When this is truthy templating mode will also be automatically set to `functional`
*/
customRenderer?: string;
/** /**
* Set to `true` to force the compiler into runes mode, even if there are no indications of runes usage. * Set to `true` to force the compiler into runes mode, even if there are no indications of runes usage.
* Set to `false` to force the compiler into ignoring runes, even if there are indications of runes usage. * Set to `false` to force the compiler into ignoring runes, even if there are indications of runes usage.
@ -3274,6 +3270,10 @@ declare module 'svelte/types/compiler/interfaces' {
* @since 5.36 * @since 5.36
*/ */
async?: boolean; async?: boolean;
/**
* Path to a module that exports the custom renderer to use. When this is truthy templating mode will also be automatically set to `functional`
*/
customRenderer?: string;
}; };
} }
/** /**

Loading…
Cancel
Save