Sharing tutorials, concepts, events, etc., with video blogs is entertaining and engaging. Additionally, blog posts that contain videos receive more inbound links and views than those that don't.
In this post, we will learn how to build a video blog in Svelte using Cloudinary as our video hosting service.
Sandbox
We completed this project in a CodeSandbox. Fork and run it to get started quickly.
GitHub repository
https://github.com/Olanetsoft/Build-a-video-blog-in-Svelte
Prerequisites
To follow along, you’ll need the following:
- Basic knowledge of JavaScript
- A Cloudinary account for storing and delivering our images and video (Create a free account here)
- A Node.js installation on your machine
Getting started with Svelte
Svelte is a revolutionary new method for creating user interfaces. Svelte puts that work into a compile stage when we build our app, as opposed to standard frameworks like React and Vue, which perform most of their work in the browser.
Project setup and installation
To create a new project, use the command below to scaffold a new project:
1npm init svelte@next <project-name>
A series of prompts will appear as a result of the command. Here are the defaults we recommend:
The command creates a Svelte project called video-blog-in-svelte
.
Next, we need to navigate into the project directory, install some additional packages we will use later in this article and start the development server using the command below.
1cd video-blog-in-svelte && npm i && npm i glob front-matter remark remark-html @mapbox/rehype-prism rehype && npm run dev
The additional packages we installed are explained below:
1glob # To import multiple files with a * syntax23 front-matter # To extract frontmatter and body from markdown45 remark remark-html @mapbox/rehype-prism rehype # For HTML parsing
Svelte will start a development environment accessible by default at http://localhost:3000
Building the video blog
In this section, we’ll go over building a video blog. First, we need to define our project structure and create some directories and files as indicated below:
1src/components/ -> // Svelte Components directory2 src/components/post-card.svelte -> // Post card component34 src/lib/ -> // Directory for building our pages from markdown5 src/lib/handle-markdown.js -> // File to handle markdown67 src/posts/ -> // Directory for Markdown post files8 src/posts/first-post.md -> // markdown for first post9 src/posts/second-post.md -> // markdown for second post1011 src/routes/ -> // Router with all available pages12 src/routes/posts -> // Endpoints and pages for the route /posts/1314 src/routes/api.js // File to implement the functionality to retrieve post dynamically1516 src/routes/__Layout.svelte -> // A layout design file for all our pages
After creating the directories and files, we should have something similar to what is shown below:
Next, update the __layout.svelte
with the following code snippet.
1<header>2 <h1><a href="/">Home</a></h1>3 </header>4 <slot />56 <style>7 header {8 display: flex;9 justify-content: space-between;10 border-bottom: 1px solid lightgray;11 padding-left: 4vw;12 padding-right: 4vw;13 }1415 h1 {16 margin: 5;17 font-weight: 400;18 font-size: 25px;19 }20 </style>
Let’s update index.svelte
with the following code snippet.
1<svelte:head>2 <title>Build a video blog in Svelte</title>3 <meta name="description" content="Build a video blog in Svelte!" />4 </svelte:head>56 <main>7 <h1>Build a video blog in Svelte</h1>8 </main>910 <style>11 main {12 display: flex;13 flex-direction: column;14 align-items: center;15 justify-content: center;16 margin-top: 20px;17 }1819 /* card style */2021 .post {22 display: flex;23 flex-direction: column;24 align-items: center;25 justify-content: center;26 margin-top: 20px;27 }28 </style>
As shown above, we have completely set up our layout and can now implement the blog retrieval functionality in the following step.
Let’s update the handle-markdown.js
file inside the components
directory with the following code snippet.
1//handle-markdown.js23 import fs from 'fs';4 import glob from "glob";5 import fm from "front-matter";6 import {remark} from "remark";7 import html from "remark-html";8 import rehypePrism from "@mapbox/rehype-prism";9 import {rehype} from "rehype";1011 /**12 * import all markdown files in the specified path, extract front matter and convert to HTML13 * @param {string} markdownPath path to folder containing the markdown files (ends on /)14 * @returns [{path, attributes, body}]15 */16 export function importMarkdowns(markdownPath) {17 let fileNames = glob.sync(`${markdownPath}*.md`);18 return fileNames.map((path) => convertMarkdown(path))19 }2021 /**22 * convert markdown to object with attributes and HTML23 * @param {string} path path to file24 * @returns25 */26 export function convertMarkdown(path) {27 let file = fs.readFileSync(path, 'utf8');2829 let { attributes, body } = fm(file);30 let result = remark().use(html).processSync(body).value31 result = rehype().use(rehypePrism).processSync(result).value32 const retValue = { path, attributes, html: result};33 return retValue34 }35 export function convertToPostPreview(object) {36 const url = object.path.replace(".md","").replace("src/", "");37 return {...object.attributes, url};38 }
The code snippet above will be used to find all posts, extract the frontmatter, and parse the body to HTML.
Next, update the post-card.js
inside the components
directory with the following code snippet.
1<script>2 // src/components/post-card.svelte3 export let title;4 export let description;56 export let url;7 </script>89 <a href={url}>10 <article>11 <h1>{title}</h1>12 <p>{description}</p>13 </article>14 </a>1516 <style>17 article {18 padding: 2vw;19 border-radius: 15px;20 background-color: rgb(186, 186, 186);21 box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);22 margin-bottom: 2vw;23 }24 article:hover {25 box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);26 }2728 article:first-child {29 margin-top: 2vw;30 }3132 article:last-child {33 margin-bottom: 2vw;34 }3536 :global(a) {37 text-decoration: none;38 color: inherit;39 }40 </style>
In the code snippet above, the post-card
contains a title
and description
that we can find in the frontmatter of the Markdown file. It also needs a URL redirecting the user to the right path upon clicking.
Retrieve all posts
In this section, we will retrieve all posts on the browser. We can proceed to update first-post.md
and second-post.md
with their respective code snippets below.
src/posts/first-post.md
1---2 title: Creating first post on how to build video blog in Svelte3 description: Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard.4 ---56 The idea is to create first post on how to build video blog in Svelte.
src/posts/second-post.md
1---2 title: Creating second post on how to build video blog in Svelte3 description: Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard.4 ---56 The idea is to create second post on how to build video blog in Svelte.
Update index.svelte
with the following code snippet.
1<script context="module">2 ///src/routes/index.svelte3 export async function load({ fetch }) {4 const posts = await fetch("/api").then((r) => r.json());5 return {6 props: { posts },7 };8 }9 </script>1011 <script>12 import PostCard from "/src/components/post-card.svelte";13 export let posts;14 </script>1516 //...1718 <main>19 <h1>Build a video blog in Svelte</h1>20 <div class="post">21 {#each posts as post}22 <PostCard {...post} />23 {/each}24 </div>25 </main>2627 //...
Next, restart the server to reflect new changes, as shown below.
Create routes and load posts dynamically
We'll read the written post in this section. We must develop a dynamic route that loads a post to do so.
Update the api.js
file under the src/routes
directory with the following snippet.
1// src/routes/api.js2 import { importMarkdowns, convertToPostPreview } from "$lib/handle-markdown"34 export function GET() {5 let postFiles = importMarkdowns("src/posts/")67 let o_posts = postFiles.map((file) => convertToPostPreview(file))89 let body = JSON.stringify(o_posts);1011 return {body}12 }
Next, we will create a dynamic page with [url].svelte
and [url].json.js
in the src/routes/posts
directory. The url
variable is to request the needed file and display the content in the HTML of the page.
Let’s update [url].svelte
with the following code snippet.
1<script context="module">2 // src/routes/posts/[url].svelte3 export const load = async ({ fetch, params, url }) => {4 const post = await fetch(`/posts/${params.url}.json`).then((r) => r.json());5 console;6 return { props: { post } };7 };8 </script>910 <script>11 export let post;12 </script>1314 <svelte:head>15 <title>{post.attributes.title}</title>16 <meta name="description" content={post.attributes.description} />17 </svelte:head>1819 <article>20 <h1 class="section-header">{post.attributes.title}</h1>2122 {@html post.html}23 </article>2425 <style>26 :global(article) {27 padding: 4vw;28 }29 </style>
Now, update [url].json.js
with the following code snippet.
1import { convertMarkdown } from "$lib/handle-markdown"23 export async function GET({ params }) {4 const {url} = params;5 const post = await convertMarkdown(`src/posts/${url}.md`)6 let body = JSON.stringify(post);7 return { headers: { 'Content-Type': 'application/json' },body}8 }
We should be able to preview individual posts, as shown below.
Add a video from Cloudinary
Let's log in to our Cloudinary account on our browser to upload new videos and retrieve the video URL for the videos uploaded.
https://res.cloudinary.com/olanetsoft/video/upload/v1554336421/samples/sea-turtle.mp4 https://res.cloudinary.com/olanetsoft/video/upload/v1554336425/samples/elephants.mp4
We will update the first-post.md
and second-post.md
with the following code snippets.
Update first-post.md
1---2 //..3 video: https://res.cloudinary.com/olanetsoft/video/upload/v1554336421/samples/sea-turtle.mp44 ---56 The idea is to create first post on how to build video blog in Svelte.
Update second-post.md
1---2 //...3 video: https://res.cloudinary.com/olanetsoft/video/upload/v1554336425/samples/elephants.mp44 ---56 The idea is to create second post on how to build video blog in Svelte.
Next, we’ll update [url].svelte
to preview individual video on our blog post.
1<article>2 <h1 class="section-header">{post.attributes.title}</h1>34 {@html post.html}56 <!-- svelte-ignore a11y-media-has-caption -->7 <video8 src={post.attributes.video}9 height="400"10 width="600"11 controls12 autoplay13 />14 </article>1516 //..
Now, let’s restart the server and test our application.
Conclusion
This post demonstrates how to build a video blog in Svelte.