Site Build Notes

A large building construction site

An actual photo showing how the Pennock Projects website was built

Resources

I started with the excellent Udemy course by Piotr Jura Unlock Nuxt 3 & Vue Mastery: Build a Markdown Blog-Portfolio and Supabase Finance Tracker here and studied the GitHub source final and then like all developers before me, I built from there.

Nuxt

Nuxt is the framework for SSG. See Nuxt Cheat Sheet

Nuxt Content Doc

The Nuxt Content Doc is a Nuxt module that allows you to generate HTML content from markdown files. Used in combination with Tailwind Typography module to automatically 'up level the default style' Markdown documents to beautiful and readable HTML.

Installation

Install Content Doc

npx nuxi@latest module add content

Content Folder

The Content Doc module will automatically scan the /content folder in the source tree for markdown files and generate HTML for each. In each page .vue file you add a <ContentDoc /> element within <template></template> section. The NuxtContent generated HTML from the markdown file is injected in the <ContentDoc /> element.

The /content directory structure should match the /pages folder, so the Markdown file at /content/about.md contents will be converted and injected into the <ContentDoc /> in the <template></template> for the page at /pages/about.vue.

Mapping Content to Different Pages

To override the default behavior, you can specify that a different Markdown file is included by adding a path="{contentfolderpath}" property to the <ContentDoc />. For example, to inject the /content/blog/2023/hello.md into the /pages/about.vue page, you would add the following.

<ContentDoc path="/blog/2023/hello" />

NuxtContent Remark Plugin

Nuxt Content uses the MDC Remark plugins process Markdown text and to allow Markdown to support Vue components. One downside to this approach is that it will convert an image into a <p><img></p> structure. For example, an image specified in Markdown like this:

![Logo](/images/PPNDLogoSm.png)

It will get converted by the MDC Remark plugin into HTML like this:

<p>
  <img title="Logo" src="/images/PPNDLogoSm.png">
</p>

remark-unwrap-images

The outer <p></p> tags can cause formatting issues.

NuxtContent MDC uses remark plugins list to do the conversion to code blocks. A remark-unwrap-images plugin will unwrap images from the paragraph elements.

The Nuxt Configuration for remark plugins documents on how to enable them.

Unwrap Installation

npm install remark-unwrap-images

And then add this to your nuxt.config.js

content: {
  markdown: {
    remarkPlugins: ['remark-unwrap-images']
  },
},

Tailwind CSS

The Tailwind CSS module enables the use of Tailwind CSS classes and particularly the Typographic Prose class for NuxtContent Markdown files. Tailwind CSS has a CSS 'reset', which resets the basic default classes for common HTML elements like <p></p> and <h1></h1>. The Tailwind Typographic Prose class is an Uber class which will style its element and all of its children elements with carefully chosen defaults for consistency and readability.

Installation

I installed the Tailwind CSS Typographic Prose module like this:

npm install --save-dev @nuxtjs/tailwindcss

added 104 packages, and audited 931 packages in 7s

184 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
PS C:\dev\>

Further you need to add the Tailwind CSS module to the nuxt.config.ts file

export default defineNuxtConfig({
  devtools: { enabled: true },
  modules: [
    '@nuxtjs/tailwindcss'
  ]
})

Restarting the server will enable the new module. You can check in the Vue dev tools under the modules section.

Typographic Prose Class

A common way to add the Tailwind Typographic prose class is to add the class="prose" attribute to the parent element containing the NuxtContent <ContentDoc /> element, for example the surrounding <div></div> or <article></article> element. Tailwind CSS, by default, will strip all the normal default HTML styling, i.e. the <h1></h1> element is not shown as large by default. When you use the Prose class it reasserts a clean and typography styling. The <h1></h1> elements are all set to this. You add the tailwind class prose for light mode and dark: prose-invert for dark mode.

<template>
  <article class="prose dark:prose-invert">
    <ContentDoc />
  </article>
</template>

Using Tailwind CSS

In a .vue file you can use tailwind CSS classes directly in the <template></template> section, or you can apply them to CSS rules in the <style></style> section. To add tailwind classes in the style section use the @apply line, for example, the class link has the tailwind CSS class p-1 and hover:bg-gray-200 applied to it.

<style scoped>
.link {
  @apply p-1 hover:bg-gray-200
}
</style>

Note you can also use regular styles, the :deep() combinator, v-bind(), etc. alongside the @apply.

For example:

<style>
.monk-inset :deep(p) {
  font-size: v-bind('pFontSizeClass');
  line-height: v-bind('pLineHeightClass');
  height: v-bind('pLineHeightClass');
  margin: -0.2ch 0 0 0;
  @apply p-0
}
</style>

Social Share Buttons

Since each page has custom metadata, I also wanted convenience buttons to quickly share the page on social media. Stefano Bartoletti Nuxt Social Share module was a good and easy as following the instructions to add the module. Then add the component into the page template.

The terminal command I issued.

npx nuxi@latest module add nuxt-social-share

nuxt.config.ts entries required

  modules: [
    '@stefanobartoletti/nuxt-social-share'
  ],

  socialShare: {
    baseUrl: 'https://pennockprojects.com'
  }

Here is the usage within the code.

<template>
/<!-- snip -->
  <SocialShare
    v-for="network in ['facebook', 'x', 'linkedin', 'email']"
    :key="network"
    :label="false"
    :network="network"
    :styled="true"
  />
<!-- snip -->
</template>

Nuxt PDF

Better support for showing PDF files is with the paid component vue-pdf-viewer

Install

npm install @vue-pdf-viewer/viewer

Purchase a Developer License Key

  • A single user
  • Perpetual license
  • Use in multiple websites
  • Access to all features
  • Free 1-year update and support

Use License key to activate

Essential code below.

<script setup>
  import { VPdfViewer, useLicense } from '@vue-pdf-viewer/viewer';
  let licenseKey = "123"
  useLicense({ licenseKey }); 
</script>

<template>
  <VPdfViewer />
</template>

CloudFlare Analytics

Install

npm i nuxt-cloudflare-analytics

Update nuxt.config.js

{
  modules: [
    'nuxt-cloudflare-analytics'
  ],
  cloudflareAnalytics: {
    // See below for more options
    token: 'your-token', // Example 1a2b3v4a5er6ac7r8afd
  }
}

Deployment

Deployment Steps

  1. Generate Static Site npm run generate - places built files in .output/public directory
  • Debugging steps for
  1. Generate Static Site