Svelte Vietnam (Go to home page)
Svelte Vietnam (Go to home page)

Writing Guide

Guidelines and recommendations for authoring blog posts on the Svelte Vietnam Blog

a human holding hand with an anthropomorphized planet earth

Table of contents


Technical Design Overview

The Svelte Vietnam Blog is a static site: its data is part of the source code, and blog post contents are written in Markdown and Svelte syntax. The process of writing and publishing a blog post shares much similarities with a typical daily software development workflow and does not depend on any third party database or fancy editor (WYSIWYG, Markdown editor, rich text, etc.). In a way, the Svelte Vietnam Blog uses Git as its CMS.

This design requires writers to have some basic experience with web development, but it also helps reduce significantly the infrastructure cost and human resources needed to maintain the blog.

For non-technical writers

If you are looking for ways to contribute to the Svelte Vietnam Blog but are not familiar with the technical aspects listed here, please feel free to reach out to administrators via the official Svelte Vietnam Discord server, or send your blog post in any traditional text format (txt, pdf, docx, etc.) to blog@sveltevietnam.dev.

Directory Structure of a Blog Post

Each blog post is a collection of files located under a sites/sveltevietnam.dev/src/data/blog/posts/:id directory:

  sites/sveltevietnam.dev/src/data/blog/posts/:id
    │
    ├── metadata.ts       <-- main data definition
    │
    ├── content/
    ┆   │
    ┆   ├── en.md.svelte  <-- content in English
    ┆   └── vi.md.svelte  <-- content in Vietnamese
    │
    ├── images/
    ┆   │
    ┆   └── thumbnail.jpg <-- thumbnail and social sharing image
    ┆   └── ...           <-- any other images used in the post
    ┆
    ├── ...               <-- other data used in the post

Overview of the writing process

Step 1: Install Necessary Software

  1. node.js:
    • The required node.js version for the project is defined in package.json under the "engines" key.
    • It is recommended you use volta to manage node.js versioning. If installed, volta will automatically set the appropriate version for the project based on the definition in package.json.
  2. lefthook: a git hook manager that automatically runs code convention & sanity checks before committing code.
  3. pnpm: a package manager that serves as an alternative to npm.

You of course also need git and a code editor of your choice. Setting up code editor is unfortunately out of the scope of this document, but there should be plenty resources on the web for that.

Step 2: Set up Local Development Environment

  1. Clone the source code:

    git clone https://github.com/sveltevietnam/sveltevietnam.dev.git
    git clone git@github.com:sveltevietnam/sveltevietnam.dev.git
    gh repo clone sveltevietnam/sveltevietnam.dev
  2. Run the following setup command at the root directory of the project:

    pnpm boot
  3. Start the development server at the sites/sveltevietnam.dev directory:

    cd sites/sveltevietnam.dev
    pnpm dev

If everything is set up correctly, you can now access a local copy of the Svelte Vietnam Blog at http://localhost:5005/en/blog.

Step 3: Initialize Post Data

In your terminal, get to the sites/sveltevietnm.dev directory. If this is your first time contributing content for sveltevietnam.dev, initialize your author data with the following command:

pnpm create:person

Next, initialize blog post data with the following command:

pnpm create:post

Step 4: Complete your Post Content

If you are using VSCode, open the project at the root directory instead of sites/sveltevietnam.dev, so that the editor settings under .vscode can be read.

Following step 3, you will need to finish you writing at two newly created files:

  • .../content/en.md.svelte: your writing in English,
  • .../content/vi.md.svelte: your writing in Vietnamese.

You may refer to "Post Content Syntax: Markdown + Svelte" for examples and guidelines on special syntax and features available in post content, as well as "Updating Post Metadata" on how to edit post metadata.

If you can only contribute in one of the two languages, just leave the other empty. Administrators and community members may be able to help you with translation.

Step 5: Create a Pull Request

Once you are satisfied with your writing, you will need to perform typical source control operations with git and Github, including committing your changes onto a new branch and creating a pull request targeting the default branch (the branch displayed when you visit the sveltevietnam/sveltevietnam.dev repository).

You may also use Github CLI to simplify certain workflows. For example, after installation and login (gh auth), you can create a pull request quite conveniently with the following command:

gh pr create

Refer to DEVELOPMENT.md - Commit Message Guidelines for guidelines on writing commit messages. Workflow with git and Github are not particularly difficult, but require several steps and can be achieved in different ways, so we will not go into details here. If you need assistance or have questions, please contact our administrators via the Discord - Discussion - Blog channel.

