Hoppa till innehåll

Kom igång med Svelte

Förutsättningar

Lägg gärna några timmar på tutorialen för att komma igång!

Installation

App

Boilerplate för en ny Svelte App kan skapas med @soleil-se/create-app.

Terminal window
npm init @soleil-se/app@latest

Projekt

Enklast för att komma igång är att titta på KEX 2 att se struktur och inställningar.

Nedan finns en steg för steg guide och förklaring till de filer som behövs att installera i ett projekt.

Installera i projekt

1. Installera dependencies
För att kunna kompilera Svelte installera svelte och svelte-preprocess.

Terminal window
npm i svelte svelte-preprocess --dev

Förutsätter att @soleil-se/eslint-config finns installerat och uppdaterat.

2. Filer i rotkatalogen
Skapa upp eller uppdatera innehållet i följande filer i rotkatalogen.

  • Directoryclient_src/
  • Directoryserver_src/
  • eslint.config.js
  • jsconfig.json
  • package.json
  • prettier.config.js
  • stylelint.config.js
  • svelte.config.js

eslint.config.js
Konfiguration för ESLint, här använder vi @soleil-se/eslint-config.

.eslint.config.js
import config from '@soleil-se/eslint-config';
export default config;

prettier.config.js
Inställningar för Prettier som används som för att formatera kod i Svelte-filer.
Läs mer under Kodformatering

prettier.config.js
import config from '@soleil-se/eslint-config/prettier';
export default config;

stylelint.config.js
Konfiguration för Stylelint, här använder vi @soleil-se/stylelint-config.

stylelint.config.js
export default {
extends: '@soleil-se/stylelint-config',
};

jsconfig.json
Används för att sätta var roten av projektet eller appen finns, detta för att språkservicen ska veta var den ska leta efter beroenden.
Läs mer om jsconfig.json.

jsconfig.json
{
"exclude": ["node_modules", "dist"]
}

svelte.config.js
Används bland annat för att ställa in preprocessing, exempelvis Sass eller Less.
Läs mer under Preprocessing.

svelte.config.js
import { sveltePreprocess } from 'svelte-preprocess';
export default {
preprocess: sveltePreprocess(),
};

Visual Studio Code

Installera Svelte tillägget till Visual Studio Code för att få korrekt highlighting, formatering osv.

ESLint

Svelte filer lintas automatiskt om man har eslint och @soleil-se/eslint-config installerat och läser in denna konfiguration.

Kodformatering

Formatering av kod i Svelte använder Prettier så man behöver lägga till inställningar för detta så HTML kan formateras, dessvärre påverkar detta även JavaScript så några regler som man är van vid har fått stängas av så det inte krockar med Prettier.

Prettier

Skapa en fil som heter prettier.config.js i roten av projektet eller appen.

prettier.config.js
import config from '@soleil-se/eslint-config/prettier';
export default config;

Automatisk formatering

För att formatera automatiskt behöver man lägga till följande i settings.json i VS Code.

settings.json
{
"[svelte]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "svelte.svelte-vscode"
},
}

Man kan även stänga av formateringen av skript genom att lägga till kommentaren
<!-- prettier-ignore --> före skripttaggen om det blir krockar och problem.

<!-- prettier-ignore -->
<script>
const foo = 'bar';
</script>
<p>{foo}</p>

Preprocessing

Vi använder ofta preprocessing av styling i våra appar med antingen Sass eller Less. För att få korrekta felmeddelanden behöver man berätta för Svelte att man använder en preprocessor.
Skapa en fil som heter svelte.config.js i roten av appen.

Om du använder Sass i projektet

Använder man appen i ett projekt med standardstrukturen är det vanlig att man enkelt vill kunna importera variabler och mixins.
Följande konfiguration säger att det finns en till path där Sass ska leta efter filer.

svelte.config.js
import { sveltePreprocess } from 'svelte-preprocess';
export default {
preprocess: sveltePreprocess({
scss: { includePaths: [`${import.meta.dirname}/../../../../client_src/sass`] }
}),
};
Om du använder Less i projektet

Använder man appen i ett projekt med standardstrukturen är det vanlig att man enkelt vill kunna importera variabler och mixins.
Följande konfiguration säger att det finns en till path där Less ska leta efter filer.

svelte.config.js
import { sveltePreprocess } from 'svelte-preprocess';
export default {
preprocess: sveltePreprocess({
less: { paths: ['../../../../client_src/less'] },
}),
};

Struktur

Struktur för en WebApp som använder Svelte.

  • Directoryconfig Konfiguration för appen.
    • App.svelte Huvudkomponent för konfigurationen
    • config.js Klientkod för konfigurationen
    • index.js Serverkod för konfigurationen
  • Directoryconfig_global Global konfiguration för appen
    • App.svelte Huvudkomponent för globala konfigurationen
    • config.js Klientkod för globala konfigurationen
    • index.js Serverkod för globala konfigurationen
  • Directorysrc
    • Directoryclient/ Klientspecifik kod
    • Directorycommon/ Universell kod
    • Directorycomponents/ Komponenter
    • Directoryserver/ Serverspecifik kod
    • Directoryresource/ Mapp för appens resurser
    • App.svelte Huvudkomponent för appen
    • index.js Serverkod för appen
    • headless.js Headless kod för appen
    • hooks.js Pre render hooks
    • main.js Klientkod för appen
    • appDataDefaults.json Defaultvärden för konfiguration
  • jsconfig.json
  • manifest.json
  • package.json
  • svelte.config.js

Filer

jsconfig.json
{
"exclude": ["node_modules", "dist"]
}

Läs mer om jsconfig.json

manifest.json

Standard manifest.json för WebApps:

{
"id": "se.soleil.mySvelteApp",
"version": "1.0.0",
"name": "Min Svelte App",
"author": "Soleil AB",
"description": "Min Svelte app",
"helpUrl": "https://soleil.se/support",
"type": "WebApp",
"bundled": true
}
package.json
{
"name": "my-app",
"author": "Soleil AB",
"license": "UNLICENSED",
"private": true,
"dependencies": {
"@sitevision/api": "^2025.1.1",
"@soleil-se/app-util": "^5.0.0",
"svelte": "^5.0.0"
},
"devDependencies": {
"@soleil-se/build-app": "^2.0.0"
},
"scripts": {
"build": "build-app build",
"watch": "build-app watch",
"start": "build-app start",
"deploy": "build-app deploy"
}
}

Rendering

Det finns tre sätt man kan rendera en Svelte app på:

  1. Universellt, appen kommer renderas både på servern och klienten.
  2. Serverside renderad (SSR), appen kommer bara renderas på servern.
  3. Clientside renderat (CSR), appen kommer bara renderas på klienten.

När ska man använda vad?
Blir alltid en avvägning efter vilka krav kunden har.

  • Måste appen fungera utan JavaScript igång?
    Använd Universellt eller SSR.
  • Är appen statisk utan interaktivitet?
    Använd SSR.
  • Har appen mycket interaktivitet?
    Använd Universellt eller CSR.
  • Är det en kritisk app för att kunna besöka och använda webbplatsen?
    Använd Universellt eller SSR.
  • Finns det mycket dynamiskt innehåll eller interaktivitet som inte behöver indexeras eller som inte är kritisk för webbplatsen?
    Använd CSR.

Universell

En universell app kommer renderas både på servern och klienten.
Först kommer statisk HTML skrivas ut på serversidan i Sitevision sedan kommer koden på klientsidan ta över den HTML som renderats på servern och lägga på interaktivitet.

index.js

Läs mer om render i index.js.

import router from '@sitevision/api/common/router';
import { render } from '@soleil-se/app-util/server/svelte/5';
import App from './App.svelte';
router.get('/', (req, res) => {
const props = { foo: 'bar' };
const html = render(App, props);
res.agnosticRender(html, props);
});
main.js

Läs mer om render i main.js.

import { render } from '@soleil-se/app-util/client/svelte/5';
import App from './App.svelte';
export default (props, target) => {
render(App, { props, target });
};

Komponenterna behöver därför fungera både på servern och klienten. Men det kan hända att man har kod som behöver kunna exekveras på klienten men inte servern, vilket är ganska vanligt då man oftast har interaktivitet i sin app om den behöver renderas på klienten.

Man kan då använda sig av isBrowser från @soleil-se/app-util, vilken enbart kommer inkludera koden om man är på klientsidan. Motsvarande för servern finns också, se isServer.
Man kan även tänka på att alla events och onMount enbart körs på klientsidan.

Exempel: Lägg på en klass på html-elementet

document finns enbart tillgänglig på klientsidan.

import { isBrowser } from '@soleil-se/app-util';
if(isBrowser) {
document.documentElement.classList.add('foo')
}
Exempel: Rendera bara en komponent på klientsidan

Komponenten kan innehålla funktionalitet som inte fungerar på serversidan och då kan man välja att inte rendera komponenten överhuvudtaget.

