3. A First [nuxt.js] Application
3.1. Creating the application
For our [nuxt.js] development, we will continue to use VS Code. We have created an empty [dvp] folder where we will place our examples. Then we open this folder:

We save the workspace under the name [intro-nuxtjs] [3-5]:

We open a terminal [6-7]:

Up until now, we have used the JavaScript package manager [npm]. For a change, we will use the [yarn] manager here. Like [npm], it is installed with recent versions of [node.js]. To create a first [nuxt] application, we use the command [yarn create nuxt-app <folder>] [1]. The command will ask for some information about the project to be generated and, once this information is provided, will generate it [2]:

In [2], an entire file tree has been created. The [package.json] file lists the JavaScript libraries downloaded to the [node-modules] folder [4]:
{
"name": "nuxt-intro",
"version": "1.0.0",
"description": "nuxt-intro",
"author": "serge-tahe",
"private": true,
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start",
"generate": "nuxt generate",
"lint": "eslint --ext .js,.vue --ignore-path .gitignore ."
},
"dependencies": {
"nuxt": "^2.0.0",
"bootstrap-vue": "^2.0.0",
"bootstrap": "^4.1.3",
"@nuxtjs/axios": "^5.3.6"
},
"devDependencies": {
"@nuxtjs/eslint-config": "^1.0.1",
"@nuxtjs/eslint-module": "^1.0.0",
"babel-eslint": "^10.0.1",
"eslint": "^6.1.0",
"eslint-plugin-nuxt": ">=0.4.2",
"eslint-config-prettier": "^4.1.0",
"eslint-plugin-prettier": "^3.0.1",
"prettier": "^1.16.4"
}
}
This file reflects the responses provided to the [create nuxt-app] command to define the created project (November 2019). The reader may have a different [package.json] file:
- they may have provided different answers to the questions;
- the [create nuxt-app] command may have evolved since this document was written: dependencies and versions may have changed;
Line 8 of the script is the command that launches the application:

