kit
kit copied to clipboard
Global styles or scripts
Describe the problem
Currently in Svelte Kit the recommended way to import global styles or scripts is in your root layout, this is a problem for the following reasons:
- Slower connects will receive a FOUC (Flash Of Unstyled Content)
- Resets will remove these applied style sheets
- Styles won't be applied if js isn't functioning correctly (in some contexts)
- (opinion) it's weird
Describe the proposed solution
I was reading up in the discord and issues here and I believe one of the following is the best solution:
-
A global js/ts file and global css/scss file
this would be my initial guess at a solution and it was even shown here #1948 but the downsides are that users might want more than provided options such as less or another javascript superset that isn't provided and adding a option might add extra complexity
-
A global js/ts file
Vite already allows for this easily and can just be treated as a secondary entry point I guess. This is already what you do in vanilla vite, for example on my personal site which is currently in routify
-
A global svelte file
This might be familiar for those using vanilla svelte, having a App.svelte (this case would probably be better for a global.svelte file). This can be where you import your global styles but also global scripts and logic. Again this is how things are done on sites in Routify, for example global keybinds
-
Processing app.html
It might be also possible to process the scripts and links inside of app.html and have this the place your global files are placed (processing is necessary since the script or style might be in a superset such as typescript or sass)
Alternatives considered
Writing a script or vite plugin to do this for me but this is just bad for the community
Importance
i cannot use SvelteKit without it
Additional Information
No response
I think another way is to add it to app.html, but IIRC SvelteKit doesn't process it, and links to styles or scripts are static. Perhaps SvelteKit should have some way of transforming app.html, similar to Vite's index.html.
Related: #1530
@bluwy Yep SK doesn't process app.html - already tried
cant you just add a style tag inside your __layout.svelte to head with vanilla js on first render?
that wouldn't solve any of the issues I brought up @Kapsonfire-DE
From what I See , the only thing which isnt covered up is the js part. Otherwise you can add the global CSS in Layout and reflect it to the head. This ist permanent and dont have the other mentioned issues.
Holen Sie sich Outlook für Androidhttps://aka.ms/AAb9ysg
From: GHOST @.> Sent: Monday, January 3, 2022 1:15:20 AM To: sveltejs/kit @.> Cc: Dennis Kaspar @.>; Mention @.> Subject: Re: [sveltejs/kit] Global styles or scripts (Issue #3127)
that wouldn't solve any of the issues I brought up @Kapsonfire-DEhttps://github.com/Kapsonfire-DE
— Reply to this email directly, view it on GitHubhttps://github.com/sveltejs/kit/issues/3127#issuecomment-1003801188, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AP7SMRHACALFCK3NAQ3SPV3UUDTBRANCNFSM5K6EJEUA. Triage notifications on the go with GitHub Mobile for iOShttps://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Androidhttps://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub. You are receiving this because you were mentioned.Message ID: @.***>
If you read my original post then you will see why layout related styling isn't optimal. @Kapsonfire-DE
What I'm missing? If you reflect the style in the head (outside of svelte) it wont be removed. Nothing will flicker, resets wont remove it and so on. The Idea to put this in in __layout and reflect it outside of svelte is that the css will be processed by SK - and multiple to the style will not be loaded multiple times since its cached
This is very much wanted 👍
@Kapsonfire-DE While putting styles in your app.svelte works, these scripts/styles don't get processed by Svelte Kit which leads to limitations or extra scripts / build tools needing to be installed. Having the official way to be putting global scripts/styles in a layout (which isn't even global since it can be reset) is a bad move.
I didnt talk about app.svelte. You can just put in in __layout.svelte or any other component. Make it processed by svelte kit. After that, copy the css with vanilla javascript into the documents head outside of the svelte scope, which makes them persistent and global.
Again even if you can make that work (at a initial guess it would be additional script(s)) it's terrible DX. Would love to know what your root issue is with this proposed solution @Kapsonfire-DE
It would be great if app.html could just be processed by Vite in some way after SvelteKit is done with it. Vite already handles all the bundling etc. properly and works the way you would expect if you for example include a Typescript file instead of a Javascript one.
My specific use case is for pages with hydrate = false where I want to inject a small amount of deferred Javascript (or Typescript) for a background canvas animation. Achieving this with SvelteKit requires hydrating the entire page, which seems like a huge waste, especially if the animation is written in plain Javascript.
I have updated my post to add in that ideas @ratorx
Sorry for the mis-tag @borntofrappe - github mobile being slow
Would like to see a solution to this as well.
I have a naive question between these two proposed options:
- A global js/ts file and global css/scss file
- A global js/ts file
Would choosing 2. mean doing an import 'path/to/global.scss'; in the ts or js file? Would that still have FOUC issues? Does a "CSS in JS" solution always come with FOUC issues? (Go easy on me, there's a gap in my understanding with what the vite + svelte plugin is actually doing.)
At the moment I'm building a single global.css file in an external dir with all our global scss files, using rollup. The build drops that global.css file into sveltekit's src/static dir, and I'm loading it in my __layout.svelte file with:
<svelte:head>
<link rel="stylesheet" href="/global.css">
</svelte:head>
It gets rid of my FOUC, but of course the css file is large since there is no tree shaking. The whole approach feels clunky, and __layout seems the wrong place for "global" stuff. I'm building a strictly static site with many pages -- no SSR, not a SPA. It would seem that the same tree-shaking and code splitting for CSS could still apply somehow with a global scss file(s) and generate the appropriate <link > entries. Letting a developer supply a list of arbitrary "entry points", or "build points" to have svelte + vite build would be useful. I guess I could also argue "why build/output anything that won't be used".
@bseib Hopefully the FOUC issue at this point is close to nothing, you will always get it in dev mode but in production hopefully it's limited to slower connection (not much kit can do about this anyway and when building static or ssr the issue shouldn't be present since it should be loading styles in the head of the page).
Yes putting the global ts/js file would mean you put the scripts inside of that with with a import statement, this is how it's done in vanilla svelte + vite projects for example. We could even combine the global style and global js so that you wouldn't need to do any importing and there is a content seperation.
If you are currently already building your css file then you should put it in static and link to it in your app.html as then it will be global, if you don't wish to do this you might as well get rid of your extra build step as svelte kit can handle this for you
Code splitting global styles doesn't make sense as even if you wanted to strip styles that don't apply then it would essentially no longer be global but scoped to your enitre app, which while that is a interesting concept wouldn't be global styling
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.
Hi all, I'm a little late to the party, but hopefully there's still a lot of fun to be had ^^. I just created my first SvelteKit skeleton project and currently have my global CSS reset in static/css/common.css with the following code in src/app.html:
<link rel="stylesheet" href="/css/common.css">
I suppose this is fine for simple projects, but what if I want to replace common.css with common.scss? Is there a method that is considered "best practice" in SvelteKit to implement a global SCSS?
Had the same problem, no global.css found. Changed the link in app.html to ‘%svelte.assets%/css/global.css” for dev path static/css/global.css and its working.
I worked around this issue by doing the following:
- Create an
src/App.sveltefile with the following in it:
// src/App.svelte
<slot />
<style lang="scss" global>
@use './global.scss';
</style>
-
Create a
src/global.scssfile with your global styles in it. -
Import
App.sveltelike this insrc/routes/index.svelte:
// src/routes/index.svelte
<script lang="ts">
import App from '../App.svelte'
</script>
<App>
<p>content</p>
</App>
The main downside is that you have to import <App> and wrap it around every route.
It would be nicer if SvelteKit provided a way to just have a global scss file.
People usually (if not always) import global CSS inside __layout.svelte, but that doesn't make sense because global CSS is usually page/app related things, like CSS resets, custom properties / variables, etc. I think of it like this:
<html>
<body>
<Layout>
<main>
Why are we setting CSS for <html> and <body> inside <Layout>?
Also, if you have __error.svelte, you need to import the global CSS file there too! And now with the new Named Layouts feature is also worse because if you have 10 different layouts that share the same CSS resets... you have to import it 10 times. Even if the output CSS is not duplicated and file is only imported once... it doesn't make sense as Layouts shouldn't be responsible for this!
A layout is a visual representation of a page, it shouldn't be responsible for setting variables or resetting css among other things.
I think we need an entrypoint for global CSS that is outside of layouts, for example an option inside svelte.config.js like:
const config = {
kit: {
'globalCss or cssEntrypoint': 'src/lib/styles/index.css',
}
}
I tried using prependData inside postcss with svelte-preprocess but that's worse because the variables get added over and over again.
Having <style> or <link> inside app.html doesn't let you process those files with postcss or any other preprocessor, so not really a solution.
Don't forget that the solution must support Sass/Less as well
that file can be read and preprocessed
I found this article and it really works. https://www.closingtags.com/global-css-in-sveltekit/
Someone may have already mentioned this but the best way to get global styles in my experience is to include something like this in your __layout.svelte:
<style>
:global(:root) {
--green: #293d3a;
--pink: #ff7965;
--white: #ffffff;
--grey: #222222;
}
...
...
...
</style>
Just want to add, for anyone using the <svelte:head> method to insert the global stylesheet into the head tag, HMR doesn't pick up changes to the stylesheet normally, but you don't need to restart your server to apply the changes. Instead you can comment out the <link> in the <svelte:head> tag to remove the stylesheet from the build, save the file so HMR picks up the removed stylesheet, then uncomment the <link> tag and save again so HMR restores the stylesheet with your changes. Not the smoothest method but for me it's better than stopping and restarting the dev server.
I have been facing this issue while trying to import an external dependency under script type="module" tag. I need it this way so that one of my dependency installs first before anything else gets installed.
<html lang="en">
<head>
<script type="module">
import '@master/css';
</script>
What I have realised is that though vite handles this without any issue. However, since sveltekit takes over html processing, it throws Failed to resolve module specifier <external dependency> error. It suggest for relative urls which in my case did not work due to nested external dependency. Here's the reproduction of the issue.
For the time being I have linked external dependency file from node_modules to my static folder and then linking it with script tag inside app.html. This is definitely hacky.
Would be great if svelte kit allows vite to preprocess app.html after it has done its side of the processing.
Heads up: Under the new layouts proposal, the root +layout.svelte would always be guaranteed to exist and be loaded, so you can import global styles or scripts there. https://github.com/sveltejs/kit/discussions/6124
That will be awesome.
@dummdidumm Currently all the scripts are loaded by sveltekit as module scripts that are deferred automatically by the browsers. This leads to FOUC for global styles imported within layout components on slower connections when html is parsed before style is loaded. Just wondering if this will this get addressed too?
Currently I am using app.html to ensure that non-deferred scripts and styles are loaded before any other processing happens.
FOUC should not be possible for styles imported by the root layout, since those styles are injected into the document (as a <style> during dev, and as a <link> in production). If you have an example of it, please raise an issue with a repro!
Prior to #6174 it was possible to end up in a FOUCy situation because you might land on a page that bypassed the root layout. That's no longer possible — under the new system, every page inherits from the root layout, which means it's a perfect place to add global scripts and styles:
<!-- src/routes/+layout.svelte -->
<script>
import '$lib/javascript-that-should-run-before-hydration.js';
import './global.css';
import { afterNavigate } from '@sveltejs/kit';
afterNavigate(() => {
// this will run after every single navigation, making it an
// ideal place to put e.g. analytics tracking code etc
});
</script>
Note that $lib/javascript-that-should-run-before-hydration.js can even do async work, thanks to top-level await.
I'm pretty sure this issue can therefore be closed — any objections?