35
loading...
This website collects cookies to deliver better user experience
npm init svelte@next my-sveltekit-app && cd $_
npm install
npm run dev
Skeleton project
option for a quick start. It literally only takes about 40 seconds to download everything you need and start up your local server. Next, open up your browser and go to http://localhost:3000. If you already have a process running on TCP port 3000
, see the tip below on changing the default SvelteKit dev server port..
├── README.md
├── jsconfig.json
├── node_modules
│ ├── ...
│ └── ...
├── package-lock.json
├── package.json
├── src
│ ├── app.html
│ ├── global.d.ts
│ ├── lib
│ └── routes
│ └── index.svelte
├── static
│ └── favicon.ico
└── svelte.config.js
The README.md
file contains some tips on getting going, handy to keep while you are still getting used to SvelteKit.
jsconfig.json
defines some paths which the compiler needs. If this is your first SvelteKit project, I would keep files in their default locations.
package.json
: remember you will find the npm script definitions here so you can check back on the build, dev and preview commands if you have as bad a memory as I do. We'll look at some scripts you might want to modify in package.json
further down.
src/app.html
is an HTML template, which SvelteKit injects your code into. You can set some accessibility properties here, or alternatively hang on and you will see a way to set meta tags programmatically, further down.
src/global.d.ts
: if you're a TypeScript person, you already know what this is for!
src/lib
: create this directory and use it to store your own components, utility functions etc. SvelteKit has a nice way of importing files from here, so you don't need to use ../../../../file-i-want.js
notation, which can become burdensome when refactoring code. We go into this later.
src/routes
: SvelteKit creates app pages based on the file and folder structure here. You will find this familiar is you are already have Next.js or Gatsby experience.
static
: by default this directory contains a Svelte favicon, replace that with your own favicon. Also use this directory for logos and other assets which you do not need SvelteKit to generate at compile time (such as PGP public keys) in here.
svelte.config.js
does what is days on the tin! We will drill into a couple of options below.
3000
locally by default. There's a few different services and apps which also use that port so you might find you need to switch. To save having to remember command line switches, I would just update your package.json
file:"name": "my-sveltekit-app",
"version": "0.0.1",
"scripts": {
"dev": "svelte-kit dev --port 4000",
"build": "svelte-kit build && cp netlify/functions/backblaze.js functions/.",
"preview": "svelte-kit preview --port 4000",
"lint": "prettier --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .",
"format": "prettier --write --plugin-search-dir=. ."
},
...
4000
for both the dev server and the preview server.lang
attribute is helpful for Screen Readers to choose the best pronunciation. Although you can set the lang
attribute in app.html
you might consider setting it programmatically (if you do this delete the lang attribute in app.html
). There are a few options, varying in complexity. Let's see the simplest below. You might, instead, choose to use a Svelte Layout (explained further down) in a more complex project. If your project will have more than a couple of pages, it is worth creating a Svelte SEO component in which you can include meta tags for search engines and social media sites to ingest, alongside these accessibility tags. However for a small site you can just do something like this on each page (changing the title to match the page):<script>
// omit script element if it is not needed on your page
</script>
<svelte:head>
<title>my-sveltekit-app | Home Page</title>
<html lang="en-GB" />
</svelte:head>
<h1>Welcome to my SvelteKit site</h1>
<p>It is not too difficult to get started with SvelteKit...</p>
<svelte:head>
element is one of the special elements in Svelte, you can learn more about them in the Svelte tutorial. For more language codes see the W3C Internationalisation Guide.src/routes/__layout.svelte
, this is automatically interpreted as the default layout for your app. In that file you define your layout (e.g. header and footer) and just need to include a <slot />
element. This is where the content from whichever page is using the layout goes:<header>
<nav>
<a href="/.">Home</a>
<a href="/contact">Contact</a>
</nav>
</header>
<main>
<slot />
</main>
<footer>
<p>
A project by
<a aria-label="Open the Rodney Lab site" href="https://rodneylab.com/" target="_blank" rel="nofollow noopener noreferrer"
>RODNEY LAB</a
>.
</p>
</footer>
<header>
, <main>
, <footer>
etc.) where possible to keep the app accessible.src/routes/__error.svelte
:<script context="module">
export function load({ error, status }) {
return {
props: {
title: \`\${status}: \${error.message}\`
}
};
}
</script>
<script>
export let title;
</script>
<svelte:head>
<title>{title}</title>
</svelte:head>
<h1>{title}</h1>
{`
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
floc: true, // override default if you need to
// hydrate the <div id="svelte"> element in src/app.html
target: '#svelte'
}
};
export default config
In general to use environment variables in SvelteKit. First define them in a .env
file:
VITE_SECRET_SAUCE_RECIPE="onions,tomatoes,oregano,specialIngredient"
VITE_SUPER_SECRET_API_KEY="$ecret@p1Key
note the variables are prefixed VITE_
(you will omit this prefix for server side secrets).
To use the variables in a file, just import them like so:
const secretSauceRecipe = import.meta.env.VITE_SECRET_SAUCE_RECIPE
If you needed to use an environment variable in the rendered content (for example a public email address stored as an environment variable), you can use and reference it in exactly the same way. Be careful with what you output to the browser though!
If you get cryptic errors in the terminal, read on for some solutions.
Cannot split a chunk that has already been edited (0:7 – "import.meta")
[rollup-plugin-dynamic-import-variables] Unexpected token
[rollup-plugin-dynamic-import-variables] Unexpected token (6:627)
<style>
tag in a page which also uses environment variables.const variables = {
secretSauceRecipe: import.meta.env.VITE_SECRET_SAUCE_RECIPE,
superSecretAPIKey: import.meta.env.VITE_SUPER_SECRET_API_KEY,
};
export { variables as default };
<script>
import environmentVariables from '$lib/constants/environmentVariables';
const { superSecretAPIKey } = environmentVariables;
async function handleClick() {
const options = {
method: 'POST',
body: JSON.stringify({ secret: superSecretAPIKey })
};
await fetch('/.netlify/functions/secret-sauce-server', options);
}
</script>
<span>
<button on:click={handleClick}>
Order Secret Sauce
</button>
</span>
<style>
button {
padding: 1em;
font-size: 1em;
}
</style>
static/
at the project root. Put any files which SvelteKit does not need to process in here (e.g. small logo files and public PGP keys). You will need to create the folder if you selected a skeleton project when you initialised the app.src/lib/components
folder for SvelteKit for placing components in. As previously mentioned, another of the developer experience tweaks in SvelteKit saves you having to work out and then type out the relative path from the page you are editing to the components folder. The src/lib
folder is accessible throughout the project, just using $lib
. Here is an example for importing an SEO
component with path src/lib/components/SEO.svelte
, used on the home page:<script>
import SEO from '$lib/components/SEO/index.svelte';
let title = 'my-svelte-kit-app | Home';
let metadescription = 'my-svelte-kit-app - my first ever SvelteKit app';
</script>
<SEO {title} {metadescription} />
<h1>Welcome to my SvelteKit site</h1>
<p>It is not too difficult to get started with SvelteKit...</p>
7
we use a shortcut syntax (another developer experience perk in Svelte). This is equivalent to writing:<SEO title={title} metadescription={metadescription} />
<script>
import OpenGraph from './OpenGraph.svelte';
import SchemaOrg from './SchemaOrg.svelte';
import Twitter from './Twitter.svelte';
import website from '$lib/config/website.js';
import { VERTICAL_LINE_ENTITY } from '$lib/constants/entities.js';
export let title;
export let metadescription;
const { author, ogLanguage, siteLanguage, siteTitle, siteTitleAlt } = website;
const siteUrl = import.meta.env.VITE_SITE_URL;
const pageTitle = \`\${siteTitle} \${VERTICAL_LINE_ENTITY} \${title}\`;
const openGraphProps = {
facebookAppId: import.meta.env.VITE_FACEBOOK_APP_ID,
image,
metadescription,
ogLanguage,
pageTitle,
siteTitle,
siteUrl
};
const schemaOrgProps = {
author,
siteLanguage,
siteTitle,
siteTitleAlt,
siteUrl
};
const twitterProps = {
author,
twitterUsername: import.meta.env.VITE_TWITTER_USERNAME,
metadescription,
pageTitle,
siteUrl
};
</script>
<svelte:head>
<title>{pageTitle}</title>
<meta name="description" content={metadescription} />
<meta
name="robots"
content="index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1"
/>
<html lang={siteLanguage} />
<SchemaOrg {...schemaOrgProps} />
<OpenGraph {...openGraphProps} />
<Twitter {...twitterProps} />
</svelte:head>
<svelte:head>
tag. Here we have the accessibility lang
and title
elements defined within our SEO component. As well as those, we have a robots
tag which tells search engines we are happy for them to index the page. The Twitter and OpenGraph components work in a similar way so we won't look at those here. Let me know if you would like me to write a separate post on SEO for Social Media in SvelteKit, or more generally — it's a little too much detail to go into here. I could include a complete example, showing how to add and test social images and generate rich search engine results if you would find that helpful.application/ld+json
. We create this tag in a few stages. Take a look through the code then see the explanation below:<script>
import hash from 'object-hash';
export let author;
export let siteLanguage;
export let siteTitle;
export let siteTitleAlt;
export let siteUrl;
const entityHash = hash({ author }, { algorithm: 'md5' });
const schemaOrgWebsite = {
'@type': 'WebSite',
'@id': \`\${siteUrl}/#website\`,
url: siteUrl,
name: siteTitle,
description: siteTitleAlt,
publisher: {
'@id': \`\${siteUrl}/#/schema/person/\${entityHash}\`
},
potentialAction: [
{
'@type': 'SearchAction',
target: \`\${siteUrl}/?s={query}\`,
query: 'required'
}
],
inLanguage: siteLanguage
};
const schemaOrgArray = [schemaOrgWebsite];
const schemaOrgObject = {
'@context': 'https://schema.org',
'@graph': schemaOrgArray
};
let jsonLdString = JSON.stringify(schemaOrgObject);
let jsonLdScript = \`
<script type="application/ld+json">
\${jsonLdString}
\${'<'}/script>
\`;
</script>
<svelte:head>
{@html jsonLdScript}
</svelte:head>
40–42
we add the script to the HTML head. The @html
in line 41
is important for the correct compilation of our svelte code. In lines 33–37
we define the script tag which we inject into the DOM at end of the file. The funkiness in line 36
, is the workaround I mentioned to prevent ESLint messing up the code. What we need to output is simply </script>
, but to stop ESLint in its tracks, we wrap the opening angular bracket using the interpolated template variable syntax.