
Security News
Package Maintainers Call for Improvements to GitHub’s New npm Security Plan
Maintainers back GitHub’s npm security overhaul but raise concerns about CI/CD workflows, enterprise support, and token management.
@jdeighan/blog
Advanced tools
was the web page at:
https://joshcollinsworth.com/blog/build-static-sveltekit-markdown-blog
First, scaffold a SvelteKit app:
(Actually, FIRST, make sure you have NodeJS and Git installed)
$ npm create svelte@latest blog
$ cd blog
$ mkdir src/lib
$ npm install
$ git init && git add -A && git commit -m "initial commit"
$ npm run dev -- --open
The last command starts the "development server". We will keep the development server running throughout this tutorial. To enter any commands from this point on, open a second terminal window.
Edit the src/routes/+page.svelte file - it's your home page:
<h1>My Blog Posts</h1>
<p>My blog posts will go here eventually</p>
Observe the immediate change to the web site
Add some directories and files to the src/routes folder: e.g. src/routes/about/+page.svelte:
<h1>About my blog</h1>
<p>I'm learning Svelte and SvelteKit</p>
and src/routes/contact/+page.svelte:
<h1>Contact me</h1>
<p>Via email: john.deighan@gmail.com</p>
FYI, I almost never check this email address, but
I'm not ready to publish the email address that I actually use.
You should now be able to browser to any of these URLs and see the new pages:
http://localhost:5173/
http://localhost:5173/about
http://localhost:5173/contact
What we really want is to have a menu at the top of the page with links for:
So, next, let's investigate svelte layouts.
A file named +layout.svelte in the src/routes/ folder will act
as a layout file. That is, when you visit a page like your
'about' page using a URL like: localhost:5173/about
, the page
+layout.svelte will actually be served, but on that page there
is an HTML <slot/>
element and that is where the contents of
about/+page.svelte
will be placed. So, first, create this page
src/routes/+layout.svelte:
<nav>
A menu will go here
</nav>
<main>
<slot/>
</main>
<footer>
Built with SvelteKit!
</footer>
Now, look at your web site. You should see your header and footer, from the layout file, with the requested page's contents placed in between.
This refers to a layout with the following properties:
There is a menu at the top of the page that stays there and doesn't move as the web site is used. It stays there even if the current page has a lot of content and the user scrolls down to view information that wasn't initially visible.
There is a footer at the bottom of the page that stays there and doesn't move as the web site is used, even when scrolling down.
There's an area in between where your content appears. If it contains more content than the area can hold vertically, a scroll bar appears that allows you to scroll the contents so all of it can be viewed. Also, we're going to limit the width of this area to 800px. You can choose any value that works for you, but it's very difficult to read text if the content is too wide because your eye will find it difficult to find the beginning of the next line when you're finished reading a line.
This is easiest to achieve using CSS grid layout and media queries. We'll keep it simple, and we'll only use CSS grid layout at the top level of our web site. We'll also use CSS variables to make it easy to change things like text and background colors throughout the document by making changes in just one place.
First, add the following <style>
block to src/app.html,
somewhere in the <head>
section (I put it at the end
of the <head>
section):
<style>
:root {
--bkg-color: GhostWhite;
--text-color: Black;
--menu-bkg-color: #09CABE;
--menu-text-color: White;
}
* {
box-sizing: border-box;
}
html, body {
height: 100vh;
width: 100vw;
margin: 0;
padding: 0
}
body {
font: 15px sans-serif;
display: grid;
grid-template-areas:
"left top right"
"left middle right"
"left bottom right"
;
grid-template-rows: auto 1fr auto;
}
/* NOTE: Using a CSS variable in place of '800px' doesn't work */
@media (max-width: 800px) {
body {
grid-template-columns: 0 100% 0;
}
}
@media (min-width: 800px) {
body {
grid-template-columns: 1fr 800px 1fr;
}
}
</style>
Secondly, in src/app.html, add id="svelte"
to the
<div>
element inside the <body>
:
<div id="svelte">%svelte.body%</div>
Lastly, we need to use the grid areas set up in this file inside the src/routes/+layout.svelte file. Add this style block to the bottom of the layout file:
<style>
main {
grid-area: middle;
padding: 15px 5px;
overflow: auto; /* scroll bars appear with large content */
background-color: var(--bkg-color);
color: var(--text-color);
}
nav, footer {
background-color: var(--menu-bkg-color);
color: var(--menu-text-color);
text-align: center;
margin: 0;
padding: 5px 0;
}
nav {
grid-area: top;
}
nav a {
color: var(--menu-text-color);
text-decoration: none;
padding: 0 8px;
display: inline-block;
}
nav a:hover {
color: white;
}
footer {
grid-area: bottom;
}
</style>
I've added background colors to the 3 areas to make it easier to see where they are. You can change or remove them if you like.
NOTE: When running the development server, when you make a change to a file, the web page in your browser is automatically updated. However, some things are not noticed by SvelteKit and you'll need to stop and start the development server. One of those things is any change to your src/app.html file. Another is any change to your svelte.config.js file. At this point, you should restart the development server and probably refresh the web page.
We'll enhance it later, but for now, let's just set up a
simple menu that will give us access to all of our pages.
Change the <nav>
element of your src/routes/
+layout.svelte file to:
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
<a href="/contact">Contact</a>
</nav>
When authoring your actual blog posts, you'll find that
it's much easier if you use a language called markdown
.
We'll enable using markdown, then I'll show how it's used.
First, install the mdsvex
package:
$ npm install -D mdsvex
Next, modify your svelte.config.js file like so:
import adapter from '@sveltejs/adapter-auto';
import {mdsvex} from 'mdsvex';
export default {
extensions: ['.svelte','.md'],
kit: {
adapter: adapter()
},
preprocess: [
mdsvex({
extensions: ['.md'],
})
],
};
NOTE: Whenever you change your svelte.config.js file,
you'll need to restart the development server. Open the
terminal window where it's running, enter Ctrl-C to
stop the server, then restart it with npm run dev
.
That's all you need to do! Let's test it by changing
your about
file to a markdown file.
Replace your src/routes/about/+page.svelte file with
this src/routes/about/+page.md file:
About my blog
=============
I created this **blog** mainly to allow me to document
**all** of
the projects that I'm working on. My main goals are:
1. Learn SvelteKit
2. Use Immer
3. Learn CoffeeScript
3. Create a web site for learning Chinese
4. Develop a language to enhance CoffeeScript
5. Develop a language to enhance Svelte
(don't worry about the incorrect numbering. I did it
intentionally to show that markdown uses the numbers to
determine that it's dealing with a numbered list, but
markdown automatically substitutes consecutive numbers)
Code Blocks
-----------
Here is some sample JavaScript code:
```javascript
str = 'abc' + ' ' + 'xyz';
console.log(`str = '${str}'`);
```
Here are some things you'll want to know about markdown:
javascript
,coffeescript
,text
,css
,
svelte
and many others.If you want to get better syntax hilighting for your
code blocks, like the javascript block above, you can
to go https://github.com/PrismJS/prism-themes
and
find a theme you like (I use prism-gruvbox-light.css).
To use it, copy the source code
for the theme, put it in a file named markdown.css in
your static
folder, which is in your root folder, then
in your app.html file, add this to your <head>
section:
<link rel="stylesheet" href="%sveltekit.assets%/markdown.css" />
Our first blog post will be about a state management library
named immer
. I want to use it because of how it will enable
me to debug problems with my data structures. The steps to
add a new blog post to our blog site are:
Add a new directory inside of src/routes/posts
. The new
directory's name will be used in the link on your posts
web page, so it should be descriptive of what the post is
about. Here, we'll simply name the directory immer
.
Inside the new folder, create the file +page.md
. It will
contain the text of the post. Here, we'll start by just
putting a top-level heading with the text 'immer is cool!'.
On the page at src/routes/+page.svelte
(the home page),
replace the paragraph saying "My blog posts will go here
eventually" with:
<ul>
<li><a href="/posts/immer">immer</a></li>
</ul>
We want to create a completely static web site. That means that the web site never changes - well, at least until you add content, rebuild it, then re-deploy it. There's no database or pages that change dynamically while the web site is running. That will enable us to put the web site on the Internet at no cost.
Install SvelteKit's static adapter. This will allow you to create a static web site to deploy to the Internet.
> npm install -D @sveltejs/adapter-static@latest
Configure the adapter by opening the file
svelte.config.js
and changing adapter-auto
to
adapter-static
:
To create a static web site, you must tell svelte that all
pages will be pre-rendered. You can do that by adding the
following file src/routes/+layout.server.js
:
export const prerender = true;
You can now build your app as a static web site by executing:
> npm run build
After that, you should check that a folder named build was created in your root folder. It contains your entire app as a set of files. You can preview this version of the app by executing:
> npm run preview -- --open
This will automatically open your web page in your browser. It should look exactly the same as the version running the development server.
Run surge to deploy your app to the Internet:
> surge ./build
When prompted, enter your email address and a password. If you have an existing surge account, use that. Otherwise, a new, free, account is set up for you.
Note that we've specified the project to upload - ./build If you're prompted for the project, make sure you use that.
When prompted for a domain, surge will suggest one,
but you can change that in place - use your left arrow key to position
the cursor, backspace to delete existing characters, and normal keys
to edit the name. Just make sure it ends with
.surge.sh
. If the name is already in use, you will
be told that and allowed to try again with another name.
For the purpose of this example, we'll use jd-blog.surge.sh
.
NOTE: You will not be able to use that name for your project
because I'm using it! Try using your initials
in place of mine (jd).
I will refer to the domain you used as in the following
When done, your web site will be on the Internet!
try entering the URL http:// or https:// in your browser and check it out! The first, non-SSL URL should actually redirect to the second SSL URL.
Modify package.json by adding key under scripts:
"deploy": "npm run build && surge ./build --domain https://<domain>"
Be sure to 1) replace with your domain, and 2) add a comma to the end of the preceding line - JSON requires that keys be separated by a comma and (unfortunately) that the last line in a set of keys does NOT have a trailing comma.
Try making a change to your home page, i.e. the file src/routes/+page.svelte
,
then re-deploying. For example, add the line
The web page running the development server (if you still have it running), should show the change immediately. To deploy that version to the Internet, execute the command:
> npm run deploy
which will re-build your project, then deploy it to surge's
servers. Try the URL https://<domain>
in your browser. If
you already had that page open in your browser, you can just
refresh the page. Pages deployed to the Internet won't
automatically update when changes are made the way they do
when you're developing.
Normally, you wouldn't deploy the new web page without first testing it with the development or preview server. However, in this case the change was very simple, and I wanted to show how simple deploying a new web page can be.
From this point on, we will make all changes locally. Just remember that when the web site works as you intend and you want that version of the web site on the Internet, you can simply execute:
> npm run deploy
I've added a few more blog posts to the site. The instructions for doing so are above, and I'm not going to go through the additional blog posts I created at this point. But the home page source code now looks like this:
<h1>My Home Page</h1>
<ul>
<li><a href="/posts/immer">immer</a></li>
<li><a href="/posts/get-caller">get JavaScript call stack</a></li>
<li><a href="/posts/ideas">Ideas</a></li>
</ul>
I'd like to style the links to look better, and possibly even work better, but at this point I've already got 3 of them, and eventually there will be many more. It would be better if we created a Svelte component that encapsulated the styling of the post links, along with how the links worked, then put 3 of those components on the home page.
We'll create a file that defines the new component. That file will
live in the src/routes
folder and be named BlogPost.svelte
. Note
that since the file name doesn't start with a +
character, SvelteKit
won't think that it's a web page. In fact, SvelteKit will completely
ignore the file unless we specifically import it, which we will do
on the home page itself. First, create the BlogPost.svelte
file
and place it in the src/routes
folder:
{#if label}
<a href="/posts/{name}">{label}</a>
{:else}
<a class="capitalize" href="/posts/{name}">{name}</a>
{/if}
<script>
export let name;
export let label = '';
</script>
<style>
a {
text-decoration: none;
display: block;
padding: 3px 20px;
font-size: 18px;
}
a.capitalize {
text-transform: capitalize;
}
</style>
Things to know:
<script>
block and only one <style>
block.
I don't know why, but it's not under my control.{#if label}
is a Svelte
if
block. It conditionally renders one of a set of HTML
blocks. The intention here is to use a label
as is if
provided, but if no label is provided, we want to display
the name
provided, but capitalize the first letter.url
and label
. In the component file, you indicate
which properties it supports by exporting variables with those
names inside a <script>
block. Here, I've also provided
default values for them, though that's not required.<script>
or <style>
blocks if they exist), you can put a name inside {
and }
and it will be replaced with the value of that variable. In fact,
you can really put any valid JavaScript expression in there and
the result of evaluating that expression will be used. This can
be done for regular text content or for the value of HTML
element attributes.<style>
block will ONLY apply
to HTML elements in this file. Those styles will not bleed into
other elements on your web site.Having created this component, let's see how to use it. Change your
home page (at src/routes/+page.svelte
) to:
<h1>My Home Page</h1>
<BlogPost name='immer' label='immer'/>
<BlogPost name='get-caller' label='get JavaScript call stack'/>
<BlogPost name='ideas'/>
<script>
import BlogPost from './BlogPost.svelte'
</script>
Things to know:
BlogPost
component, you need to import it inside
a <script>
block.import
statement.<script>
block if needed, followed by a
<style>
block if needed. Many other people prefer to put the
<script>
block first. I think that content is king and
therefore should come first.So, I've created this file to describe how this blog was
created. However, I don't want to put it inside my project
directory because I anticipate deleting it and re-creating it
using these very instructions. So, it exists outside my project
directory. Still, I'd like the blog to include these instructions.
To accomplish that, I'll add a step to the build process that
copies the file from it's current location to the directory
that holds my blog posts. Then I can add a link to the home page
for it. To make that happen, make a change in the package.json
file for the script build
:
"build": "cp ../README.md ./src/routes/posts/how-to-build/+page.svelte && vite build",
$ npm install mathlifier
Follow blog instructions
FAQs
Create a blog using SvelteKit =============================
We found that @jdeighan/blog demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Maintainers back GitHub’s npm security overhaul but raise concerns about CI/CD workflows, enterprise support, and token management.
Product
Socket Firewall is a free tool that blocks malicious packages at install time, giving developers proactive protection against rising supply chain attacks.
Research
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.