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

Ability to have code included across multiple layouts #1530

Closed
ghost opened this issue May 23, 2021 · 11 comments
Closed

Ability to have code included across multiple layouts #1530

ghost opened this issue May 23, 2021 · 11 comments
Labels
feature / enhancement New feature or request
Milestone

Comments

@ghost
Copy link

ghost commented May 23, 2021

Is your feature request related to a problem? Please describe.
Sometimes, a library or a small code snippet has to be injected globally so its available everywhere in the app. For example, here's how PurgeIcons recommends to inject its generated code into a Vue app:

import { createApp } from 'vue'
import App from './App.vue'

import '@purge-icons/generated' // <-- This

createApp(App).mount('#app')

In Sapper, I could do something similar in the src/client.js file:

import * as sapper from '@sapper/app';

import '@purge-icons/generated'

sapper.start({
  target: document.querySelector('#app'),
 });

AFAIK, there's no straight-forward way of doing this in SvelteKit currently.

Describe the solution you'd like
Perhaps adding a file somewhere in src/ which would allow to inject global code could solve this problem.

Describe alternatives you've considered
I believe it would also be possible to import the code in the __layout.svelte file, but this isn't truly global, as the layout file can be overridden. Additionally, this approach feels convoluted because really, the layout file should be used for layout, not for importing global code.

How important is this feature to you?
It's pretty important to me because I'd like to start using SvelteKit with my favorite libraries and existing code snippets I have, but I can't find a way to reliably write globally-scoped code.

@ignatiusmb
Copy link
Member

This can probably be done in src/hooks with a couple of modifications

@benmccann benmccann changed the title Feature request: Global JavaScript file (similar to Sapper) Ability to have code included across multiple layouts Jul 23, 2021
@ignatiusmb ignatiusmb added the feature / enhancement New feature or request label Aug 22, 2021
@Conduitry Conduitry mentioned this issue Sep 1, 2021
@frederikhors
Copy link
Contributor

This can probably be done in src/hooks with a couple of modifications

Can you explain how? This is EXTREMELY IMPORTANT.

@frederikhors
Copy link
Contributor

Let's say I'm using @urql/svelte and its initClient().

If I use that method both in

  1. src/routes/__layout.svelte and in
  2. src/routes/login/__layout.reset.svelte

it initializes my urql client two times!

Is there a workaround today?

I'm using it like this because in src/routes/__layout.svelte I redirect the user to /login if is not authenticated.

@FaustTobias
Copy link

This feature would be greatly appreciated!

At my company, we are currently using sapper's client.js to preload all components that are required to display the current page before actually hydrating it on the client-side. This is due the fact that we had to start code-splitting content components because the output bundle became too large.

The data for every page comes from a headless cms. We collect every required component on the server-side using the component's preload function and return the result as an array of strings (e.g. component ids). On the client-side we read this array from the preloaded sapper data (sapper stores its preloaded data in a global variable) and load all required components into a client side component cache. This needs to happen before sapper starts, since the components have to be fully loaded at hydration time.

I haven't found a way to do something similar with sveltekit yet.

@svenjacobs
Copy link

Let's say I'm using @urql/svelte and its initClient().

If I use that method both in

  1. src/routes/__layout.svelte and in
  2. src/routes/login/__layout.reset.svelte

it initializes my urql client two times!

Is there a workaround today?

I'm using it like this because in src/routes/__layout.svelte I redirect the user to /login if is not authenticated.

@frederikhors Have you found a solution? I have the exact same use case. I want to initialize urql only once, at a central place.

@Hai-San
Copy link

Hai-San commented Feb 21, 2022

Today I'm having the same problem to apply a .scss file globally to reset the css. It would be very important to have a way to apply styles and scripts globally.

@Zachiah
Copy link

Zachiah commented Apr 7, 2022

I know it's a bit hackish, and maybe I'm missunderstanding, but couldn't you just write the urql initialization code in a separate file of your choice and then import it into all of your layouts that way it only gets run once?

@homerjam
Copy link

homerjam commented Apr 8, 2022

I'm still at the very early stages of a build, I've implemented auth and urql only, this is the cleanest I can get my __layout file and it's still a bit of a mess (aka hackish / read difficult to discern what's going on) as far as I'm concerned. In my view there could be an improved way to re-use these sorts of simple modules across different projects that would keep the __layout file clear of boilerplate (shouldn't layout be just that?). As mentioned in a previous thread Nuxt does this with plugins.

<script lang="ts" context="module">
  import { urqlGetClient, urqlGetStuff } from '$lib/urql';
  import type { LoadInput } from '@sveltejs/kit/types/internal';

  export async function load({ fetch, session, stuff, url }: LoadInput) {
    const client = await urqlGetClient({ fetch, token: session.token });

    return {
      props: { ...session, client, key: url.pathname },
      stuff: {
        ...stuff,
        ...urqlGetStuff({ client }),
      },
    };
  }
</script>

<script lang="ts">
  import '../app.css';
  import { authOnInit } from '$lib/auth';
  import { urqlOnInit } from '$lib/urql';
  import Page from '$lib/components/page.svelte';

  export let user: any;
  export let token: any;
  export let isLoggedIn: boolean;
  export let client: any;

  export let key;

  authOnInit({ user, token });
  urqlOnInit({ client });

  // console.log({ isLoggedIn });
</script>

<Page {key}>
  <slot />
</Page>

@felixsanz
Copy link

In this case the best approach will always be have urql inside it's own js/ts file with a singleton pattern and doesn't matter how many times you instantiate it from inside svelte components

@homerjam
Copy link

homerjam commented May 10, 2022

In this case the best approach will always be have urql inside it's own js/ts file with a singleton pattern and doesn't matter how many times you instantiate it from inside svelte components

This is what I've ended up doing but this differs somewhat from the approach in the urql docs - they have this "bindings" thing which is confusing.

I've been wondering if client-side hooks could be a good place for this stuff? At the moment I'm making use of server-side hooks to setup auth/graphql client for ssr so it would be nice and tidy to have all that in one place

@benmccann
Copy link
Member

benmccann commented Aug 26, 2022

I believe this was addressed by #6174, since under the new system the root layout is always guaranteed to exist, so you can put your code there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature / enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

10 participants