A bare bones, simple, portfolio website, powered by create-svelte. Check it out at linusbrannstrom.dev. Feel free to fork and tweak to your own desires.
Clone the project and install dependencies:
git clone https://github.com/linulas/portfolio-client.git
cd portfolio-client
yarn installCreate a .env file in the project root and add the following:
# Required
PRIVATE_DATA_URL=/data.json # the url to your data
# Optional
PUBLIC_SUPPORT_EMAIL=your@support.email # only used on error page if you want to give users a way to contact youAdd a static/data.json file in the project root and follow the ApiResponse scheme to map the data correctly.
You can use the content from this example gist to get started.
Start the development server:
yarn dev
# or start the server and open the app in a new browser tab
yarn dev -- --openOptimize images by adding them to the {project_root}/lib/images directory and run the script:
yarn generate:images
The corresponding image(s) should then be accessible through the image component:
<script lang="ts">
import Image from '$lib/Image.svelte';
</script>
<Image name="my_newly_generated_image" />To create a production version of your app:
yarn buildYou can preview the production build with yarn preview.
To deploy your app, you may need to install a different adapter for your target environment, I use Netlify.
It might just be a simple static website, but it still has some cool stuff going for it. The site is build to achieve great performance and security without any big sacrifices:
The biggest challenge to optimize a website is, IMO, images and CSP. Here I owe a big thanks to Rodney Johnson for sharing his solution which I could tweak to fit my needs.
To achieve a good lazy loading solution for my images, I use Vite imagetools to create optimzed versions of all images, and my custom svelte Image component to dynamically fetch images when mounted to the browser. The crown jewel here is the generate images script that generates js-files with meta-data about all images, and a base64 encoded placeholder to use while loading the fullsized image. The script also generates a ValidImage type which I can use for typesafety in the Image component.
Sveltekit provides an easy way to configure CSP headers, but that is not enough. For that to work with Netlify hosting, we need some extra hands-on work. We need to provide a _headers file at build-time to the build-folder for Netlify to pick up, which is done by the generate headers script. Since sveltekit injects its hydration-script as an inline script, with a different hash every time, we need to extract CSP from the meta tag, which is generated by sveltekit, to get the right hash. The generate headers script is therefore run directly after the build command. Thus we can achive great security with the proper headers and CSP set. Unfortunately, since I'm using svelte transitions to perform some cool animations, I'm forced to use inline styles. This is a known issue, and until sveltekit has made the transition over to the Web Animations API, I am alas stuck with allowing 'unsafe-inline' on the style-src directive.
Fun fact, since I spend most of my day in a code-editor, I wanted to reflect that in the design. Which is why i used Dracula theme as my colorpalette, which of course, is the theme I use in my editor.
I only serve my data from a json gist, which is fine for me since I don't have a lot of data and rarely change it. It is possible to use a cms instead, as long as the response data is formatted correctly, but I wanted to opt for simplicity and avoid unnecessary hosting costs.

