DEV Community

Sébastien NOBILI
Sébastien NOBILI

Posted on • Originally published at techreads.pipoprods.org

Add Vue.js + Vite to an AdonisJS Application

AdonisJS is a Node.js backend framework. There's no frontend framework coming with it, everything is rendered on the server side.

This article will describe how to integrate Vue.js (and Vite) to an AdonisJS application.

You should first create a new project with a "web" structure and no Webpack Encore integration:

CUSTOMIZE PROJECT
❯ Select the project structure · web
❯ Enter the project name · hello-world
❯ Setup eslint? (y/N) · false
❯ Configure webpack encore for compiling frontend assets? (y/N) · false
Enter fullscreen mode Exit fullscreen mode

Add Vue.js & Vite dependencies & Configure Vite

# if using npm
npm install vue && npm install --dev vite @vitejs/plugin-vue

# if using yarn
yarn add vue && yarn add -D vite @vitejs/plugin-vue

# if using pnpm
pnpm install vue && pnpm install -D vite @vitejs/plugin-vue
Enter fullscreen mode Exit fullscreen mode

Create Vite configuration at the root of your project (vite.config.ts):

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import path from 'path';

// https://vitejs.dev/config/
export default defineConfig(({ command }) => {
  return {
    base: command === 'serve' ? '' : '/build/',
    publicDir: 'fake_dir_so_nothing_gets_copied',
    build: {
      manifest: true,
      outDir: 'public/build',
      rollupOptions: {
        input: 'resources/js/app.ts',
      },
    },
    plugins: [vue()],
  };
});
Enter fullscreen mode Exit fullscreen mode

Reconfigure app startup scripts

You'll need a parallel script runner like npm-run-all:

# if using npm
npm install --dev npm-run-all

# if using yarn
yarn add -D npm-run-all

# if using pnpm
pnpm install -D npm-run-all
Enter fullscreen mode Exit fullscreen mode

Then reconfigure your npm dev script this way (package.json excerpt):

{
  "scripts": {
    "dev": "run-p ace:serve vite:serve",
    "ace:serve": "node ace serve --watch",
    "vite:serve": "vite --host --port 3000",
  }
}
Enter fullscreen mode Exit fullscreen mode

At this point, the npm dev command starts both AdonisJS & Vite.
But we lack the integration of both: how AdonisJS will instruct your browser that it should load assets generated by Vite?

Integrate Vite into AdonisJS

We'll create a ViteProvider class that will generate the contents to be included into AdonisJS pages:

Paste this into providers/ViteProvider.ts:

import { ApplicationContract } from '@ioc:Adonis/Core/Application';
import Env from '@ioc:Adonis/Core/Env';
import { readFileSync } from 'fs';

export default class ViteProvider {
  public static needsApplication = true;

  constructor(protected app: ApplicationContract) {}

  public async boot() {
    const View = this.app.container.resolveBinding('Adonis/Core/View');

    const served = () => {
      const port = Env.get('VITE_PORT', 3000);
      return `
      <script type="module" src="http://localhost:${port}/@vite/client"></script>
      <script type="module" src="http://localhost:${port}/resources/vue/app.ts" ></script>
    `;
    };

    const built = () => {
      const data = readFileSync('./public/build/manifest.json').toString();
      const manifest = JSON.parse(data);
      return `<script type="module" src="/build/${manifest['resources/vue/app.ts']['file']}"></script>`;
    };
    View.registerTag({
      tagName: 'vite',
      seekable: false,
      block: false,
      compile(_, buffer) {
        buffer.outputRaw(
          Env.get('NODE_ENV') === 'development' ? served() : built(),
        );
      },
    });
  }
}
Enter fullscreen mode Exit fullscreen mode

Register the provider into .adonisrc.json file (excerpt):

{
  "providers": [
    "./providers/ViteProvider",
  ],
}
Enter fullscreen mode Exit fullscreen mode

Replace default view contents (resources/views/welcome.edge):

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="icon" type="image/png" href="/favicon.ico" />

    @vite

``    <title>AdonisJS + Vue.js + Vite</title>
  </head>

  <body>
    <div id="app"></div>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Create basic Vue.js application

Create Vue.js application main entry point in resources/vue/app.ts:

import { createApp } from 'vue';
import App from './App.vue';

createApp(App).mount('#app');
Enter fullscreen mode Exit fullscreen mode

Create main component in resources/vue/App.vue:

<template>Welcome to AdonisJS + Vue.js + Vite</template>

<script lang="ts">
import { defineComponent } from 'vue';

export default defineComponent({
  setup() {},
});
</script>
Enter fullscreen mode Exit fullscreen mode

Adjust for production build

We need to adjust build scripts as well (package.json excerpt):

{
  "scripts": {
    "build": "run-s vite:build ace:build",
    "ace:build": "node ace build --production",
    "vite:build": "vite build"
  },
}
Enter fullscreen mode Exit fullscreen mode

Our application will be build through the npm run build command.

This will fail because of the Vue.js code being processed by the TypeScript compiler.

To circumvent this, we add the Vue.js app folder to the TypeScript exclude paths (tsconfig.json excerpt):

{
  "exclude": ["resources/vue/", "node_modules", "build"],
}
Enter fullscreen mode Exit fullscreen mode

Final thoughts

This article gives the steps for a basic Vue.js integration into AdonisJS.

The developer experience can be enhanced by integrating a few more libraries:

Top comments (1)

Collapse
 
abdelatif_laghjaj profile image
Abdelatif Laghjaj

Thank youu mate