<!--
  canonical-url: https://www.avonture.be/blog/site-creation
  published:     2023-11-03
  This is a static plain-Markdown mirror generated at build time.
  Visit the canonical URL above for the fully rendered page, with images and interactive components.
-->

# Site creation

> Follow the steps taken to create this Docusaurus blog. Learn about using essential plugins like search, sitemap, image zoom, and adding the Giscus comment system.

---
> [Docusaurus.io](https://docusaurus.io/)

![Creation of this blog](/img/v2/site_creation.webp)

**TL;DR**

This article documents how this blog was built: bootstrapping Docusaurus in blog-only mode entirely through the official Docker `node` image (no local Node.js install), configuring `docusaurus.config.js`, and adding plugins for local search, sitemap, image zoom, and Giscus comments. It ends with building the static site via `yarn build` and deploying it over FTP with WinSCP, plus injecting a GDPR-compliant analytics script from withcabin.com.

Here are the steps I followed to create this blog.

## Using Docusaurus

Since I really like the simplicity of Docker, I will not install Node.js on my machine but use the official Docker image. *This article shows the raw `docker run` approach; if you prefer a ready-made `Dockerfile` and a `compose.yaml`, jump to [Running Docusaurus with Docker](/blog/docusaurus-docker).*

```bash
docker run --rm --name blog --user $UID:$GID -it -v ${PWD}/:/project -w /project node /bin/bash
```

The instruction above will download Node.js (the latest version) on my machine if it is not already present and create a running instance (called a *container* of it). The flag `--user $UID:$GID` is used to start the container using the same credentials as my local one (i.e., reuse my local Unix `christophe` user so files/folders created in the container will be owned by my local user).

The `-v ${PWD}/:/project` command line argument will [share my current folder](/blog/docker-volume) on my computer with the container that is, the `/project` folder in the container will be my current folder on my computer.

And finally, I run an interactive shell since I have mentioned `/bin/bash` as the entry point.

Now that I have a prompt in the container, I will create my blog using Docusaurus (as explained in the [official documentation](https://docusaurus.io/docs/installation)).

```bash
$ npx create-docusaurus@latest blog classic --javascript
```

After a long time, the blog folder is created and I can take a look at its content:

```tree
.
├── blog
├── docs
├── node_modules
├── src
└── static
```

The installation step is now finished; I will exit the container and return to my computer, and to do this, from the Docker console, I just type `exit`.

## Run the website

Back to my computer, I will now go inside my `blog` folder (`cd blog`) and run the Docker command again but this time with the `-p 
3000
:3000` extra parameter. This parameter will expose the port 3000 from the container to my machine so I can see the website by surfing to `http://localhost:`3000.

Instead of running an interactive shell session I prefer to run `/bin/bash -c "npx docusaurus start"` to run the Docusaurus watcher and serve my files:

```bash
```

After a few seconds, the container is ready to use and I surf to my site by going to `http://localhost
:
3000`.

> Screenshot — http\://localhost:3000
>
> ![Homepage](./images/homepage.webp)

> **The --host 0.0.0.0 flag:**
>
> It is really crucial to use the `--host 0.0.0.0` flag when calling `npx docusaurus start`. This will allow external access to the website. If missing, browsing to `http://localhost
> :
> 3000` (or running `curl 
> http://127.0.0.1
> :
> 3000`) will display an error `Empty reply from server`.

## Some settings

By default (using the standard installation), Docusaurus will create a skeleton of a website having two main entries: a blog and a tutorial.

To keep things manageable, I will only keep the blog and remove the tutorial part. For this, I have followed this official article: <https://docusaurus.io/docs/blog#blog-only-mode>.

Now, I can remove the `/docs` folder from my `blog` directory:

```tree
.
├── blog
├── node_modules
├── src
└── static
```

I will also make some changes to files like `docusaurus.config.js` or `blog/authors.yml` to fit my needs.

### File docusaurus.config.js

By setting `hideOnScroll` to `true`, the navigation bar will be hidden when the user scrolls down but will be displayed back as soon as they scroll up. Idea is to give more space on the screen for the content.

**docusaurus.config.js**

```javascript
export default {
  themeConfig: {
    navbar: {
        // auto-hide the navbar when the user will scroll down, show again when scroll up
        hideOnScroll: true,
    },
  },
};
```

Define the default image for social media:

**docusaurus.config.js**

```javascript
export default {
  themeConfig: {
    // Default image when sharing a post on social media
    image: 'img/social-card.jpg',
  },
};
```

## Make my first article

With my preferred editor ([vscode](https://code.visualstudio.com/)) I open my blog's website (I just type `code .` in my Linux console to open my `blog` project).

Now, in the `/blog` directory, I create a new folder called `2023-11-02-site-creation` and there I create the `index.md` file.

> **Note:**
>
> When my blog post contains only text and no images or linked files, I can just create a `.md` file like `/blog/2023-11-02-this-is-a-test.md`. The creation of a folder is therefore not mandatory at all.

In the previous chapter, npx was executed using the `` `docker run --rm -it --name `
blog ` --user \$UID:\$GID -v \${PWD}/:/project -w /project -p `
3000 `:3000 node /bin/bash -c "npx docusaurus start --host 0.0.0.0"` `` command so, any changes made to the blog will be immediately synchronized with Docker meaning, I just need to save my article and npx will reload my site; very easy and convenient.

### Using some layouts

Docusaurus supports some Markdown special tags called *admonition* (see <https://docusaurus.io/docs/markdown-features/admonitions>).

For instance, to display a paragraph as a tip, like below, just use the following syntax:

```none
:::tip
Some **content** with _Markdown_ `syntax`.
:::
```

> **Information:**
>
> Some **content** with *Markdown* `syntax`.

To get the entire list of supported features, see [Markdown Features](https://docusaurus.io/docs/markdown-features).

### Adding plugins

#### Search engine

> <https://github.com/cmfcmf/docusaurus-search-local>

The search engine feature has been added by following this blog article: <https://yoandev.co/une-documentation-avec-docusaurus-et-gitlab-pages/#bonus--ajoutons-un-moteur-de-recherche>

Added by running `yarn add @cmfcmf/docusaurus-search-local` in the Docker container (opened using `make bash`).

#### Support for PHP and bash in prism

> <https://www.npmjs.com/package/@docusaurus/theme-classic>

Added by running `yarn swizzle @docusaurus/theme-classic prism-include-languages` in the Docker container (opened using `make bash`). Read more at [Supported Languages](https://docusaurus.io/docs/markdown-features/code-blocks#supported-languages).

#### Sitemap generator

> <https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-sitemap>

Added by running `yarn add @docusaurus/plugin-sitemap` in the Docker container (opened using `make bash`).

When added, I have also manually created the `static/robots.txt` file with this content:

**static/robots.txt**

```txt
User-Agent: *
Sitemap: https://www.avonture.be/sitemap.xml
Disallow: /*index.xml$
Disallow: /index.json
Disallow: /search/index.json
```

#### Image plugins

> <https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-ideal-image>

Added by running `yarn add @docusaurus/plugin-ideal-image` in the Docker container (opened using `make bash`). Read more at [Supported Languages](https://docusaurus.io/docs/markdown-features/code-blocks#supported-languages).

> <https://www.npmjs.com/package/docusaurus-plugin-image-zoom>

Added by running `yarn add docusaurus-plugin-image-zoom` in the Docker container (opened using `make bash`).

#### Adding a comment area

> [How to add Giscus comments to Docusaurus](https://dev.to/m19v/how-to-add-giscus-comments-to-docusaurus-439h)

Adding Giscus to allow comments and feedback.

## Push to Github

On Github.com, I have created a new repository called `blog` (<https://github.com/cavo789/blog>). Once this is done, back to my console and I run a few git commands:

```bash
$ git init
...
$ git add .
...
$ git commit -m "Initial commit"
...
$ git remote add origin git@github.com:cavo789/blog
...
$ git push -u origin master
...
```

Once this was done, I have thus pushed my files to Github as foreseen by Docusaurus that is, for instance, the `/node_modules` is not part of my repo; which is fine since we will create that folder later by running some npx command on the web server where the site will be hosted.

## Build static version of the blog

In order to build static pages, I run `docker run --rm -it --user $UID:$GID -v ${PWD}/:/project -w /project node /bin/bash -c "yarn build"`.

This will create/update the `/build` folder with a fresh version of the site.

The next step is to start my FTP client (which is [WinSCP](https://winscp.net/eng/download.php)) and copy my local `/blog/build` folder to my remote website. To only send the files that really changed, see [WinSCP - Synchronize host and remote](/blog/winscp-synchronize-both).

*Nowadays, I no longer do this by hand: the site is deployed automatically, as explained in [GitHub - Use Actions to deploy this blog](/blog/github-action).*

## Adding withcabin for GDPR compliant stats

By adding the lines below to the `docusaurus.config.js` as child node of `const config`, I'm injecting a script into the body part. This will then allow GDPR compliant stats on <https://withcabin.com/>.

**docusaurus.config.js**

```javascript
scripts: [
  {
    src: 'https://scripts.withcabin.com/hello.js',
    async: true,
    defer: true,
  },
],
```

Note: the script is only injected to pages after a `yarn build` that is when the static site is rendered; not during a `yarn watch`.
