chore: use create_element everywhere (#17683)

follow-up to #17418. This replaces every occurrence of
`document.createElement` with a helper, `create_element`, that delegates
to `document.createElementNS`. This makes the code a tiny bit simpler
and in theory should allow Svelte to run on `text/xml` documents, though
I'm not ready to add a test suite to prevent regressions for something
so niche.

If we choose to merge this, I think we can safely close #17418 as all
the other points (around case sensitivity etc) have already been taken
care of AFAICT.

### Before submitting the PR, please make sure you do the following

- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] Prefix your PR title with `feat:`, `fix:`, `chore:`, or `docs:`.
- [x] This message body should clearly illustrate what problems it
solves.
- [ ] Ideally, include a test that fails without this PR but passes with
it.
- [ ] If this PR changes code within `packages/svelte/src`, add a
changeset (`npx changeset`).

### Tests and linting

- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint`

---------

Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>
Co-authored-by: Tee Ming <chewteeming01@gmail.com>
pull/17690/head
Rich Harris 6 months ago committed by GitHub
parent bcd170ceb0
commit 9400689e1c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -7,7 +7,7 @@ import {
set_hydrate_node,
set_hydrating
} from '../hydration.js';
import { create_text, get_first_child } from '../operations.js';
import { create_element, create_text, get_first_child } from '../operations.js';
import { block, teardown } from '../../reactivity/effects.js';
import { set_should_intro } from '../../render.js';
import { active_effect } from '../../runtime.js';
@ -57,7 +57,11 @@ export function element(node, get_tag, is_svg, render_fn, get_namespace, locatio
block(() => {
const next_tag = get_tag() || null;
var ns = get_namespace ? get_namespace() : is_svg || next_tag === 'svg' ? NAMESPACE_SVG : null;
var ns = get_namespace
? get_namespace()
: is_svg || next_tag === 'svg'
? NAMESPACE_SVG
: undefined;
if (next_tag === null) {
branches.ensure(null, null);
@ -67,11 +71,7 @@ export function element(node, get_tag, is_svg, render_fn, get_namespace, locatio
branches.ensure(next_tag, (anchor) => {
if (next_tag) {
element = hydrating
? /** @type {Element} */ (element)
: ns
? document.createElementNS(ns, next_tag)
: document.createElement(next_tag);
element = hydrating ? /** @type {Element} */ (element) : create_element(next_tag, ns);
if (DEV && location) {
// @ts-expect-error

@ -1,6 +1,7 @@
import { DEV } from 'esm-env';
import { register_style } from '../dev/css.js';
import { effect } from '../reactivity/effects.js';
import { create_element } from './operations.js';
/**
* @param {Node} anchor
@ -18,7 +19,7 @@ export function append_styles(anchor, css) {
// Always querying the DOM is roughly the same perf as additionally checking for presence in a map first assuming
// that you'll get cache hits half of the time, so we just always query the dom for simplicity and code savings.
if (!target.querySelector('#' + css.hash)) {
const style = document.createElement('style');
const style = create_element('style');
style.id = css.hash;
style.textContent = css.code;

@ -2,6 +2,7 @@ import { createClassComponent } from '../../../../legacy/legacy-client.js';
import { effect_root, render_effect } from '../../reactivity/effects.js';
import { append } from '../template.js';
import { define_property, get_descriptor, object_keys } from '../../../shared/utils.js';
import { create_element } from '../operations.js';
/**
* @typedef {Object} CustomElementPropDefinition
@ -103,7 +104,7 @@ if (typeof HTMLElement === 'function') {
* @param {Element} anchor
*/
return (anchor) => {
const slot = document.createElement('slot');
const slot = create_element('slot');
if (name !== 'default') slot.name = name;
append(anchor, slot);

@ -1,5 +1,5 @@
import { hydrating, reset, set_hydrate_node, set_hydrating } from '../hydration.js';
import { create_comment } from '../operations.js';
import { create_comment, create_element } from '../operations.js';
import { attach } from './attachments.js';
/** @type {boolean | null} */
@ -13,7 +13,7 @@ let supported = null;
*/
function is_supported() {
if (supported === null) {
var select = document.createElement('select');
var select = create_element('select');
select.innerHTML = '<option><span>t</span></option>';
supported = /** @type {Element} */ (select.firstChild)?.firstChild?.nodeType === 1;
}

@ -7,6 +7,7 @@ import { active_effect } from '../runtime.js';
import { async_mode_flag } from '../../flags/index.js';
import { TEXT_NODE, EFFECT_RAN } from '#client/constants';
import { eager_block_effects } from '../reactivity/batch.js';
import { NAMESPACE_HTML } from '../../../constants.js';
// export these for reference in the compiled code, making global name deduplication unnecessary
/** @type {Window} */
@ -231,18 +232,17 @@ export function should_defer_append() {
}
/**
*
* @param {string} tag
* @template {keyof HTMLElementTagNameMap | string} T
* @param {T} tag
* @param {string} [namespace]
* @param {string} [is]
* @returns
* @returns {T extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[T] : Element}
*/
export function create_element(tag, namespace, is) {
let options = is ? { is } : undefined;
if (namespace) {
return document.createElementNS(namespace, tag, options);
}
return document.createElement(tag, options);
return /** @type {T extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[T] : Element} */ (
document.createElementNS(namespace ?? NAMESPACE_HTML, tag, options)
);
}
export function create_fragment() {

@ -1,6 +1,8 @@
import { create_element } from './operations.js';
/** @param {string} html */
export function create_fragment_from_html(html) {
var elem = document.createElement('template');
var elem = create_element('template');
elem.innerHTML = html.replaceAll('<!>', '<!---->'); // XHTML compliance
return elem.content;
}

@ -275,7 +275,7 @@ function run_scripts(node) {
const effect = /** @type {Effect & { nodes: EffectNodes }} */ (active_effect);
for (const script of scripts) {
const clone = document.createElement('script');
const clone = create_element('script');
for (var attribute of script.attributes) {
clone.setAttribute(attribute.name, attribute.value);
}

Loading…
Cancel
Save