- in [4], we see that the application is available at the URL [localhost:3000];
- in [5-6], we see that the application spawns a server [6] and a client (of that server) [5];
Let’s request the URL [http://localhost:3000/] in a browser:

3.2. Description of the directory structure of a [nuxt] application
Let’s look at the directory structure of the created application:

The role of the folders is as follows:
assets | uncompiled application resources (images, etc.); |
static | files in this folder will be available at the root of the application. We place files in this folder that need to be found at the root of the application, such as the [robots.txt] file intended for search engines; |
components | the application’s [view] components used in [layouts] and [pages]; |
layouts | the [Vue] components of the application used to layout the [pages]; |
pages | the [Vue] components displayed by the application’s various routes. These could be called the application’s views. Pages play a special role in [Nuxt]: routes are dynamically created based on the directory structure found in the [pages] folder; |
middleware | scripts executed whenever a route changes. They allow you to control these routes; |
plugins | has a misleading name. It can contain plugins as well as standard scripts. The scripts found in this folder are executed when the application starts; |
store | if it contains a script [index.js], then this script defines an instance of the [Vuex] store; |
If a folder is empty, it can be removed from the directory structure. Above, the [assets, static, middleware, plugins, store] folders can be removed [2].
3.3. The configuration file [nuxt.config]
The application’s execution is controlled by the following [nuxt.config.js] file:
export default {
mode: 'universal',
/*
** Page headers
*/
head: {
title: process.env.npm_package_name || '',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{
hid: 'description',
name: 'description',
content: process.env.npm_package_description || ''
}
],
link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
},
/*
** Customize the progress bar color
*/
loading: { color: '#fff' },
/*
** Global CSS
*/
css: [],
/*
** Plugins to load before mounting the App
*/
plugins: [],
/*
** Nuxt.js dev-modules
*/
buildModules: [
// Doc: https://github.com/nuxt-community/eslint-module
'@nuxtjs/eslint-module'
],
/*
** Nuxt.js modules
*/
modules: [
// Doc: https://bootstrap-vue.js.org
'bootstrap-vue/nuxt',
// Doc: https://axios.nuxtjs.org/usage
'@nuxtjs/axios'
],
/*
** Axios module configuration
** See https://axios.nuxtjs.org/options
*/
axios: {},
/*
** Build configuration
*/
build: {
/*
** You can extend the Webpack configuration here
*/
extend(config, ctx) {}
}
}
- line 2: the type of generated application:
- [universal]: client/server application. When the application is initially loaded, as well as with each page refresh in the browser, the server is requested to deliver the page;
- [sap]: [Single Page Application] type: a server initially delivers the entire application. After that, the client operates independently, even when a page is refreshed in the browser;
- Lines 6–18: define the HTML header `<head>` for the application’s various pages:
- line 7: the <title> tag for the page title;
- lines 8–16: the <meta> tags;
- line 17: the <link> tags
In the generated application, the <head> tag is as follows (source code of the page displayed in the browser):
<title>nuxt-intro</title>
<meta data-n-head="ssr" charset="utf-8">
<meta data-n-head="ssr" name="viewport" content="width=device-width, initial-scale=1">
<meta data-n-head="ssr" data-hid="description" name="description" content="nuxt-intro">
<link data-n-head="ssr" rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="preload" href="/_nuxt/runtime.js" as="script">
<link rel="preload" href="/_nuxt/commons.app.js" as="script">
<link rel="preload" href="/_nuxt/vendors.app.js" as="script">
<link rel="preload" href="/_nuxt/app.js" as="script">
Now, let's modify the [nuxt.config] file as follows:
head: {
title: 'Introduction to [nuxt.js]',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{
hid: 'description',
name: 'description',
content: 'SSR, routing, loading, async data, middleware, plugins, store'
}
],
link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }]
},
When we rerun the application, the <head> tag has changed to the following (source code of the page displayed in the browser):
<head >
<title>Introduction to [nuxt.js]</title>
<meta data-n-head="ssr" charset="utf-8">
<meta data-n-head="ssr" name="viewport" content="width=device-width, initial-scale=1">
<meta data-n-head="ssr" data-hid="description" name="description" content="ssr routing loading asyncdata middleware plugins store">
<link data-n-head="ssr" rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="preload" href="/_nuxt/runtime.js" as="script">
<link rel="preload" href="/_nuxt/commons.app.js" as="script">
<link rel="preload" href="/_nuxt/vendors.app.js" as="script">
<link rel="preload" href="/_nuxt/app.js" as="script">
Let's go back to the [nuxt.config] file:
export default {
mode: 'universal',
/*
** Page headers
*/
head: {
...
},
/*
** Customize the progress bar color
*/
loading: { color: '#fff' },
/*
** Global CSS
*/
css: [],
/*
** Plugins to load before mounting the App
*/
plugins: [],
/*
** Nuxt.js dev-modules
*/
buildModules: [
// Doc: https://github.com/nuxt-community/eslint-module
'@nuxtjs/eslint-module'
],
/*
** Nuxt.js modules
*/
modules: [
// Doc: https://bootstrap-vue.js.org
'bootstrap-vue/nuxt',
// Doc: https://axios.nuxtjs.org/usage
'@nuxtjs/axios'
],
/*
** Axios module configuration
** See https://axios.nuxtjs.org/options
*/
axios: {},
/*
** Build configuration
*/
build: {
/*
** You can extend the Webpack configuration here
*/
extend(config, ctx) {}
}
}
- line 12: between each route in the [nuxt] client, a loading bar appears if the route change takes a little time. The [loading] property allows you to configure this loading bar; here, the color of the bar;
- line 16: the global [css] files. They will be automatically included in all pages of the application;
- lines 24–27: the JavaScript modules required for building the application;
- lines 31–36: the JavaScript modules used by the application;
- line 41: configuration of the [axios] library when it has been selected by the user for HTTP interactions with third-party servers;
- lines 45–50: project build configuration;
You can add other keys to the configuration file. In particular, you can configure the service port (3000 by default) and the project root (by default, the project’s root folder). That’s what we’ll do now by adding the following keys:
// source code directory
srcDir: '.',
router: {
// Root URL of the application's pages
base: '/nuxt-intro/'
},
// server
server: {
// server port - default 3000
port: 81,
// network addresses listened to - default localhost=127.0.0.1
host: '0.0.0.0'
}
- line 2: where to find the project's source code. It is located here in the current directory, i.e., at the same level as the [nuxt.config.js] file. This is the default value;
- lines 8–13: configure the server (keep in mind that a [nuxt] application of the [universal] type is installed on both a server and a client browser);
- line 10: the application’s pages will be served on port 81 of the server;
- line 12: by default [localhost] (network address 127.0.0.1). A machine can have multiple network addresses if it belongs to multiple networks. The address 0.0.0.0 indicates that the web server listens on all of the machine’s network addresses;
- lines 3–6: configure the [nuxt] application router;
- line 5: the application’s pages will be available at the URL [http://localhost:81/nuxt-intro/];
Let’s add these lines to the [nuxt.config.js] file and then run the project (npm dev script). The result is as follows:

- [1] is the machine’s address on a public network;
- in [2], the service port;
- in [3], the application’s root URL;
3.4. The [layouts] folder

The [layouts] folder is intended for layout components. By default, the component named [default.vue] is used. In this project, it is as follows:
<template>
<div>
<nuxt />
</div>
</template>
<style>
html {
font-family: 'Source Sans Pro', -apple-system, BlinkMacSystemFont, 'Segoe UI',
Roboto, 'Helvetica Neue', Arial, sans-serif;
font-size: 16px;
word-spacing: 1px;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: border-box;
margin: 0;
}
.button--green {
display: inline-block;
border-radius: 4px;
border: 1px solid #3b8070;
color: #3b8070;
text-decoration: none;
padding: 10px 30px;
}
.button--green:hover {
color: #fff;
background-color: #3b8070;
}
.button--grey {
display: inline-block;
border-radius: 4px;
border: 1px solid #35495e;
color: #35495e;
text-decoration: none;
padding: 10px 30px;
margin-left: 15px;
}
.button--grey:hover {
color: #fff;
background-color: #35495e;
}
</style>
Comments
- lines 1-5: the component's [template];
- line 3: the <nuxt /> tag designates the current routing page;
- lines 7–55: the style embedded by the layout component. Since this component contains the current routing page, this style will apply to all routed pages in the application;
We can see that the primary purpose of the [default.vue] page here is to apply a style to routed pages.
3.5. The [pages] folder

The [pages] folder contains the routed views, which are what the user sees. The [index.vue] page is the application’s home page. With [nuxt.js], there is no routing file. Routes are determined based on the structure of the [pages] folder. Here, the presence of an [index.vue] file automatically creates a route named [index] with a path of [/index], which is shortened to [/] since it is the home page. Thus, the following route is created:
The [index.vue] file is as follows:
<template>
<div class="container">
<div>
<logo />
<h1 class="title">
nuxt-intro
</h1>
<h2 class="subtitle">
nuxt-intro
</h2>
<div class="links">
<a href="https://nuxtjs.org/" target="_blank" class="button--green">
Documentation
</a>
<a
href="https://github.com/nuxt/nuxt.js"
target="_blank"
class="button--grey"
>
GitHub
</a>
</div>
</div>
</div>
</template>
<script>
import Logo from '~/components/Logo.vue'
export default {
components: {
Logo
}
}
</script>
<style>
.container {
margin: 0 auto;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
.title {
font-family: 'Quicksand', 'Source Sans Pro', -apple-system, BlinkMacSystemFont,
'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
display: block;
font-weight: 300;
font-size: 100px;
color: #35495e;
letter-spacing: 1px;
}
.subtitle {
font-weight: 300;
font-size: 42px;
color: #526488;
word-spacing: 5px;
padding-bottom: 15px;
}
.links {
padding-top: 15px;
}
</style>
The [template] in lines 1–25 displays the following view:

Image [1] is generated by line 4 of the [template]. We can see that the page uses a component called [logo]. This is defined in lines 27–35 of the page’s script. In line 28, the notation [~] refers to the project root.
3.6. The [Logo] component

The [Logo.vue] component is as follows:
<template>
<div class="VueToNuxtLogo">
<div class="Triangle Triangle--two" />
<div class="Triangle Triangle--one" />
<div class="Triangle Triangle--three" />
<div class="Triangle Triangle--four" />
</div>
</template>
<style>
.VueToNuxtLogo {
display: inline-block;
animation: turn 2s linear forwards 1s;
transform: rotateX(180deg);
position: relative;
overflow: hidden;
height: 180px;
width: 245px;
}
.Triangle {
position: absolute;
top: 0;
left: 0;
width: 0;
height: 0;
}
.Triangle--one {
border-left: 105px solid transparent;
border-right: 105px solid transparent;
border-bottom: 180px solid #41b883;
}
.Triangle--two {
top: 30px;
left: 35px;
animation: goright 0.5s linear forwards 3.5s;
border-left: 87.5px solid transparent;
border-right: 87.5px solid transparent;
border-bottom: 150px solid #3b8070;
}
.Triangle--three {
top: 60px;
left: 35px;
animation: goright 0.5s linear forwards 3.5s;
border-left: 70px solid transparent;
border-right: 70px solid transparent;
border-bottom: 120px solid #35495e;
}
.Triangle--four {
top: 120px;
left: 70px;
animation: godown 0.5s linear forwards 3s;
border-left: 35px solid transparent;
border-right: 35px solid transparent;
border-bottom: 60px solid #fff;
}
@keyframes turn {
100% {
transform: rotateX(0deg);
}
}
@keyframes godown {
100% {
top: 180px;
}
}
@keyframes goright {
100% {
left: 70px;
}
}
</style>
This component consists primarily of styles and animations to create an animated image.
3.7. Vue DevTools
[Vue DevTools] is the browser extension that allows you to inspect [nuxt.js] and [vue.js] objects in the browser. We’ve already used it in the chapter on [vue.js]. Let’s examine what this tool finds when our app’s home page is displayed:

- in [1], the [PagesIndex] component refers to the [pages/index.vue] page;
- in [2] we see that this component has a [$route] property, which is the route that led to the [index] page;
As a simple exercise, let’s display this route in the console.
3.8. Modifying the Home Page
We’re going to modify the [index.vue] file. In our project setup, we’ve installed two dependencies:
- [eslint]: which checks the syntax of JavaScript files and Vue components. If the [ESLint] extension for VSCode has been installed, this syntax is checked as you type, and errors are immediately flagged;
- [prettier]: which formats JavaScript code in a standard way;
These dependencies are listed in the [package.json] file:
"devDependencies": {
"@nuxtjs/eslint-config": "^1.0.1",
"@nuxtjs/eslint-module": "^1.0.0",
"babel-eslint": "^10.0.1",
"eslint": "^6.1.0",
"eslint-config-prettier": "^4.1.0",
"eslint-plugin-nuxt": ">=0.4.2",
"eslint-plugin-prettier": "^3.0.1",
"prettier": "^1.16.4"
}
I noticed (Nov 2019) that when installing via the [yarn create nuxt-app] command, the [eslint, prettier] tools do not work while typing. Errors are only reported during compilation. After some research, I found a configuration that works:

Create a [.vscode] folder in the project root and place the following [settings.json] file inside it:
{
"eslint.validate": [
{
"language": "vue",
"autoFix": true
},
{
"language": "javascript",
"autoFix": true
}
],
"eslint.autoFixOnSave": true,
"editor.formatOnSave": false
}
- lines 2–11: specify that when [eslint] validates .vue and .js files, it should fix any errors it can;
- line 12: when a file is saved, [eslint] should fix any errors it can;
- line 13: disables the default formatting in VSCode when saving. [prettier] will handle this instead;
With this configuration:
- syntax or formatting errors are flagged as soon as text is typed;
- formatting errors are automatically corrected when the file is saved;
The [prettier] library is configured by the [.prettierrc] file:

By default, this file is as follows:
{
"semi": false,
"arrowParens": "always",
"singleQuote": true
}
- line 1: no semicolon at the end of statements;
- line 2: if an arrow function has a single parameter, it is enclosed in parentheses;
- line 3: strings are enclosed in single quotes (not double quotes);
We add the following two rules:
{
"semi": false,
"arrowParens": "always",
"singleQuote": true,
"printWidth": 120,
"endOfLine": "auto"
}
- Line 5: The line of code can be up to 120 characters long;
- line 6: the end-of-line character can be either CRLF (Windows) or LF (Unix);
Finally, the [package.json] file is modified as follows:
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start",
"generate": "nuxt generate",
"lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
"lintfix": "eslint --fix --ext .js,.vue --ignore-path .gitignore ."
},
- Line 7: We add the [lintfix] command, which is identical to the [lint] command on line 6 except that it includes the [--fix] parameter. The [lint] command checks the syntax and formatting of all files in the project and reports any errors. [lintfix] will do the same, except that any formatting issues that can be corrected will be fixed automatically. [lintfix] is the command to use if the build fails due to file formatting issues;
With that done, we modify the [index.vue] file as follows:

<script>
/* eslint-disable no-console */
import Logo from '~/components/Logo.vue'
export default {
components: {
Logo
},
// lifecycle
created() {
console.log('created, route=', this.$route)
}
}
</script>
- lines 10–12: we add the [created] function, which is automatically executed when the component is created;
- line 11: we display the current route;
- line 2: a comment intended for [eslint]. Without this comment, [eslint] reports an error line 11: it does not allow [console] statements in lifecycle functions. [eslint] is configurable. We will keep its default configuration and use comments like the one on line 2 to disable a specific [eslint] rule. We will use two types of comments:
- /* disable [eslint] rule */: disables a rule for the entire file;
- // disable [eslint] rule: disables a rule for the following line;
As you type, errors are flagged and a [Quick Fix] feature is available:

Run the project:

- in [1], the [View] tab of the browser’s developer tools (F12);
- in [2] and [3], the route display;
Why two views instead of just one?
A [Nuxt] application consists of two components, a server and a client:
- the server provides the application’s pages when the application starts up and then every time a page is refreshed in the browser (F5) or the user manually enters an application URL;
- Each page served by the browser contains the requested page as well as the JavaScript code for the entire application, which is then executed in the browser. This is the client. As long as there is no page refresh in the browser, the application functions like a classic Vue application in [SPA] (Single Page Application) mode. As soon as the user manually triggers a page refresh, the page is requested from the server, and we return to the previous step 1.
What you need to understand is that these are the same pages from the [pages] folder that are served by either the server or the client. For this reason, the developers of [nuxt] call this type of page an isomorphic page. The same [.vue] pages can be interpreted by both the client and the server. Let’s take the example of the [index] page:
<template>
<div class="container">
<div>
<logo />
nuxt-intro
</h1>
<h2 class="subtitle">
nuxt-intro
</h2>
<div class="links">
<a href="https://nuxtjs.org/" target="_blank" class="button--green">
Documentation
</a>
<a
href="https://github.com/nuxt/nuxt.js"
target="_blank"
class="button--grey"
>
GitHub
</a>
</div>
</div>
</div>
</template>
<script>
/* eslint-disable no-console */
import Logo from '~/components/Logo.vue'
export default {
components: {
Logo
},
// lifecycle
created() {
console.log('created, route=', this.$route)
}
}
</script>
Since this is the home page, it is served by the server when the application starts. The page on the server also has a lifecycle, the same as that of a classic [Vue] page except for the [beforeMount, mounted] functions, which do not exist on the server side. The [created] function is executed, which explains the first log. This means, by the way, that the server is capable of executing JavaScript scripts. Here and in general, this server is a [node.js] server. Once the page is created on the server, it arrives in the browser where it undergoes the lifecycle again. The [created] function is executed a second time, which produces the second log.
The architecture of a [nuxt] application could be as follows:

- [1]: the browser that hosts the [nuxt] application once it has been loaded into the browser. This is what we call the [nuxt] client;
- [3]: the server that initially hosts the [nuxt] application. It is loaded into the browser [1] when the application starts and every time the user refreshes the current browser page or manually enters an application URL. This is where the difference in operation lies compared to a classic Vue application. With a classic Vue application, once loaded into the browser, the server was never called upon again. Another important difference we haven’t seen yet is that the server for a Vue application is a static server, incapable of interpreting [.vue] pages, whereas the server for a [universal] Nuxt application is a JavaScript server. Before sending a page to the browser, the server can execute scripts and, for example, fetch data from the server [2];
- [2]: is the server that provides data either to the [nuxt] client [1] or to the [nuxt] server [3];
In the diagram above, we can distinguish three client/server subsystems:
- [1, 3]: hosts the [nuxt] application. [3] provides it when the application starts up with the home page and every time the user manually requests a page. [1] hosts the [nuxt] application received from [3], which then operates in [SAP] mode as long as pages are not manually requested from [3];
- [1, 2]: In [SAP] mode, the [nuxt] client retrieves external data from one or more servers;
- [3, 2]: when generating the page requested by the user, server [3] can also retrieve external data from one or more servers;
It is therefore the server [3] that distinguishes a [Nuxt] application from a [Vue] application. This server is called upon every time the user manually requests a page. It processes the same [.vue] pages as the [Vue] client [1]. It is a JavaScript server capable of executing the scripts present on the page. This can, for example, change how the homepage is generated using external data: whereas a [vue] application necessarily fetches this data from the client [1], here it can be fetched by the server [3] before the page is sent to the client. The homepage thus becomes meaningful and can help improve the application’s SEO.
Note: In development mode, the three entities [1, 2, 3] are often on the same machine. This will be the case here for all our examples.
3.9. Moving the application’s source code to a separate folder
Next, we will create various [nuxt] applications in the same [dvp] folder. This is because the [node_modules] dependencies folder generated for each [nuxt] project can be several hundred megabytes in size. We will create various folders [nuxt-00, nuxt-01, ...] within the [dvp] folder to hold the source code for the examples to be tested. Then we will use the configuration file [nuxt-config.js] to specify the location of the source code for the [dvp] project, which will remain the sole [nuxt] project in this tutorial.
We move the source code of the application initially generated by the [yarn create nuxt-app] command into a [nuxt-00] folder:

- in [2], we moved the [components, layouts, pages] folders into a [nuxt-00] folder;
- In [3], we need to modify the [nuxt.config.js] file;
We modify the [nuxt.config.js] file as follows:
export default {
mode: 'universal',
/*
** Page headers
*/
...
/*
** Build configuration
*/
build: {
/*
** You can extend the Webpack configuration here
*/
extend(config, ctx) {}
},
// source code directory
srcDir: 'nuxt-00',
// router
router: {
// application URL root
base: '/nuxt-00/'
},
// server
server: {
// server port, 3000 by default
port: 81,
// network addresses listened to, default is localhost: 127.0.0.1
// 0.0.0.0 = all network addresses on the machine
host: '0.0.0.0'
}
}
The file is modified in two places:
- line 17: we specify that the source code for the [dvp] project is located in the [nuxt-00] folder;
- line 21: we specify that the application’s root URL is now [/nuxt-00/]. This change was not mandatory. We could have omitted this property, in which case the root of the URLs would be [/]. Here, this will help us remember that the source code being executed is from the [nuxt-00] folder;
Once this is done, the [dvp] project is executed as before:

3.10. Deploying the [nuxt-00] application
We will run the [nuxt-00] application in an environment other than VSCode’s built-in environment.
First, we compile the application:

- in [3], the result of the client compilation. This will be executed by the browser;
- in [4], the result of the server compilation. This will be executed by the [node.js] server;
The compilation output is placed in the [.nuxt] folder:

We copy the [.nuxt, node_modules] folders and the [package.json, nuxt.config.js] files to a separate folder:

The [package.json] file is simplified as follows:
{
"scripts": {
"start": "nuxt start"
}
}
- We keep only the [start] script, which runs the compiled version of the project;
The [nuxt.config.js] file is simplified as follows:
export default {
// router
router: {
// application URL root
base: '/nuxt-00/'
},
// server
server: {
// server port, 3000 by default
port: 81,
// network addresses listened to, default is localhost: 127.0.0.1
// 0.0.0.0 = all network addresses on the machine
host: '0.0.0.0'
}
}
- line 5: sets the base URL of the compiled application;
- lines 8–14: define the service port and the network addresses to listen on;
Once this is done, open a Laragon terminal and navigate to the folder containing the compiled version of the project. You can open any type of terminal, but the [npm] executable must be in the terminal’s PATH. This is the case for the Laragon terminal.
Once this is done, type the command [npm run start]:

In [3], we see that a server has been launched and is listening at the URL [http://192.168.1.128:81/nuxt-00/]. Now let’s request this URL using a browser [4]. We see the same result as before. In the terminal, logs have been written [5]. This is the log placed in the [created] method of the [index.vue] page, which was executed by the [node.js] server.

On the browser side [6], we also see the log from the [created] method of the [index.vue] page, but this time executed by the client.
3.11. Setting up a secure server
Above, the application’s URL is [http://192.168.1.128/nuxt-00/]. We’d like it to be [https://192.168.1.128/nuxt-00/]. So we need to set up a secure server. Here’s how to do it.
Note: This method was taken from the article [https://stackoverflow.com/questions/56966137/how-to-run-nuxt-npm-run-dev-with-https-in-localhost].
First, we create a private key and a public key using [openssl]. [openssl] is normally installed along with the Laragon server. As a result, this command is available in any Laragon terminal. So let’s open a Laragon terminal and navigate to the folder of the deployed application:


- in [2], type the command [openssl genrsa 2048 > server.key];
- in [3], a [server.key] file is created;
- in [4], type the command [openssl req -new -x509 -nodes -sha256 -days 365 -key server.key -out server.crt];
- in [5], a file named [server.crt] is created;
These two files constitute a self-signed certificate. Most browsers only accept them after approval by the user who requested the page.
The [server.key, server.crt] files must now be used by the web application. To do this, the [nuxt.config.js] file must be modified as follows:
import path from 'path'
import fs from 'fs'
export default {
// router
router: {
// application URL root
base: '/nuxt-00/'
},
// server
server: {
// server port, 3000 by default
port: 81,
// network addresses listened to, default is localhost: 127.0.0.1
// 0.0.0.0 = all network addresses on the machine
host: '0.0.0.0',
// self-signed certificate
https: {
key: fs.readFileSync(path.resolve(__dirname, 'server.key')),
cert: fs.readFileSync(path.resolve(__dirname, 'server.crt'))
}
}
}
Lines 18–21 implement the [https] protocol.
Now let’s run the application again:

3.12. End of the first example
The first example is now complete. It has taught us many [nuxt] concepts. We will now develop other examples that we will place in folders [nuxt-01, nuxt-02, ...]. Since these examples will use a different [nuxt.config.js] file, we will save the [nuxt.config.js] file used to run each of them in their respective folders:
