Skip to content
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

Allow lazy loading of rendering dependencies on ssr mode #7053

Closed
JeanJPNM opened this issue Dec 26, 2021 · 6 comments
Closed

Allow lazy loading of rendering dependencies on ssr mode #7053

JeanJPNM opened this issue Dec 26, 2021 · 6 comments

Comments

@JeanJPNM
Copy link

Describe the problem

Sveltekit currently has an issue where components that have dependencies using browser features such as the window and document objects throw errors during the component module initialization, preventing the framework from checking the component's module exports and deciding whether the component is suitable for server-side rendering.

Describe the proposed solution

Adding a compiler option to lazily load the dependencies of a component's regular <script>, allowing the framework to read the configuration of a page without loading modules that may be incompatible with the current environment.

Alternatives considered

Additional configuration options and special handler parameters

Importance

would make my life easier

@bluwy
Copy link
Member

bluwy commented Dec 28, 2021

If I understand correctly, you're proposing to be able to read stuff like export const ssr = true in <script context="module">, without actually executing the component compiled code. I don't think this is desirable/possible, do you have a compiler output code in mind that would work with this?

I think the better solution overall is to have SvelteKit not actually importing the component at all, but lexes the exports to determine the options. This has its own caveats, like export const ssr = __SOME_VAR__ not working, but I don't think it's a common pattern.

Routify on the other hand tackles this with special comments like <!-- routify:options bundle=true -->, which can be analyzed without importing too.

@JeanJPNM
Copy link
Author

JeanJPNM commented Dec 29, 2021

This has its own caveats, like export const ssr = SOME_VAR not working, but I don't think it's a common pattern.

The template uses this pattern to conditionally add a router and hydrate the page.

Here is an example on how I think it would work:

<!-- ClientThing.svelte -->
<script>
	export let name;
</script>

<span>hello, {name}</span>
<!-- index.svelte -->
<script context="module">
	export const ssr = Math.floor(Math.random() * 2)
</script>

<script>
	  import ClientThing from './ClientThing.svelte'
</script>
<ClientThing name="user"/>

The compiled code currently looks like:

/* index.svelte generated by Svelte v3.44.3 */
import { create_ssr_component, validate_component } from "svelte/internal";

import ClientThing from './ClientThing.svelte';
const ssr = Math.floor(Math.random() * 2);

const Index = create_ssr_component(($$result, $$props, $$bindings, slots) => {
	return `${validate_component(ClientThing, "ClientThing").$$render($$result, { name: "user" }, {}, {})}`;
});

export default Index;
export { ssr };

But if the option was enabled, the output could look like this:

import { create_ssr_component, validate_component } from "svelte/internal";

const ssr = Math.floor(Math.random() * 2);

async function load_Index() {
  const {default: ClientThing} = await import("./ClientThing.svelte")
  return create_ssr_component(($$result, $$props, $$bindings, slots) => {
	return `${validate_component(ClientThing, "ClientThing").$$render($$result, { name: "user" }, {}, {})}`;
});
}

export default load_Index;
export { ssr };

@bluwy
Copy link
Member

bluwy commented Dec 29, 2021

Thanks for the explanation, I see what you mean now. From a glance, a caveat with this approach is that Svelte is re-writing imports to dynamic imports. This feels like it would open a can of worms. For example, if a dependency has side effects. I'm still not quite convinced that we have to change Svelte to accommodate this syntax though. But I think there are ways to support this at the bundler level, like importing only the script context="module" part, or some sort of manifest (though I'm not too familiar where/how SvelteKit reads it). I think it'd be risky to go this way forward, but that's my 2c.

@JeanJPNM
Copy link
Author

JeanJPNM commented Jan 9, 2022

Although the manifest would be easier to implement, it could bring problems because we would be duplicating the module part of each page. And unlike sveltejs/kit#2804 this particular solution would not require additional configuration from the sveltekit users, and would keep the logic scoped inside each page again.

Although I'm not sure as to how to tell if a module should be lazy loaded because:

  • Tracking where the imported variables are used can take a significant amount of time to process and may not produce the desired results.
  • Using the place of declaration (either <script> or <script context="module">) could potentially break existing code, since there was no clear distinction between the two before.

@JeanJPNM JeanJPNM changed the title Allow lazy loading of component dependencies on ssr mode Allow lazy loading of rendering dependencies on ssr mode Jan 9, 2022
@JeanJPNM
Copy link
Author

JeanJPNM commented Jan 9, 2022

What if instead of using a compiler otion, we add a new option to <svelte:options> so that each component can individually trigger this behaviour. Like this:

<svelte:options lazy={true}/>

@Rich-Harris
Copy link
Member

This was solved in Kit by putting export const ssr in a separate +page.js/+page.server.js file, and evaluating it before components are imported. I don't think there's anything more granular we can/should do than that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants