Create a blog in Nuxt 3
It has been 3 years since I built this blog in Nuxt 2 but the support of Nuxt 2 will end soon, so I created it again in Nuxt 3.
Initialize the project
Refer to the following page to initialize the project using Nuxt Content v2.
Reference: Installation - Nuxt Content
Environment variables
Nuxt 3 has dotenv built in.
Reference: .env · Nuxt Directory Structure
If you prepare several files, such as .env.local, .env.production, etc., you can set the environment variables for each environment. If you are connecting from the same local network, set the following variables:
.env.local
HOST=0
PORT=3000
Preprocessors
Pug.js
terminal
$ yarn add pug
You can use Pug.js by setting pug
to lang
attribute of <template>
.
Sass
Reference: # Using Preprocessors
Modules
Nuxt 3 offers additional functionality as a module. I think it covers most of the functions you need.
Nuxt UI
Bulma and Buefy are not provided for Nuxt 3, so I use Nuxt UI (@nuxt/ui
) as an alternately.
Nuxt UI is based on Tailwind CSS. @nuxtjs/color-mode
and nuxt-icon
are imported automatically, but it is necessary to edit the config file to use them.
nuxt.config.ts
export default defineNuxtConfig({
modules: ['@nuxt/ui', '@nuxtjs/color-mode', 'nuxt-icon'],
})
If you would like to change the default color, choose from the provided color map or create a new one. The following site is very helpful in creating a color map.
Reference: uicolors.app/create
Running the following command will create the config file in the root directory.
terminal
$ npx tailwindcss init --ts
Reference: Using ESM or TypeScript
The color map referenced by components is set in app.config.ts.
Reference: Theming - Nuxt UI
Nuxt UI Pro provides many components, but you must pay to use them in production.
Dark mode
It is enabled by the settings above.
In @nuxtjs/color-mode
, each class name is light-mode
and dark-mode
. In @nuxt/ui
, they are light
and dark
.
Icon
You can easily reference different icon packages using <Icon>
tag.
Reference: GitHub - nuxt-modules/icon: The <Icon> component, supporting Iconify, Emojis and custom components.
You would like to use SVG icons, you can also use nuxt-icons
package. Its name is similar, but it is a different package.
Reference: Icons · Nuxt Modules
Syntax Highlighting
Nuxt 3 uses Shikiji for syntax highlighting by default.
Reference: highlight
This highlight module addresses light/dark modes, but this setting is overridden by default
settings.
In Nuxt Content v1, the highlight module displays a file name, but it is not available in Shikiji. If you would like to display the file name, you need to overwrite the component.
Generate Open Graph image
Og-image module automatically generates the image for Open Graph.
Reference: Og-image · Nuxt Modules
It is necessary to specify the font style if you use non-English language.
Reference: Non-English Locales · Nuxt SEO
You can use HTML tags to make the image, but the image design will be different from the appearance of the HTML page because some tags are not supported. I think linebreaks won't work.
Sitemap
Reference: Sitemap · Nuxt Modules
Google Analytics
Reference: Gtag · Nuxt Modules
Internationalization
Reference: GitHub - nuxt-modules/i18n: I18n module for Nuxt
Edit the project
Directory Structure
Reference: Nuxt Guide
layouts
It is necessary to edit app.vue.
Reference: layouts/ · Nuxt Directory Structure
The difference between composables and utils
Composable is available in Nuxt 3 using Vue's Composition API. The Composition API encapsulates the state control logic for reusability.
Reference: Composables | Vue.js
The scripts in the composables and utils directories are automatically imported. The encapsulated processes that are not composables are stored in utils.
Reference: utils/ · Nuxt Directory Structure
script setup
<script setup>
tag is available as of Vue 3. Its way of writing is different from the previous version.
<script>
はコンポーネントがインポートされた最初のタイミングで実行されますが,<script setup>
はコンポーネントのインスタンスが作成されるたびに実行されます.
The difference is below:
<script>
: run when the component is first imported<script setup>
: run when the instance of the component is created
Reference: <script setup> | Vue.js
A component looks like this:
<template>
<div>
<p v-if="hasName">{{ name }}</p>
</div>
</template>
<script setup>
const props = defineProps({
name: {
type: String,
default: '',
},
})
const { name } = props
const hasName = computed({
get() {
return name === 'alice'
},
})
</script>
Reference: Writable Computed
Get content from Markdown file
$content
tag in Nuxt Content v1 is unavailable and alternatively available for useAsyncData()
function.
<script setup>
const { data } = await useAsyncData('home', () => queryContent('/').findOne())
</script>
Note that the retrieved data is controlled by the first argument, so the other argument should be specified when retrieving data in parallel.
Reference: queryContent() - Nuxt Content
Execution environment
nuxt dev or preview
In Nuxt 3, nuxt preview
is available. This command works the same as start
.
Reference: nuxi preview · Nuxt Commands
Connect from the local network
This script makes it available to connect from the same local network.
package.json
{
"scripts": {
"local": "yarn dev --dotenv .env.local"
}
}
terminal
$ yarn local
SEO
favicon
According to Google's guidelines, it is necessary to prepare icons in the size multiple of 48px.
But some icons are required for iPhone/iPad(Pro/mini)/Mac by Apple's guide.
Reference: App icons | Apple Developer Documentation
Therefore, I suggest using SVG because there is no need to specify the size. Apple-touch-icon is also required for the device of iOS/iPad OS. Its size is 180x180.
Head
Reference: useSeoMeta
Conclusion
The Lighthouse score of the previous blog is below:
Mobile
Reported by Lighthouse
PC
Reported by Lighthouse
After rebuilding with Nuxt 3, this score decreased slightly due to the size of the JS library and the implementation of AdSense.
Mobile
Reported by Lighthouse
PC
Reported by Lighthouse