Vite
AdonisJS uses Vite to bundle the frontend assets of your applications. We provide an official integration that performs all the heavy lifting required to integrate Vite with a backend framework like AdonisJS. It includes:
- Embedding the Vite development server inside AdonisJS.
- A dedicated Vite plugin to simplify configuration options.
- Edge helpers and tags to generate URLs for assets processed by Vite.
- Access to the Vite Runtime API to perform server-side rendering (SSR).
Vite is embedded inside the AdonisJS dev server, and every request that should be handled by Vite is proxied to it through an AdonisJS middleware. It allows us to directly access Vite's runtime API to perform server-side rendering (SSR) and manage a single dev server. That also means that assets are served by AdonisJS directly and not by a separate process.
Still using @adonisjs/vite 2.x ? See the migration guide to upgrade to the latest version.
Installation
First, make sure to have at least the following versions of AdonisJS installed:
@adonisjs/core
: 6.9.1 or later@adonisjs/assembler
: 7.7.0 or later
Then install and configure the @adonisjs/vite
package. The command below installs the package and vite
, and configures the project by creating the necessary configuration files.
node ace add @adonisjs/vite
-
Registers the following service provider inside the
adonisrc.ts
file.{providers: [// ...other providers() => import('@adonisjs/vite/vite_provider')]} -
Create
vite.config.ts
andconfig/vite.ts
configuration files. -
Create the frontend entry point file, i.e.
resources/js/app.js
.
Once done, add the following to your adonisrc.ts
file.
import { defineConfig } from '@adonisjs/core/build/standalone'
export default defineConfig({
assetsBundler: false,
hooks: {
onBuildStarting: [() => import('@adonisjs/vite/build_hook')],
},
})
The assetsBundler
property is set to false
to turn off the assets bundler management done by the AdonisJS Assembler.
The hooks
property registers the @adonisjs/vite/build_hook
to execute the Vite build process. See Assembler hooks for more information.
Configuration
The setup process creates two configuration files. The vite.config.ts
file is used to configure the Vite bundler, and config/vite.ts
is used by AdonisJS on the backend.
Vite config file
The vite.config.ts
file is a regular configuration file used by Vite. Per your project requirements, you can install and register additional Vite plugins inside this file.
By default, the vite.config.ts
file uses the AdonisJS plugin, which accepts the following options.
import { defineConfig } from 'vite'
import adonisjs from '@adonisjs/vite/client'
export default defineConfig({
plugins: [
adonisjs({
entrypoints: ['resources/js/app.js'],
reload: ['resources/views/**/*.edge'],
}),
]
})
- entrypoints
-
The
entrypoints
refers to the entry point file of your frontend codebase. Usually, it will be a JavaScript or a TypeScript file with additional imports. Each entry point will result in a separate output bundle.Also, if needed, you can define multiple entrypoints. For example, an entry point for your user-facing app and another for the admin panel.
- buildDirectory
-
The
buildDirectory
option defines a relative path to the output directory. The option value is supplied to Vite as thebuild.outDir
option.If you decide to change the default value, make sure also to update the
buildDirectory
path in theconfig/vite.ts
file.Default: public/assets
- reload
-
It contains an array of glob patterns to watch and reload the browser on file change. By default, we watch for Edge templates. However, you can configure additional patterns as well.
- assetsUrl
-
It contains the URL to prefix when generating links for assets in production. If you upload the Vite output to a CDN, then the value of this property should be the CDN server URL.
Ensure you update the backend configuration to use the same
assetsUrl
value.
AdonisJS config file
AdonisJS uses the config/vite.ts
file on the backend to know about the output paths of the Vite build process.
import { defineConfig } from '@adonisjs/vite'
const viteBackendConfig = defineConfig({
buildDirectory: 'public/assets',
assetsUrl: '/assets',
})
export default viteBackendConfig
- buildDirectory
-
It contains the path to the Vite's build output directory. You must also update this backend config if you change the default value inside the
vite.config.ts
file. - assetsUrl
-
The URL to prefix when generating links for assets in production. If you upload the Vite output to a CDN, then the value of this property should be the CDN server URL.
- scriptAttributes
-
You can use the
scriptAttributes
property to set attributes on the script tags generated using the@vite
tag. The attributes are a collection of key-value pairs.config/vite.tsdefineConfig({scriptAttributes: {defer: true,async: true,}}) - styleAttributes
-
You can use the
styleAttributes
property to set attributes on the link tags generated using the@vite
tag. The attributes are a collection of key-value pairs.config/vite.tsdefineConfig({styleAttributes: {'data-turbo-track': 'reload'}})You can also apply the attributes conditionally by assigning a function to the
styleAttributes
option.defineConfig({styleAttributes: ({ src, url }) => {if (src === 'resources/css/admin.css') {return {'data-turbo-track': 'reload'}}}})
Folder structure for frontend assets
Technically, AdonisJS does not enforce any folder structure for storing your frontend assets. You can organize them as you like.
However, we recommend storing frontend assets inside the resources
folder, with each asset class inside its subdirectory.
resources
└── css
└── js
└── fonts
└── images
The vite output will be in the public/assets
folder. We choose the /assets
subdirectory so you can continue using the public
folder for other static files you wish not to process using Vite.
Starting the dev server
You can start your application as usual, and AdonisJS will automatically proxy the needed requests to Vite.
node ace serve --hmr
Including entrypoints in Edge templates
You can render the script and the style tags for the entrypoints defined inside the vite.config.ts
file using the @vite
Edge tag. The tag accepts an array of entrypoints and returns the script
and the link
tags.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
@vite(['resources/js/app.js'])
</head>
<body>
</body>
</html>
We recommend importing CSS files inside your JavaScript files and not registering them separately as an entry point. For example:
resources
└── css
└── app.css
└── js
└── app.js
import '../css/app.css'
Referencing assets inside Edge templates
Vite creates a dependency graph of files imported by the entrypoints and auto-updates their paths per the bundled output. However, Vite is unaware of Edge templates and cannot detect their referenced assets.
Therefore, we provide an Edge helper you can use to create URLs for files processed by Vite. In the following example:
- The
asset
helper will return a URL pointing to the Vite dev server during development. - Return a URL pointing to the output filename during production.
<link rel="stylesheet" href="{{ asset('resources/css/app.css') }}">
<link rel="stylesheet" href="http://localhost:5173/resources/css/app.css">
<link rel="stylesheet" href="/assets/app-3bc29777.css">
Processing additional assets with Vite
Vite ignores static assets not imported by the frontend code. It could be static images, fonts, or SVG icons only referenced inside the Edge templates.
Therefore, you will have to notify Vite about the existence of these assets using its Glob imports API.
In the following example, we ask Vite to process all the files within the resources/images
directory. This code should be written within an entry point file.
import.meta.glob(['../images/**'])
Now, you can reference the images within your Edge templates as follows.
<img src="{{ asset('resources/images/hero.jpg') }}" />
Configuring TypeScript
If you plan to use TypeScript in your frontend codebase, create an additional tsconfig.json
file inside the resources
directory. Vite and your code editor will automatically use this config file for the TypeScript source code inside the resources
directory.
{
"extends": "../tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"lib": ["DOM"],
"jsx": "preserve", // If you are using React
"paths": {
"@/*": ["./js/*"]
}
}
}
Enabling HMR with React
To enable react-refresh during development, you must use the @viteReactRefresh
Edge tag. It should be written before you include the entrypoints using the @vite
tag.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
@viteReactRefresh()
@vite(['resources/js/app.js'])
</head>
<body>
</body>
</html>
Once done, you can configure the React plugin as usual in a regular Vite project.
import { defineConfig } from 'vite'
import adonisjs from '@adonisjs/vite/client'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [
adonisjs({
entrypoints: ["resources/js/app.js"],
}),
react(),
],
})
Deploying assets to a CDN
After you create the production build using Vite, you can upload the bundled output to a CDN server to serve the files.
However, before you do that, you must register the URL of your CDN server with both Vite and AdonisJS so that the output URLs inside the manifest.json
file or lazy loaded chunks should point to your CDN server.
You must define the assetsUrl
inside the vite.config.ts
and config/vite.ts
files.
import { defineConfig } from 'vite'
import adonisjs from '@adonisjs/vite/client'
export default defineConfig({
plugins: [
adonisjs({
entrypoints: ['resources/js/app.js'],
reloads: ['resources/views/**/*.edge'],
assetsUrl: 'https://cdn.example.com/',
}),
]
})
import { defineConfig } from '@adonisjs/vite'
const viteBackendConfig = defineConfig({
buildDirectory: 'public/assets',
assetsUrl: 'https://cdn.example.com/',
})
export default viteBackendConfig
Advanced concepts
Middleware Mode
With older versions of AdonisJS, Vite was spawned as a separate process and had its own dev server.
With the 3.x version, Vite is embedded inside the AdonisJS dev server, and every request that should be handled by Vite are proxied to it through an AdonisJS middleware.
The advantages of the middleware mode are that we can directly access Vite's runtime API to perform server-side rendering (SSR) and have a single dev server to manage.
You can read more about the middleware mode in the Vite documentation.
Manifest file
Vite generates the manifest file alongside the production build of your assets.
The manifest file contains the URLs to the assets processed by Vite, and AdonisJS uses this file to create URLs for assets referenced inside the Edge templates either using the asset
helper or the @vite
tag.