code English

AdonisJS 5 and Tailwind10 min read

Mayıs 15, 2021 6 min read

AdonisJS 5 and Tailwind10 min read

Reading Time: 6 minutes

AdonisJS 5 released its stable version. I plan this post to be a tutorial about AdonisJS 5. In this article, I will do the basic setups for the AdonisJS application and integrate it with the Tailwind CSS library.


My only back-end experience is with Python Django. I was thinking of using Node for a long time. But I just couldn’t get used to Node frameworks. I think Django has a big impact on this. I like to use Django with JavaScript.

However, I have been watching a few libraries that interested me for a while. Among them is AdonisJS.

AdonisJS has migrated to the newer version 5. I previously failed because I tried to use it during this transition before. Fortunately, This time I get used to the concepts of Adonis.

AdonisJS 5

AdonisJS is an opinionated fully featured web framework for Node.js.

Also, AdonisJS is one of the few Node.js frameworks (if not the only one) that has first-class support for SQL databases. It has Lucid ORM. This is maybe one of the most important factors for me to try AdonisJS. Because Django is a batteries-included framework and it has a nice ORM.

Installation of AdonisJS

There are two ways to install it. My choice would be using yarn. However, it doesn’t work in my case. It throws an error. Therefore, I’ll use the way of npm init.

# npm npm init adonis-ts-app@latest myapp # OR # yarn yarn create adonis-ts-app myapp
Code language: Bash (bash)

Choosing Project Type and Initial Customization

Choose web project.

