How to Use Phoenix 1.7 with Vite.js
Abstract
How to set up a Phoenix 1.7 project with Vite.js in place of the default setup, or how to start a Phoenix project if you’re not a Tailwind person.
This article will guide you through the process of integrating a new Phoenix 1.7 application with Vite.js. I will show you how to use it in development, and how to prepare your application for deployment using Docker. It is a partly rewritten version of an earlier article called Integrating Vite.js with Phoenix 1.6.
On the front end side of things, I will be using the vanilla-ts
template, with no front end framework and pre-configured TypeScript support.
Steps
Make sure you have Elixir, Erlang, and Node.js configured on your development machine. This article was written and tested on Debian 12 “Bookworm”, using Elixir 1.17.3, Erlang 27.1.2, and Node 22.11.0 (the latest LTS version as of this writing):
$ node --version
v22.11.0
$ elixir --version
Erlang/OTP 27 [erts-15.1.2] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [jit:ns]
Elixir 1.17.3 (compiled with Erlang/OTP 27)
# https://stackoverflow.com/a/34326368
$ erl -eval '{ok, Version} = file:read_file(filename:join([code:root_dir(), "releases", erlang:system_info(otp_release), "OTP_VERSION"])), io:fwrite(Version), halt().' -noshell
27.1.2
Install the mix phx.new
generator. This is only necessary when you first generate the project.
$ mix local.hex --force
$ mix archive.install hex phx_new
Create a new Phoenix project. For the sake of simplicity, we will be using SQLite3. This is because SQLite3 stores all of its data in regular files, unlike most other database management systems, such as PostgreSQL or MySQL/MariaDB, which run as servers. This way, I do not need to explain how to configure a database server on your machine.
For a real world project, I highly recommend you use PostgreSQL instead.
$ mix phx.new --database=sqlite3 --no-assets --no-live my_app
After this command has finished its execution, initialize a Git repository and commit the initial contents:
$ cd my_app
$ git init
$ git add -A
$ git commit -m "Initial commit"
Initialize a database and run any migrations (spoiler: there are none).
$ mix ecto.setup
Generated my_app app
The database for MyApp.Repo has been created
19:08:38.799 [info] Migrations already up
[info] Migrations already up
Ensure pnpm
is installed:
which pnpm || npm i -g pnpm
Initialize a Vite project under assets
:
pnpm create vite@latest --template vanilla-ts assets
cd assets
pnpm install
Now may be a good time to commit your changes:
git add -A
git commit -m "Generate Vite project"
Create a file at assets/vite.config.js
with the following contents:
import { defineConfig } from "vite";
export default defineConfig(({ command }) => {
const isDev = command !== "build";
if (isDev) {
// Terminate the watcher when Phoenix quits
process.stdin.on("close", () => {
process.exit(0);
});
process.stdin.resume();
}
return {
publicDir: "static",
build: {
target: "esnext", // build for recent browsers
outDir: "../priv/static", // emit assets to priv/static
emptyOutDir: true,
sourcemap: isDev, // enable source map in dev build
manifest: false, // do not generate manifest.json
rollupOptions: {
input: {
main: "./src/main.ts",
},
output: {
entryFileNames: "assets/[name].js", // remove hash
chunkFileNames: "assets/[name].js",
assetFileNames: "assets/[name][extname]",
},
},
},
css: {
preprocessorOptions: {
scss: {
api: "modern-compiler",
},
},
},
};
});
Install dependencies:
cd assets
pnpm add -D sass-embedded
pnpm add phoenix_html
You may want to delete all the assets created by default in the assets/src
directory, such as the default JS application (counter written in vanilla JS) or typescript.svg
(the TypeScript logo).