<script>
import { isBrowser } from '@soleil-se/app-util';
import ClientSideComponent from './ClientSideComponent.svelte';
</script>
{#if isBrowser}
<ClientSideComponent />
{/if}

När koden byggs ihop för servern kommer dead code elimination i Rollup plocka bort den kod som inte ska köras på serversidan.

Fördelar

  • Renderas först på servern och visas därför direkt när sidan laddas.
  • Renderas när JavaScript är avstängt.
  • Indexeras i Sitevisions sök.
  • Bättre för SEO.

Nackdelar

  • Kan bli krångligt att hålla isär vad som körs på servern och på klienten.
  • Om man har en app med mycket interaktivitet kan det kosta mer än det smakar.

SSR

Används när man bygger statiska moduler utan behov av klientsideskript, exempelvis puffar, enklare listningar, banners osv.
Förfarandet blir ungefär lika som med en universell app men att man utelämnar main.js.

Server-side rendering (SSR) is the generation of the page contents on the server. SSR is generally preferred for SEO. While some search engines can index content that is dynamically generated on the client-side it may take longer even in these cases. It also tends to improve perceived performance and makes your app accessible to users if JavaScript fails or is disabled (which happens more often than you probably think).

index.js

Går att använda både render och renderServer. Skillnaden är att render kommer läsa in main.js om denna finns med i appen. Om man har en SSR app så har man oftast inte det. Annars kan man använda renderServer för att försäkra sig om att appen bara renderas på servern.

import router from '@sitevision/api/common/router';
import { render } from '@soleil-se/app-util/server/svelte/5';
import App from './App.svelte';
router.get('/', (req, res) => {
const props = { foo: 'bar' };
const html = render(App, props);
res.send(html);
});

Läs mer om render i index.js.

Fördelar

  • Renderas när JavaScript är avstängt.
  • Indexeras i Sitevisions sök.
  • Bättre för SEO.
  • Kan användas för exempelvis templates för mail osv.

Nackdelar

  • Går inte att använda om man behöver ha någon form av interaktivitet i appen.

CSR

Används när man bygger moduler med mycket interaktivitet som inte behöver fungera med JavaScript avstängt.

Client-side rendering (CSR) is the generation of the page contents in the web browser using JavaScript. A single-page app (SPA) is an application in which all requests to the server load a single HTML file which then does client-side rendering of the requested contents based on the requested URL.

All navigation is handled on the client-side in a process called client-side routing with per-page contents being updated and common layout elements remaining largely unchanged.

SPAs do not provide SSR, which has the shortcoming described above. However, some applications are not greatly impacted by these shortcomings such as a complex business application behind a login where SEO would not be important > and it is known that users will be accessing the application from a consistent computing environment.

index.js

Här renderas inget på servern utan appen kommer att renderas på klientsidan, detta görs genom att skicka med en tom sträng i res.agnosticRender och de props som ska skickas med till appen.

index.js
import router from '@sitevision/api/common/router';
router.get('/', (req, res) => {
const props = { foo: 'bar' };
res.agnosticRender('', props)
});
main.js

Läs mer om render i main.js.

main.js
import { render } from '@soleil-se/app-util/client/svelte/5';
import App from './App.svelte';
export default (props, target) => {
render(App, { props, target });
};

Fördelar

  • Behöver inte tänka på att appen ska fungera på serversidan.

Nackdelar

  • Går inte att använda om appen ska fungera utan JavaScript påslaget.
  • Indexeras inte i Sitevisions sök.

Hydration

När en applikation först renderas på servern och sedan på klienten används ett koncept som kallas för hydration.

Svelte components store some state and update the DOM when the state is updated. When fetching data during SSR, by default this data will be transmitted to the client along with the server-rendered HTML. The components can then be initialized on the client with that data without having to call the same API endpoints again. Svelte will then check that the DOM is in the expected state and attach event listeners in a process called hydration. Once the components are fully hydrated, they can react to changes to their properties just like any newly created Svelte component.

App props

Props som skickas med när appen renderas på servern är tillgängliga i App.svelte och genom getAppProps.
Går även att använda Sveltes context API, men då är data bara tillgänglig i komponenter och inte js-filer.

Skicka props från servern till appen
index.js
import router from '@sitevision/api/common/router';
import { render } from '@soleil-se/app-util/server/svelte/5';
router.get('/', (req, res) => {
const props = { foo: 'bar' };
res.send(render(props));
});
App.svelte
<script>
let { foo } = $props();
</script>
<p>{foo}</p>
Hämta props djupt i strukturen

Används oftast om man har data från servern som används långt ner i strukturen så man ska slippa skicka props hela vägen ner.

App.svelte
import router from '@sitevision/api/common/router';
import { render } from '@soleil-se/app-util/server/svelte/5';
router.get('/', (req, res) => {
const props = { foo: 'bar' };
res.send(render(props));
});
Child.svelte
<script>
import { getAppProps } from '@soleil-se/app-util';
const { foo } = getAppProps();
</script>
<p>{foo}</p>

Styling

Stylingen i en Svelte app görs oftast i komponenterna.

Det är inte nödvändigt att använda BEM i en Svelte app då stylingen automatiskt scopas till komponenten.
https://svelte.dev/docs/svelte/scoped-styles

Preprocessors

Man kan använda antingen SCSS eller Less genom att lägga på lang på style taggen.

<div>
Foo
</div>
<style lang="scss">
@use 'abstracts/variables' as *;
div {
background-color: $blue;
}
</style>

Global styling

Då stylingen är scopad kan man använda :global för att nå en selektor globalt.

Global styling
<style>
:global(body) {
/* this will apply to <body> */
margin: 0;
}
div :global(strong) {
/* this will apply to all <strong> elements, in any
component, that are inside <div> elements belonging
to this component */
color: goldenrod;
}
</style>

Med svelte-preprocess går det även att ange global styling på några ytterligare sätt.
https://github.com/sveltejs/svelte-preprocess#global-style

Konfiguration

För att skapa upp konfiguration för en WebApp kan man använda @soleil-se/config-svelte.