Step 6: Review and Publish

After your pull request is sent, administrators will review your writing and involve any necessary discussion / further enquiry right in the pull request thread on Github.

Once review is completed, administrators will merge your pull request, shortly after which your post will go live on the Svelte Vietnam Blog 🎉.

Post Content Syntax: Markdown + Svelte

Post content is parsed by a custom Svelte preprocessor. Feel free to check out the source code of this preprocessor to learn more about its inner workings. In short:

  • most of the content is written in Github Flavored Markdown syntax,
  • you can also use Svelte syntax, such as the script tag, enhanced:img, or other imported Svelte components,
  • syntax highlighting for code blocks is handled by Shiki.

Several special syntax have been developed to make writing blog posts more convenient. These special syntax are introduced in the next sections.

The most natural way to get familiar with these special syntax is to refer to the source code of published blog posts at the Svelte Vietnam Blog.

Some Markdown or Svelte syntax may not work as expected, in which case please contact administrators for possible workarounds.

Code Block

For technical blog posts, sharing code snippets is expected. To display a code block, you can use the following syntax:

```ts title="basic.ts"
console.log('Hello, world!');
```

The above content will be displayed as:

console.log('Hello, world!');

Indicating Code Changes (diff)

To indicate code changes, you can wrap the code block with comments using the :::diff + or :::diff - directive. For example, the following content...

```svelte title="diff.svelte"
<script>
  // :::diff -
  import ComponentOld from './old.svelte';
  // :::
  // :::diff +
  import ComponentNew from './new.svelte';
  // :::
</script>

<!-- :::diff - -->
<ComponentOld>...</ComponentOld>
<!-- ::: -->
<!-- :::diff + -->
<ComponentNew>...</ComponentNew>
<!-- ::: -->
```

...will be displayed as:

<script>
  import ComponentOld from './old.svelte';
  import ComponentNew from './new.svelte';
</script>

<ComponentOld>...</ComponentOld>
<ComponentNew>...</ComponentNew>

Highlighting and Focusing Code

To set emphasis on one or more lines in the code block, you can wrap the code block with comments using the :::highlight or :::focus directive. For example, the following content...

```css title="highlight-focus.css"
.example {
  /* :::highlight error */
  @extend mx-auto; /* not supported */
  /* ::: */

  /* :::highlight warning */
  @apply mx-auto; /* not recommend */
  /* ::: */

  /* :::highlight */
  margin: 0 auto; /* good */
  /* ::: */

  /* :::highlight success */
  /* better */
  margin-left: auto;
  margin-right: auto;
  /* ::: */

  /* :::focus */
  margin-inline: auto; /* best */
  /* ::: */
}
```

...will be displayed as:

.example {
  @extend mx-auto; /* not supported */

  @apply mx-auto; /* not recommend */

  margin: 0 auto; /* good */

  /* better */
  margin-left: auto;
  margin-right: auto;

  margin-inline: auto; /* best */
}

Grouping Multiple Code Blocks

To display multiple code blocks that share the same context, you can use the enhanced-code-block element with the group attribute. For example, the following content...

<enhanced-code-block group display="tabs">

```bash title="npm"
npm install --save-dev @sveltevietnam/markdown
```

```bash title="yarn"
yarn add -D @sveltevietnam/markdown
```

```bash title="pnpm"
pnpm add -D @sveltevietnam/markdown
```

</enhanced-code-block>

...will be displayed as a tab group:

npm install --save-dev @sveltevietnam/markdown
yarn add -D @sveltevietnam/markdown
pnpm add -D @sveltevietnam/markdown

Additionally, to group code blocks as a collection of files, you can set display="files". For example, the following content...

<enhanced-code-block group display="files">

```html title="example.html"
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Example</title>
  <link rel="stylesheet" href="./example.css">
  <script module src="./example.js"></script>
</head>
```

```css title="example.css"
.example {
  color: red;
}
```

```js title="example.js"
console.log('Hello, world!');
```

</enhanced-code-block>

...will be displayed as a file group:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Example</title>
  <link rel="stylesheet" href="./example.css">
  <script module src="./example.js"></script>
</head>
.example {
  color: red;
}
console.log('Hello, world!');

Note: The empty lines surrounding the enhanced-code-block opening and closing tags and its content are necessary.

Images

The the time of this writing, the project does not support Markdown syntax for images in blog posts. Instead, please use HTML tags as shown in the following example...