_ _ _ _ / \ __| | ___ _ __ (_)___ | |___ / _ \ / _` |/ _ \| '_ \| / __|_ | / __| / ___ \ (_| | (_) | | | | \__ \ |_| \__ \ /_/ \_\__,_|\___/|_| |_|_|___/\___/|___/ CUSTOMIZE PROJECT ❯ Select the project structure … Press <ENTER> to select api (Tailored for creating a REST API server) ▸ web (Traditional web application with server-rendered templates) slim (A smallest possible AdonisJS application)
Code language: Bash (bash)

You can customize your settings like below.

CUSTOMIZE PROJECT ❯ Select the project structure · web ❯ Enter the project name · myapp ❯ Setup eslint? (y/N) · true ❯ Setup prettier? (y/N) · true ❯ Configure webpack encore for compiling front-end assets? (y/N) · true
Code language: JavaScript (javascript)
npm i @adonisjs/lucid
Code language: Bash (bash)

Starting Server

Change your directory to newly created one and start the development server.

╭─────────────────────────────────────────────────╮ │ Run following commands to get started │ │─────────────────────────────────────────────────│ │ │ │ ❯ cd myapp │ │ ❯ node ace serve --watch │ │ │ ╰─────────────────────────────────────────────────╯
Code language: Bash (bash)

Open a new tab in your browser and visit http://127.0.0.1:3333/. You’ll see a welcoming message like this.

AdonisJS 5 Welcome Screen

Database and Lucid ORM Installation

I’ll install database and Lucid ORM. I’ll choose to use SQLite.

# Install Lucid ORM npm i @adonisjs/lucid
Code language: CSS (css)

After, let Adonis to make database arrangements for you.

node ace configure @adonisjs/lucid
Code language: CSS (css)

Use SPACE to select SQLite, then press ENTER.

❯ Select the database driver you want to use … Press <SPACE> to select ◯ SQLite ◯ MySQL / MariaDB ◯ PostgreSQL ◯ OracleDB ◯ Microsoft SQL Server
Code language: HTML, XML (xml)

Choose browser for intructions. A new tab including setup instructions will be automatically open. However, You won’t see proper SQLite instructions.

❯ Select where to display instructions · browser
You can also check Wave Snippets for this kind of presentation

You’ll find SQLite settings in the config/database.ts file. I’ll change my database filepath.

// config/database.ts import Env from '@ioc:Adonis/Core/Env' import { DatabaseConfig } from '@ioc:Adonis/Lucid/Database' const databaseConfig: DatabaseConfig = { connection: Env.get('DB_CONNECTION'), connections: { sqlite: { client: 'sqlite', connection: { filename: "database/db.sqlite",// <---------- changed ------| }, migrations: { naturalSort: true, }, useNullAsDefault: true, healthCheck: false, debug: false, }, } } export default databaseConfig
Code language: TypeScript (typescript)

Also, don’t forget to install SQLite driver.

npm i sqlite3

Also in order to create an SQLite database via graphical user interface, you should install DB Browser for SQLite
Install and create a database file located at database/db.sqlite.

Creating Models

node ace make:model User
Code language: CSS (css)

The final code of app/Models/User.ts is below:

import { DateTime } from 'luxon' import { BaseModel, column } from '@ioc:Adonis/Lucid/Orm' export default class User extends BaseModel { @column({ isPrimary: true }) public id: number @column() public name?: string @column() public username: string @column() public email: string @column({ serializeAs: null }) public password: string @column() public imageUrl?: string @column() public rememberMeToken?: string @column.dateTime({ autoCreate: true }) public createdAt: DateTime @column.dateTime({ autoCreate: true, autoUpdate: true }) public updatedAt: DateTime }
Code language: PHP (php)

Creating Migration

Now, We’ll create a database migration for the model.

First, create migration file node ace make:migration user. This will create a migration file that looks like this:

// database/migrations/1620593365657_users.ts import BaseSchema from '@ioc:Adonis/Lucid/Schema' export default class Users extends BaseSchema { protected tableName = 'users' public async up () { this.schema.createTable(this.tableName, (table) => { table.increments('id') table.timestamps(true) }) } public async down () { this.schema.dropTable(this.tableName) } }
Code language: JavaScript (javascript)

Now, add the new lines and change the migration file. The Final form should look like this :

// database/migrations/1620593365657_users.ts import BaseSchema from '@ioc:Adonis/Lucid/Schema' export default class Users extends BaseSchema { protected tableName = 'users' public async up() { this.schema.createTable(this.tableName, (table) => { table.increments('id') table.string('name', 50) // New table.string('username', 50).unique().notNullable() // New table.string('email', 255).unique().notNullable() // New table.string('password', 180).notNullable() // New table.string('image_url', 100) // New table.string('remember_me_token').nullable() // New table.timestamps(true) }) } public async down() { this.schema.dropTable(this.tableName) } }
Code language: JavaScript (javascript)

Now, the following command will make the migration:

node ace migration:run user
Code language: Bash (bash)

You can open DB for SQLite app and check if it is true.

Create Views

Adonis uses Edge template engine which I really like.
First, create a master layout file which is a blueprint of our front-end.

# this will create resources/views/layouts/master.edge node ace make:view layouts/master
Code language: Bash (bash)

Now, we can add some code to the file. You’ll notice that @!section('content') part. The master.edge file will be used by another template.
Add the lines below to the resources/views/layouts/master.edge file.

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Webmeister's Adonis Introduction</title> <link rel="shortcut icon" href="/favicon.ico"> </head> <body> <div class="container-fliud"> @!section('content') </div> </body> </html>
Code language: HTML, XML (xml)

Let’s create a file which will be used as a route view.

# this will create resources/views/index.edge node ace make:view index
Code language: Bash (bash)

Also, add these code to the resources/views/index.edge file:

@layout('layouts/master') @section('content') <main> </main> @endsection
Code language: HTML, XML (xml)

The Adonis router automatically look in resources/views folder for the view.
Open your route file and change it according to this:

// start/routes.ts Route.get('/', async ({ view }) => { return view.render('index') })
Code language: TypeScript (typescript)

Now, we can create re-usable components. I’ll first create a navigation bar. In Edge, we can do this by the partial templates. Partials are used on many page and views. I’ll also use Devdojo Tail’s demo components.

# this will create resources/views/partials/navbar.edge node ace make:view partials/navbar
Code language: Bash (bash)

Add the codes to the resources/partials/navbar.edge file.

<header class="w-full px-8 text-gray-700 bg-white"> <div class="container flex flex-col flex-wrap items-center justify-between py-5 mx-auto md:flex-row max-w-7xl"> <div class="relative flex flex-col md:flex-row"> <a href="#_" class="flex items-center mb-5 font-medium text-gray-900 lg:w-auto lg:items-center lg:justify-center md:mb-0"> <span class="mx-auto text-xl font-black leading-none text-gray-900 select-none">tails<span class="text-indigo-600">.</span></span> </a> <nav class="flex flex-wrap items-center mb-5 text-base md:mb-0 md:pl-8 md:ml-8 md:border-l md:border-gray-200"> <a href="#_" class="mr-5 font-medium leading-6 text-gray-600 hover:text-gray-900">Home</a> <a href="#_" class="mr-5 font-medium leading-6 text-gray-600 hover:text-gray-900">Features</a> <a href="#_" class="mr-5 font-medium leading-6 text-gray-600 hover:text-gray-900">Pricing</a> <a href="#_" class="mr-5 font-medium leading-6 text-gray-600 hover:text-gray-900">Blog</a> </nav> </div> <div class="inline-flex items-center ml-5 space-x-6 lg:justify-end"> <a href="#" class="text-base font-medium leading-6 text-gray-600 whitespace-no-wrap transition duration-150 ease-in-out hover:text-gray-900"> Sign in </a> <a href="#" class="inline-flex items-center justify-center px-4 py-2 text-base font-medium leading-6 text-white whitespace-no-wrap bg-indigo-600 border border-transparent rounded-md shadow-sm hover:bg-indigo-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-600"> Sign up </a> </div> </div> </header>
Code language: HTML, XML (xml)

Because navbar component will be on every page, we should inform the master layout. We insert the partial template by putting this @include('partials/navbar') to the proper place.

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Webmeister's Adonis Introduction</title> <link rel="shortcut icon" href="/favicon.ico"> </head> <body> <div class="container-fliud"> @include('partials/navbar') @!section('content') </div> </body> </html>
Code language: HTML, XML (xml)

Adding Tailwind to Adonis

On your project directory, install the dependencies:

# install dependencies npm install -D tailwindcss@latest postcss@latest autoprefixer@latest # create postcss config file touch postcss.config.js # also install postcss-load npm i -D postcss-loader # create tailwind config file npx tailwindcss init
Code language: Bash (bash)

Set the postcss.config.js.

// postcss.config.js module.exports = { plugins: [require('tailwindcss'), require('autoprefixer')], }
Code language: JavaScript (javascript)

Also make tialwind confifs as follow. (Note: I’m also exploring tailwind and the code below includes my settings)

// tailwind.config.js const colors = require('tailwindcss/colors') module.exports = { mode: 'jit', purge: ['./resources/views/**/*.edge', './resources/assets/ts/**/*.ts'], darkMode: 'class', // or 'media' or 'class' theme: { extend: {}, }, variants: { extend: {}, }, plugins: [], theme: { colors: { transparent: 'transparent', current: 'currentColor', black: colors.black, white: colors.white, gray: colors.trueGray, indigo: colors.indigo, red: colors.rose, yellow: colors.amber, teal: colors.teal, darkblue: colors.blueGray, }, }, }
Code language: JavaScript (javascript)

We should also tell the webpack that we will use postcss. Fortunately, the webpack settings are already done for us. We just need to uncomment the line:

// webpack.config.js /* Find the line below and uncomment it */ Encore.enablePostCssLoader() /*
Code language: JavaScript (javascript)

We should create a separate css file for tailwinds. On your project’s root directory, create the file.

touch resources/css/tailwind.css
Code language: Bash (bash)
/* resources/css/tailwind.css */ @tailwind base; @tailwind components; @tailwind utilities;
Code language: CSS (css)

Import tailwind.css to app.css. Open app.css file. Only add this single line to the top of the file.

@import "./tailwind.css"; /* * */
Code language: CSS (css)

We’ll finish adding Tailwind to Adonis5 app with this final single line modification. Open your master.edge file, and add this single line to the head part:
<link rel="stylesheet" type="text/css" href="{{ asset('assets/app.css') }}">

The final form of the master.edge should look like this.

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Webmeister's Adonis Introduction</title> <link rel="shortcut icon" href="/favicon.ico"> <link rel="stylesheet" type="text/css" href="{{ asset('assets/app.css') }}"> </head> <body> <div class="container-fliud"> @include('partials/navbar') @!section('content') </div> </body> </html>
Code language: HTML, XML (xml)

If you open your app, you’ll see that tailwind is successfully integrated with AdonisJS app.

Tailwind Header AdonisJS

The post is not fully finished.

Leave a comment