Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

blog/build-static-sveltekit-markdown-blog #9

Open
utterances-bot opened this issue Dec 30, 2021 · 93 comments
Open

blog/build-static-sveltekit-markdown-blog #9

utterances-bot opened this issue Dec 30, 2021 · 93 comments
Labels

Comments

@utterances-bot
Copy link

Let's learn SvelteKit by building a static Markdown blog from scratch - Josh Collinsworth blog

Learn the fundamentals of SvelteKit by building a statically generated blog from scratch, with Markdown support, Sass, an API, and an RSS feed.

https://joshcollinsworth.com/blog/build-static-sveltekit-markdown-blog

Copy link

For someone who starts learning SvelteKit, this tutorial is amazing!

Copy link

Amazing job! Thank you, I was kinda lost with the amount of outdated SvelteKit tutorials, but this one suited well for me. Also, I like that it is well written.

Copy link

sgeisenh commented Jan 2, 2022

What's the advantage of using a JSON endpoint over creating a helper function that returns the post metadata?

@josh-collinsworth
Copy link
Owner

What's the advantage of using a JSON endpoint over creating a helper function that returns the post metadata?

Great question! If all you're planning on doing with the posts is listing them out on the blog index page, then a helper function would be just fine. I like having an API, though, because it enables you to do lots of other things down the road—for example, fetch posts for a sidebar or recent posts list, or even add a search feature to the site. Plus, you can use your content on other sites if you want to.

Copy link

Under Finishing the Blog Index Page > Server-side Rendering with Load, I edited the blog/index.svelte page with the code provided but I'm told I can't use the keyword 'await' outside an async function. It's in the line: const response = await fetch('/api/posts.json')

What's gone wrong?

Copy link

sgeisenh commented Jan 3, 2022

Under Finishing the Blog Index Page > Server-side Rendering with Load, I edited the blog/index.svelte page with the code provided but I'm told I can't use the keyword 'await' outside an async function. It's in the line: const response = await fetch('/api/posts.json')

What's gone wrong?

The arrow function where that line appears must also be marked "async":

