-
-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
fix: allow use of document root as target in typescript #7554
Conversation
It is not possible to use typescript when using `target: document` during component initialization, because target can only be of type Element or ShadowRoot. This means that it is not possible to hydrate the entire document when managing the <html> element as a Svelte component. This commit fixes this by allowing documents to be targets.
Does |
I don't think this is the right approach, though. You don't want |
It does -- document.body just targets the element, while I wanted to hydrate the actual document root. This came up in the context of SSR and prerendering: I wanted to have the main layout managed as a svelte components, so that I could define it as such: <!-- Layout.svelte -->
<html lang="en">
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<title>Svelte app</title>
<link rel='icon' type='image/png' href='/static/favicon.png'>
<link rel='stylesheet' href='/static/global.css'>
<link rel='stylesheet' href='/static/bundle.css'>
<script defer src='/static/bundle.js'></script>
</head>
<body>
<slot />
</body>
</html> And then using said layout: <script lang="ts">
export let name: string;
import Layout from 'Layout.svelte';
</script>
<Layout>
Hello, {name}
</Layout> Prerendering this with <html lang="en">
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<title>Svelte app</title>
<link rel='icon' type='image/png' href='/static/favicon.png'>
<link rel='stylesheet' href='/static/global.css'>
<link rel='stylesheet' href='/static/bundle.css'>
<script defer src='/static/bundle.js'></script>
</head>
<body>
Hello, foo
</body>
</html> With the intent of re-hydrating the static content, using this main: import App from './App.svelte';
const app = new App({
target: document,
hydrate: true,
props: {
name: 'bar'
}
});
export default app; when running this, the html gets correctly hydrated and This is all already possible when using javascript, it's only typescript that complains because target can only be an Element or a ShadowRoot. |
I initially tried with <html lang="en">
<html lang="en">
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<title>Svelte app</title>
<link rel='icon' type='image/png' href='/static/favicon.png'>
<link rel='stylesheet' href='/static/global.css'>
<link rel='stylesheet' href='/static/bundle.css'>
<script defer src='/static/bundle.js'></script>
</head>
<body>
Hello, bar
</body>
</html>
</html> Which, as you can guess, is a bit problematic. |
While technically correct, I'm not sure how I feel about this change because it's a user mistake in 99% of all cases (forgetting the |
Wow, I had no idea this worked! I'm similarly conflicted but I think I lean towards merging — the types are currently incorrect given that we do support this (and undoing that would be am unwanted breaking change), and I think people are very unlikely to hit that problem in practice. (If they do, I'm not sure that the red squiggly is more likely to steer them in the right direction than seeing their whole app blow up.) |
@dummdidumm is attempting to deploy a commit to the Svelte Team on Vercel. A member of the Team first needs to authorize it. |
The updated types have been released in 3.58.0 - thank you! |
It is not possible to use typescript when using
target: document
during component initialization, because target can only be of type
Element or ShadowRoot. This means that it is not possible to hydrate
the entire document when managing the element as a Svelte
component.
This commit fixes this by allowing documents to be targets.
Note that this just fixes the type constraint of the target option in IComponentOptions. Svelte already works well when hydrating the document root with
target: document
in regular javascript, so this just relaxes the type constraint.Tests
It is unclear to me how to add a test for this -- this can only work when hydrating and there's no skip_if_not_hydrate in test/runtime. This fix was hand-tested with the following setup, but I'd appreciate help in turning this into an actual test.
Given the following App.svelte:
And the following main.ts:
Building the bundle results in the following error:
With this commit, the error goes away.
Workaround
The workaround I'm using is adding a
// @ts-nocheck
at the top of main.ts. This is of course horribly sad, since we just throw type checking out the window.