<script>
  import illustration1 from '../images/blog.png?format=avif';
</script>

<figure>
  <img src={illustration1} class="mx-auto max-w-full" width="573" height="376" alt="illustration: a handwriting in a rectangle box that reads 'Blog'" />
  <figcaption>Illustration 1: Example for displaying an image in post content</figcaption>
</figure>

...which will be displayed as:

illustration: a handwriting in a rectangle box that reads 'Blog'
Illustration 1: Example for displaying an image in post content

Recommendations:

  • images should be placed in the .../images directory, similar to thumbnail.jpg, as shown in the "Directory Structure of a Blog Post" section,
  • use the import query format=avif to optimize for image size. For more information, refer to imagetools - directives,
  • set appropriate width, height, and alt attributes for the image.

Callout

Callout enhances a text content with some contextual meaning and helps draw user's attention. The following example shows one possible variant of callout:

Content to be highlighted...

To display the above callout, you can use the following syntax:

<div class="c-callout c-callout--success c-callout--icon-trophy">

Content to be highlighted...

</div>

Use the playground below to find the right classes for your desired callout.

Config
Status:
Icon (optional):
Result

=> Class names to apply: c-callout c-callout--info .

This is a sample “callout” that enhances a text block with some contextual meaning and helps draw user's attention. See more examples and how to use it via "Svelte Vietnam Blog - Writing Guidelines".

Data Definition & Edit

Following "Overview of the writing process", post and author data can be initialized with the help of the pnpm create:post and pnpm create:person commands. However, you may review and edit this data at any time.

Updating Post Metadata

As mentioned in "Directory Structure of a Blog Post", data definition for a blog post is located at sites/sveltevietnam.dev/src/data/blog/posts/:id/metadata.ts. For example, the metadata for the post "Come for Svelte, Stay for the Web" is defined as follows:

import { defineBlogPostMetadata } from '..';

export default defineBlogPostMetadata((lang) => ({
	publishedAt: new Date('2024-04-20'),
	authors: ['vnphanquang'],
	categories: ['svelte-and-kit', 'ecosystem'],
	...(
		{
			en: {
				slug: '20240420-come-for-svelte-stay-for-the-web',
				title: 'Come for Svelte, Stay for the Web',
				description:
					'Svelte is exceptionally good at staying out of your way, allowing you to focus on building a better web. No one cares about frameworks anyway!',
				keywords: 'web, ecosystem, runtime, compile-time, action',
				readMinutes: 8,
				numWords: 1590,
				translation: 'manual',
			},
			vi: {
				slug: '20240420-den-voi-web-thong-qua-svelte',
				title: 'Đến với web thông qua Svelte',
				description:
					'API của Svelte được thiết kế để thân thiện với các công nghệ và kiến thức nền tảng, giúp bạn dễ dàng tập trung vào việc xây dựng ứng dụng web, thay vì quan tâm đến framework này và nọ.',
				keywords: 'web, hệ sinh thái, runtime, compile-time, action',
				readMinutes: 8,
				numWords: 1990,
				translation: 'original',
			},
		} as const
	)[lang],
}));

Once you have completed the writing process (step 1 -> 4), make sure you revisit the corresponding .../metadata.ts and update the necessary fields, such as readMinutes and numWords.

Post Thumbnail

To set a custom thumbnail for a blog post, simply add the image as thumbnail.jpg to the .../images directory, as listed in "Directory Structure of a Blog Post". Some guidelines and recommendations are as follows:

  • the image should be in JPEG format and named thumbnail.jpg,
  • it should have a minimum width of 2240px,
  • it should have an aspect ratio of 16:9,
  • it should be minimalistic, and without too much text.

Updating Author Data

Author data is defined at sites/sveltevietnam.dev/src/data/people/:id/index.ts. For example, data for "Quang Phan" is defined as follows:

import { definePerson } from '..';

export default definePerson((lang) => ({
	links: {
		website: 'https://vnphanquang.com',
		bluesky: 'https://bsky.app/profile/vnphanquang.com',
		github: 'https://github.com/vnphanquang',
	},
	...{
		en: {
			name: 'Quang Phan',
			description: 'Developer, administrator',
		},
		vi: {
			name: 'Phan Quang',
			description: 'Lập trình viên, quản trị viên',
		},
	}[lang],
}));

Edit this page on Github sveltevietnam.dev is an open source project and welcomes your contributions. Thank you!