export const load = async ({ fetch }) => {
  const posts = await fetch('/api/posts.json')
  const allPosts = await posts.json()

@josh-collinsworth
Copy link
Owner

The arrow function where that line appears must also be marked "async":

Good eye, and thanks for the reply! I've just updated the code in the post.

Copy link

pejato commented Jan 4, 2022

Josh, this was a really great article. I started to make a personal blog a few months back with SvelteKit but couldn't stick with it. Most everything here just worked, which was great. Also, your website is beautiful 😎

One thing I'll add is that I did run across this error message when I tried using the page param for load. The error message is fairly self explanatory, of course.

`page` in `load` functions has been replaced by `url` and `params

@josh-collinsworth
Copy link
Owner

One thing I'll add is that I did run across this error message when I tried using the page param for load. The error message is fairly self explanatory, of course.

`page` in `load` functions has been replaced by `url` and `params

Ah, thanks for bringing that up! The hazards of blogging about a pre-1.0 technology 😅 I'll see about adding an update for that.

Copy link

This post is incredible!!

A note from the https://kit.svelte.dev/docs#routing-endpoints docs — fetch is now supported in endpoints, and everywhere!

Copy link

Hi Josh,

thanks for the great tutorial!

I noticed, however, a white flicker when scrolling this page to the top/bottom by using the Pos1/End keys. It only happens in Firefox and only in Dark Mode. (I first noticed it in my computer's dev environment but then I also noticed it here.)

I use TailwindCSS (which I guess you're not using), and I found pages that have dark mode but don't flicker (for example, https://adityatelange.github.io/hugo-PaperMod/posts/papermod/papermod-features/).

Do you see it as well? Any idea what's going on?

Gunnar

@josh-collinsworth
Copy link
Owner

Do you see it as well? Any idea what's going on?

@freeform99 Looks like it's nothing to do with SvelteKit or Tailwind; looks like Firefox's rendering engine just allows the default background to seep through for a split second when scrolling tall pages very quickly.

My current implementation of dark mode only sets the background color on the #app element, which covers the whole html body. Apparently forcing Firefox to render that much content that fast just causes a blip where the html body background shows through. Easily fixable by moving the background color to the html/body tag (probably a good idea anyway, I just wasn't always setting classes that high in the DOM).

Copy link

Wolsten commented Feb 13, 2022

Great blog Josh, wish I had come across it a couple of months ago - looks like I have some refactoring to do :-)

Copy link

Josh, God bless you, this is an excellent tutorial for understanding endpoints in Svelte. You do mention extending this API to use the resolver default.render to access the .md content. How would you do this?

Please point me in the right direction if possible! I'm trying to get around the dynamic component restriction of building static sites. 🙏

@josh-collinsworth
Copy link
Owner

You do mention extending this API to use the resolver default.render to access the .md content. How would you do this?

It's similar to how the endpoint grabs the metadata from the resolver, just with an extra step (since default is a reserved keyword in JavaScript):

const post = await resolver()
const content = post.default.render()

If you run that inside the endpoint code, alongside where we get the metadata and the postPath, then you should have the HTML output of the post's content in the content variable.

Copy link

You are an absolute star. That's it. Such an unbelievable help.

Copy link

This is one of the best tech tutorials I've ever completed - it is clear, concise, error-free, and very well illustrated. Thank you!

Copy link

After feeling very lost trying to get started with svelte-kit, I stumbled across your excellent tutorial, and now I see the light. Thanks so much for your clear and thorough explanations. I feel like this should be a required tutorial for anyone starting out with svelte-kit. I'm definitely buying you a coffee!

Copy link

bnonn commented Mar 5, 2022

Josh, thanks for writing this, it is very helpful. I have been investigating SvelteKit for creating an app, but have been pondering whether to also adopt it for an SSG. I prefer to not use a bunch of different tools if one will cover all the use-cases...

However, reading this, it seems like SvelteKit adds a lot of extra work compared to something like 11ty or Astro. (I'm very familiar with 11ty, but looking at Astro for its ability to easily integrate Svelte components.) There's a lot of boilerplate required to do something like set up and retrieve a collection, for instance. Am I getting an accurate picture, or am I missing something?

@josh-collinsworth
Copy link
Owner

josh-collinsworth commented Mar 7, 2022

@bnonn I think your picture is accurate. As mentioned in the intro, SvelteKit definitely isn't the simplest thing you could use for a static site generator. It's more powerful and free-form, which also makes it more complex. 11ty and Astro are both great choices for pure static sites.

Copy link

JappIC commented Mar 8, 2022

Hello. Thank you very much for this great tutorial. A few months ago I made one of WebJeda and now I update and optimize it following yours.

Everything works fine and now my code looks much more readable.

I just wanted to tell you about a problem that is happening to me after I updated SvelteKit yesterday. When you interact with the web from the links everything works fine, but for some reason if I copy the link from some post... and paste it into a new browser window, the url throws a 404 error.

The application is compiled as static and hosted on an apache server, in previous versions it worked.

Again thank you very much for the tutorial.

Copy link

@ajbajbajb I get part of the object with html visible in there if I console.log it, but then it crashes halfway through with the error: Cannot read properties of undefined (reading 'data').

I suspect there's something in the .md files that breaks it, maybe because inside that .md file I fetch an endpoint? Anyone has an idea?

@josh-collinsworth
Copy link
Owner

I just wanted to tell you about a problem that is happening to me after I updated SvelteKit yesterday. When you interact with the web from the links everything works fine, but for some reason if I copy the link from some post... and paste it into a new browser window, the url throws a 404 error.

Sorry, @JappIC, I'm not able to replicate this. Maybe it's a version issue? If you run npm update, does it still happen? And if so, if you could link to a repo where the issue can be seen, I'll take a look.

@JappIC
Copy link

JappIC commented Mar 11, 2022

Lo siento, @JappIC , no puedo replicar esto. ¿Quizás es un problema de versión? Si corres npm update, ¿todavía sucede? Y si es así, si pudiera vincular a un repositorio donde se puede ver el problema, le echaré un vistazo.

Yes, I updated to the latest version of Svelte and added...:

prerender: { default: true, },
...as requested now.

I realized that if I add .html at the end of the url it works.
I sent you access to my repository

Thank you very much for your attention

@josh-collinsworth
Copy link
Owner

josh-collinsworth commented Mar 11, 2022

@JappIC I'll take a look. One thought: this may be an issue with the host's web server configuration. Where is it hosted currently?

On Netlify, Vercel, etc., a route like /post-title should automatically fall back and load the /post-title.html route behind the scenes. Maybe this host is not set up to do that?

PS the site looks great! 👏

[EDIT]: I also wonder if maybe the deploy configuration mentioned in this issue might help.

@JappIC
Copy link

JappIC commented Mar 11, 2022

PS the site looks great! 👏

Thank you very much!!!

It's an apache server "banahosting", that's why I want it to be static. I also have my website hosted with an older version of svelte and it works. However, the application to which I gave access is updated to the latest version of svelte and generate this problem.

The 404 error is generated by the server, not the application.

I don't think the problem comes from what I learned from you in this post, which helped me a lot to improve the code. I think it's something from svete

Copy link

I can't figure out how you're dynamically getting a single post, like here:

    const post = await import(`../../../lib/posts/${params.post}.md`);

Sveltekit is complaining about SSR / not being able to dynamically import a module. Alternatively, usingimport.meta.glob can't handle variables inside the string literal.

I resorted to just getting all the posts and then filter out the single post.
Are there some additional settings to allow for the code in [post].svelte to work?

Copy link

Great write up, Josh! Big SvelteKit fan myself and was currently looking for some supplemental examples for how folks like to handle markdown with SvelteKit and you didn’t disappoint. Well done and thanks for all the effort!

Copy link

OMG this post is all I needed to start my SvelteKit + MD project.. thank you so much Josh!

I have only one question.. do you have any experience of using this stack + internationalization???

@stephang
Copy link

stephang commented May 20, 2022

This is really a great article! As SvelteKit's official docs are still somewhat lean, your article is very helpful. Thanks a lot!

One question, though: I wonder if in my adapter-static-configured project, if I can have routes built with Vite. In your example it's the routes for /api/posts.json and /rss.xml.

To reproduce my use case:

  • Use Node v16.15.0
  • clone your project
  • run npm run build
  • Run this in nginx:
    docker run -v $(pwd)/build:/app -p 3000:8080 bitnami/nginx:latest
  • open http://localhost:3000/rss.xml.
  • Returns 404

If I run npm run dev, I can open the route and get some nice RSS data.

Did you ever have this working on a statically built site? Any idea if this is supported by SvelteKit?

Copy link

This is an awesome project! Thanks for making it available to all!

@dmorgorg
Copy link

dmorgorg commented Jan 10, 2023

Just revisited the site after a while; still as helpful as ever! And thanks for keeping it updated.

I had to install prismic-themes for any styling of code blocks

Thanks again; this is my favourite Sveltekit tutorial and it has taught me a lot! :)

Copy link

How can we escape angle brackets in markdown files? I've tried tried < > and other options but each gave me a parsing error like "Unexpected token". < works but looks like code :)

Copy link

Awesome!! 😃

Copy link

Just a fabulous article Josh. This is exactly what I need for my project, so I'm going to go through it again with my actual site and content to build a prototype

Copy link

zmccj commented Feb 16, 2023

This is AWESOME !!!
Thank you Josh!

Copy link

I really enjoyed the content! I learned a lot.

Does anyone have an example of how to apply pagination?

Copy link

Absolutely loved the tutorial, I'm a newbie and I'm trying to understand the index.js used to import the MD files, I played around with the code and ended up with this:

var MDs = new Object;
    for (const [path, importFunc] of Object.entries(import.meta.glob(`/src/routes/diaryof/*.md`))) { // The `...` is a template literal, how cool!
        let data = await importFunc()
        MDs[path.slice(11, -3)] = data.metadata
    }

is this a valid alternative to the mapping function or do I have to study promises better?

Copy link

I have a build problem after importing a static adapter.

@sveltejs/adapter-static: all routes must be fully prerenderable, but found the following routes that are dynamic:

Is your guide complete? Works that static adapter with approach 2?

Copy link

git-no commented Mar 19, 2023

@josh-collinsworth FYI
With Contentlayer implementation and handling of markdown files is much easier.

Copy link

Maratzz commented May 24, 2023

Thank you so much for this article Josh, it helped me figure out some SvelteKit concepts, it's an amazing tool! Do you mind if I translate your article in French, with full credits and link here of course? The ressources outside the English environment are quite lacking to say the least.

There's something I couldn't wrap my head around using the API endpoint and filtering. I wanted to create a single API endpoint listing all the posts regardless of where they are by modifying const allPostFiles = import.meta.glob('/src/routes/blog/*.md') to const allPostFiles = import.meta.glob('/src/routes/*/*.md') and from then using some kind of filtering to display them in their correct routes according to the categories, but I can't figure out how or where I should do that. Can you point me in the right direction?

EDIT: I figured it out, I was trying to apply filter() before receiving the response.json().

@josh-collinsworth
Copy link
Owner

@Maratzz Glad you were able to figure it out. :) And yes, you're welcome to translate content with attribution. Thanks!

Copy link

Hi Josh, thank you so much for this tutorial. I am trying to use an alias for dynamic routing:

const post = await import(`$posts/${params.slug}.md`)

where I configured $posts in svelte.config.js as $posts: './src/posts'. This avoids a relative path like ./../../../posts. However, this doesn't seem to be working. Can you help me out here?

Copy link

Hi Josh, another question. I tried adding the scss :where(h2, h3, h4, h5, h6) code block to a <style lang="scss"> tag inside +page.svelte in the /blog/[slug] folder. Can't we do this? Does it have to be inside $lib/styles/style.scss?

Copy link

This is Incredible, thank you very much

@leokolt
Copy link

leokolt commented Jul 22, 2023

Is super content. Thanks

Copy link

leokolt commented Jul 22, 2023

Hi. Can you tell me how to make articles that have the draft: true parameter added to the frontmetter do not appear at all. I added this to the api/posts/server.js and articles are not displayed in the blog, but the article itself is available by url

import { getMarkdownPosts } from '$lib/utils/getPosts'
import { json } from '@sveltejs/kit'

export const GET = async () => {
  const allPosts = await getMarkdownPosts()

  const notDraftPosts = allPosts.filter(post => post.meta.draft === false)

  const sortedPosts = notDraftPosts.sort((a, b) => {
    return new Date(b.meta.date) - new Date(a.meta.date)
  })

  return json(sortedPosts)
}

Copy link

This is a great post. Thank you very much! It is very helpful.

Copy link

Thank you so much, this is so useful !
But, I just can't understand how "resolver" works ; "resolve" exists in the doc but not "resolver". Could you explain that to a brave neophyte like me, please ?

Copy link

torb-no commented Sep 3, 2023

Sorry if this is a very novice question (it's been a while since I've used Node). You save all of npm packages to devDependencies (as opposed to just dependencies). Is this because SvelteKit generates what should run in production for you? Reason I ask is that I always want to understand the why of everything I'm doing.

Thanks for a great and detail guide! I'm using it to get my blog on to SvelteKit (and learn it in the process). I really appreciate that you explain why and how you are doing things, making it possible for me to use that understanding to solve things the way I want and not blindly follow the tutorial.

@josh-collinsworth
Copy link
Owner

@leokolt You can see how I handle hiding post drafts here: josh-collinsworth/joco-sveltekit/src/lib/assets/js/utils/fetchPosts.ts


@Mellifico "Resolver" is just my own word. When you import a markdown file, you get an object where the key is the path to the file, and the value is a function that generates its content, something like this:

{
  '/blog/my-post.md': asyncFunctionThatGetsThisPostsContent()
}

I just call that function "resolver" because you have to assign it a name when looping over the entries. You could call it whatever you want. It's just a function that runs asynchronously and (eventually) returns all of the details of the post for you.


@torb-no My understanding is: devDependencies is for things that are required to either help with development (like eslint, prettier, a dev server), or things that help with building and compilation. These are dependencies that, in other words, help the site get built, but not that actually run on the production site.

Sass is a good example; Sass does not run on the live website, since by the time you get the code to production, all the Sass code has been compiled away to pure CSS. So setting something as a devDependency signals to the build step that the package is not needed in production.

Copy link

Such a good article!

@jason-johnson
Copy link

I'm trying to follow through the tutorial and I've run into an issue: after I install mdsvex and modify svelte.config.js, I created a +page.md file as instructed but now it fails with this error:

Files prefixed with + are reserved (saw src/routes/uses/+pages.md)

I'm using vitePreprocess (seems to come default that way now) but I switched to sveltePreprocess to check and it didn't change anything. I've stopped the server (it restarts automatically when it sees the config change, but just to be sure) and started it again but that doesn't fix it.

Copy link

Assuming you're starting from scratch, #1 seems useful if you want to colocate markdown files with images. But it can be annoying since you have to name the path and the file title. In #2 you'd have to name the .md file and the title which might as well be the same as naming the folder and title. So you end up naming two things either way.

Copy link

btw: think

If you followed approach #1 above and have every post inside its own individual folder, you'll need to change the import path to end /blog/*/.md, to go one level deeper.

should be: /blog/**/*.md

@RIGIK93
Copy link

RIGIK93 commented Jun 27, 2024

I Loved it! Your tutorial really helped with my blog, thank you!

Copy link

honnip commented Aug 20, 2024

I can't figure out how you're dynamically getting a single post, like here:

   const post = await import(`../../../lib/posts/${params.post}.md`);

Sveltekit is complaining about SSR / not being able to dynamically import a module. Alternatively, usingimport.meta.glob can't handle variables inside the string literal.

I resorted to just getting all the posts and then filter out the single post.
Are there some additional settings to allow for the code in [post].svelte to work?

@sebbasim
This may be because a vite configuration is missing.

vite.config.ts:

import { sveltekit } from "@sveltejs/kit/vite";
import { defineConfig } from "vite";

export default defineConfig({
	plugins: [sveltekit()],
	assetsInclude: ["**/*.md"],
});

Add the assetsInclude option. https://vitejs.dev/guide/assets

I think it might be because I'm using vitePreprocess rather than sveltePreprocess, but I haven't checked.

Copy link

Converting to web development is too much. It is difficult to get good references on recent frameworks, fonts, CSS, best practices, web design and other interesting things that you will find in the future; Well, there is a lot of noise out there and few tutorials go beyond the basics. This tutorial takes complex topics and makes them simple: you choose a problem, choose what technologies you will need and explain their use without neglecting the design and responsiveness of the site in the most modern framework today.
Thanks for this amazing tutorial!

Copy link

jimmux commented Dec 11, 2024

I just used this guide to add a blog section to a static site I was already doing in SvelteKit as a learning exercise. In no time at all, my understanding of SvelteKit is exponentially deeper. Thanks for the great write-up.

For anyone like myself who would like the markdown content to work with utility-class CSS frameworks like Tailwind, it's easy with the addition of rehype-class-names, e.g. this made mine work better with Bulma:

npm install -D rehype-class-names

In svelte.config.js:

preprocess: [
  ...
  mdsvex({
      extensions: ['.md'],
      rehypePlugins: [[addClasses, {
        "h1,h2": "subtitle",
        p: "block"
      }]]
    })
]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests