Nuxt is a framework for developing server-side redered (SSR) VueJS applications. It prioritizes providing an optimal developer experience by furnishing features such as automatic code splitting, file-based routing, server-side rendering, static site generation, and search engine optimization.

When working with Nuxt, the main difference from Vue development without a framework is that most of the required imports, such as routing components, do not need to be defined by the developer. Nevertheless, creating a Nuxt codebase for the first time may pose challenges to even experienced VueJS developers, as there is no “main.ts” or “main.js” file to import all the necessary libraries for the Vue object.

While the official documentation is online, the recent release of Nuxt v3 means that certain libraries and plugins may still be under development. As a newcomer to Nuxt during this era, I have discovered some useful insights that may be beneficial to other developers embarking on their first Nuxt v3 project.


File Structure

Nuxt, being a framework built on top of VueJS, adheres to Vue’s file structure convention. Developers do not need to worry about updating Vue Router manually.

With vanila VueJS projects, the best practice is to place routing components into /view or /pages directories under the root of the code base. However, developer can really store these components anywhere as long as they define them correctly in the router file and or co-developers can tolerate the inormal file structure.

In Nuxt project, all routing components are stored inside ~/pages directory. Nuxt uses a file-based routing system, which means what we placed inside the ~/pages directory will reflect on the web URIs. ~/pages/about-us.vue will be the address for https://domain.com/about-us. A nested component file such as ~/pages/admin/dashboard.vue will be https://domain.com/admin/dashboard.

In addition, Nuxt provides a customizable layouts framework which is not available in vanilla VueJS. The layouts framework helps to define a consistent structure for the designed application. In Nuxt, developers can define commonly used components as reusable components, and then they have to manually define the layout in the app.vue file.

A default layout (~/layouts/default.vue) can be created with the following code:

1
2
3
4
5
6
7
<template>
<div>
<AppHeader />
<NuxtPage class="container" />
<AppFooter />
</div>
</template>

This layout adds a header and a footer to every webpages.

Notibly, developers did not need to import header or footer components. Nuxt does it automatically.


Font Awesome

Apart from the built-in font libraries that come with various CSS frameworks, Font Awesome is considered the most commonly used.

In the vanila VueJs environment, font Awesome, like many other JS/TS or CSS libraries, are defined in main.ts/main.js as shown below:

1
2
3
4
5
6
7
/* Add font awesome library */
import { library, dom } from "@fortawesome/fontawesome-svg-core";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { faChevronDown, faCopyright, faBars } from "@fortawesome/free-solid-svg-icons";
import { faBtc, faTwitterSquare, faGithubSquare, faYoutubeSquare } from "@fortawesome/free-brands-svg-icons";
library.add(faBtc, faChevronDown, faCopyright, faBars, faTwitterSquare, faGithubSquare, faYoutubeSquare);
dom.watch();

In Nuxt v3 where Font Awesome hasn’t been adapt into an official module yet, developers can create a custom plugins inside ~/plugins directory. Just simply create a JavaScript or TypeScript file and call it fontawesome.[js | ts].

1
2
3
4
5
6
7
8
9
10
11
12
13
import { library, config } from "@fortawesome/fontawesome-svg-core"
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"
import { faTwitterSquare, faGithubSquare, faYoutubeSquare } from "@fortawesome/free-brands-svg-icons"
import { faChevronDown, faCopyright, faBars } from "@fortawesome/free-solid-svg-icons"

library.add(faBtc, faChevronDown, faCopyright, faBars, faTwitterSquare, faGithubSquare, faYoutubeSquare)

// This is important, we are going to let Nuxt worry about the CSS
config.autoAddCss = false

export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.component("font-awesome-icon", FontAwesomeIcon, {})
})

Code sample above is a JavaScript version of the Fontawesome plugin. Even though Nuxt v3 requires TypeScript, a JS file can still be used.

if we look closely, we can notice that importing Font Awesome in Vue and Nuxt is basically the same. Nuxt is built on top of Vue, so what works in Vue will work in Nuxt as well.

Most of Nuxt’s settings can be found in the ~/nuxt.config.ts file. To register Font Awesome’s CSS file, navigate to the CSS section or add the following:

1
2
3
4
css: [
"@fortawesome/fontawesome-svg-core/styles.css",
/*** other CSS libraries ***/
],

Using Font Awesome in Vue Components is the same as in VueJS project: <font-awesome-icon :icon="['fab', 'twitter-square']" />.


Internationalization

As a bilingual person, adding multi-language functionality is always an essnetial aspect of software development, particularly in web applications. Over the years, Multiple languages has become quite standardized by using i18n, regardless of the environment used.

To install i18n in Nuxt v3, run installation with yarn or npm, or add the following in package.json:

1
"@nuxtjs/i18n": "^8.0.0-beta.10"

Similar to Font Awesome, i18n configuration is added in nuxt.config.ts. Instead of storing all language data inside the nuxt.config.ts file, it’s cleaner and more organized to use multiple JSON or YAML files to store each language separately. These language files can be placed anywhere within the code repository. For the purpose of clarity, let’s assume that a directory called ~/locales has been created under the root of the code repo.

At the top of the nuxt.config.ts file, add:

1
2
3
import en from "./locales/en.json";
import fr from "./locales/fr.json";
import zh from "./locales/zh.json";

Find or create the modules section in the nuxt.config.ts file:

1
2
3
modules: [
"@nuxtjs/i18n"
],

Since i18n has a community module in the Nuxt v3 ecosystem, there is no need to create a new plugin.

To configure i18n, add a new section inside the nuxt.config.ts file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
i18n: {
locales: [
{ code: "en", name: "English" },
{ code: "en", name: "langue français" }
{ code: "zh", name: "中文" },
],
defaultLocale: "en",
vueI18n: {
fallbackLocale: "en",
messages: {
en,
fr,
zh,
},
},
}

The objects en, fr, and zh are imported from the JSON files. The locales array allows developers to retrieve the list of all supported languages in the project from any component.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
<div class="navbar-dropdown is-right">
<a v-for="l in locales" :key="l.code" class="navbar-item">
{{ l.name }}
</a>
</div>
<template>

<script lang="ts">
export default {
computed: {
locales(): LocaleObject[] {
return this.$i18n.locales
}
}
}
</script>

Lastly, the default language of this project is English since defaultLocale is set to “en”.