Understanding how to make Cloudflare Pages compatible with Vite, which became stable with Remix 2.7
chimame
Posted on March 1, 2024
Remix 2.7 has been released. From 2.7 onwards, Vite compatibility, which has been unstable until now, has been adopted as the official version.
Prior to 2.7, the Node.js runtime provided something that worked, but not something that worked with Cloudflare Pages. However, at the same time as the release of 2.7, something that works with Cloudfalre Pages was released, so I will summarize the results of my research on what has changed and how it is being handled.
https://github.com/remix-run/remix/blob/main/CHANGELOG.md#v270
Several bugs were fixed after the release of 2.7.0, so we recommend using the bug-fixed version of the migration instead of 2.7.0.
Also, there is an official document for migrating to the Vite version, so I think reading it will help you understand better.
https://remix.run/docs/en/main/future/vite#migrating
Differences in initial package.json
First, let's compare the differences in the initial packages between the conventional version and the Vite version.
Differences in installation commands
Please note that the templates are separate, so the traditional version and the Vite version are different.
npx create-remix@latest --template remix-run/remix/templates/cloudflare-pages
npx create-remix@latest --template remix-run/remix/templates/vite-cloudflare
Difference between npm script and npm packages
The package.json
actually generated from the above command differs as follows.
Of course, Vite etc. are added to the installed packages. You can see that the packages are different, but you can also see that the npm scripts are also different.
- Added npm scripts for
deploy
postinstall
andtypegen
- Add
dev
and changestart
There have been many changes, and I will explain each of the changes.
What are typegen
and postinstall
?
First, I will explain the additional npm scripts typegen
and postinstall
.
postinstall
allows you to define commands that are automatically started after executing the npm install command. Therefore, in the Vite version, the script defined in postinstall
will be executed by executing the command equivalent to npm install. The important content of postinstall
is simply reading the typegen
npm script. So the main body is a typegen
npm script.
The true identity of typegen
I'm hitting a command called wrangler types
which is what typegen
is doing. You can understand what this is doing by reading the Wrangler documentation.
https://developers.cloudflare.com/workers/wrangler/commands/#types
In short, it generates worker-configuration.d.ts
, the type file required for the application, from the wrangler.toml
file used in Cloudflare's development environment and deployment.
Specifically, if you have a wrangler.toml
file like the following
vars = { API_HOST = "example.com" }
kv_namespaces = [
{ id = "MY_KV", binding="MY_KV" }
]
d1_databases = [
{ binding = "DB", database_name = "TestDB", database_id = "test-db-id" }
]
interface Env {
MY_KV: KVNamespace;
API_HOST: "example.com";
DB: D1Database;
}
This worker-configuration.d.ts
type file is very important as it will be used later in Remix. This is because this file corresponds to the previous version, remix.env.d.ts
. The Vite version does not use remix.env.d.ts
, so be sure to generate it as written in the migrate documentation.
Notes on type generation
It's convenient because it automatically generates a type file, but there are some things to keep in mind.
What it is is the way wrangler.toml
is written. In the previous example, there are two ways to write vars
, and I wrote one of them, but the other is written as follows.
# Changed vars = { API_HOST = "example.com" }
[vars]
API_HOST = "example.com"
kv_namespaces = [
{ id = "MY_KV", binding="MY_KV" }
]
d1_databases = [
{ binding = "DB", database_name = "TestDB", database_id = "test-db-id" }
]
This is also a correct description, but if you run typegen
's npm script in this state, worker-configuration.d.ts
like the following will be created.
interface Env {
API_HOST: "example.com";
kv_namespaces: [{"id":"MY_KV","binding":"MY_KV"}];
d1_databases: [{"binding":"DB","database_name":"TestDB","database_id":"test-db-id"}];
}
This is not the type file format that Remix is aiming for, so be careful when writing it.
wrangler.toml
trap in Cloudflare Pages
A very big trap lurks. The README of Cloudflare Pages, which is compatible with the Vite version of Remix, has the following description.
> [!WARNING]
> Cloudflare does _not_ use `wrangler.toml` to configure deployment bindings.
> You **MUST** [configure deployment bindings manually in the Cloudflare dashboard][bindings].
Since it generates the form, wouldn't it also be reflected during deployment? For some reason, wrangler pages deploy
does not reflect the contents of wrangler.toml
. So, I'm telling you to first configure it on the Cloudflare console.
Two ways to launch a development environment
In the Vite version of 2.7, there are two methods. That's the modified dev
and start
npm script. The previous version of dev's npm script is written as follows.
"scripts": {
...
"dev": "remix dev --manual -c \"npm run start\"",
...
"start": "wrangler pages dev --compatibility-date=2023-06-21 ./public",
...
},
So, if you start dev
, it will start up to start
. (The conventional version is also built using remix dev
.) So, what's going on with the Vite version?
"scripts": {
...
"dev": "remix vite:dev",
...
"start": "wrangler pages dev ./build/client",
...
},
dev
and start
are not linked. Works as separate commands. Regarding dev
, some commands that work with Vite are defined. As for start
, the command to start with wrangler
is defined in the built file as before.
So what has changed here is that start
starts the development environment using wrangler
, which is almost the same as the previous version, and dev
is the command to start the development environment with the newly added Vite.
The reality of remix vite:dev
Let's find out what the newly added remix vite:dev
is. The explanation will be long if you follow from the cli command, so I will only write the main points.
Since it is the Vite version, when you look at the Vite configuration vite.config.ts
, you will see the following description for Cloudflare called cloudflareDevProxyVitePlugin
.
import {
vitePlugin as remix,
cloudflareDevProxyVitePlugin as remixCloudflareDevProxy,
} from "@remix-run/dev";
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";
export default defineConfig({
plugins: [
remixCloudflareDevProxy(),
remix(),
tsconfigPaths()
],
});
In this guy's code, we get to the reality of Vite Server, a so-called development environment.
In this configureServer
, we call the wranlger
API called getPlatformProxy
. It is no exaggeration to say that this is the reality of remix vite:dev
.
https://developers.cloudflare.com/workers/wrangler/api/#getplatformproxy
Simply put, wrangler
acts as a proxy, and Vite Server actually runs. So, why does wrangler
need to act as a proxy? What is returned from this getPlatformProxy
is that running Cloudflare's own services (such as D1, R2, KV, etc.) on the Vite Server side returns the API. That is a major feature. I wrote a program to access D1 in the Remix code in the development environment, and it works on Vite Server because Remix on Vite Server runs the Cloudflare environment API that was proxied with getPlatformProxy
.
Notes on remix vite:dev
If you have read this far and have the following questions, you are in good hands.
I want to check the operation in a workerd environment.
that's right. It's still the same as wrangler
providing Cloudflare's API and running on Vite Server, that is, Node server. Therefore, since it is not a wranglerd
environment, code that depends on Node's API will run without doing anything.
I think that's one of the reasons why the start
npm script remains in order to finally check the operation. On the start
side, we will use wrangler
to raise the development environment, so we will check the operation in the workerd environment.
“Then why don’t we just say start
?”
I certainly think so. However, there are other problems with start
, and you need to be careful if you use it regularly.
https://github.com/remix-run/remix/issues/7466
Since the Vite version has just been released, there are some issues, but efforts to improve this have already begun, so I think it would be best to wait patiently, or since it is OSS, it would be better to cooperate.
Build process up to deployment in Vite version
The method of starting the development environment has certainly changed with Vite, but the main focus is building. Since it is a Vite version, of course the build will be done with Vite. By the way, the conventional version is built using esbuild.
The reality of remix vite:build
Previously, Remix generated various options for building with esbuild and built it, but I will write about how it is done in the Vite version. This can also be seen by reading from vite.config.ts
in the same way as remix vite:dev
.
import {
vitePlugin as remix,
cloudflareDevProxyVitePlugin as remixCloudflareDevProxy,
} from "@remix-run/dev";
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";
export default defineConfig({
plugins: [
remixCloudflareDevProxy(),
remix(),
tsconfigPaths()
],
});
Here we set something called vitePlugin
as a Vite plugin. This is the main body that contains the settings for building.
This will return multiple Vite plugin configurations for building Remixes. Among them, the following four are the ones you should read if you want to know about build-related processes.
-
name: "remix"
: which returns the Vite build config settings -
name: "remix-virtual-modules"
: Regenerates server-side code to build only Remix server-side code. -
name: "remix-dot-server"
: Validates Remix's.server
file from being mixed into client code. -
name: "remix-dot-client"
: Validates Remix's.client
file in server code.
So, if you want to customize the options for building with Vite, you can also change the return value of name: "remix"
that is returned at the beginning of the array.
If you have been confused about not being able to change the build settings of esbuild until now, please try changing to the Vite version, as you can change the build as you like.
This will build it with Vite and generate client code and server code in build/client/
and build/server/
.
By the way, in order to build for the server, I am doing something quite clumsy to build the files in app/routes
as one file.
As you can see, the build method has changed in the Vite version, not only for Cloudflare.
Build for Cloudflare Pages
Just having the results built with Vite will not work with Cloudflare Pages. If you want to perform server-side processing, you will need a function called Cloudflare Pages Functions that links Cloudflare Pages and Cloudflare Workers.
In the previous version, functions/[[path]].js, which is Cloudflare Pages Functions, was generated by building with Remix. The Vite version hasn't gotten this far yet.
However, the Vite version provides a file called functions/[[path]].ts
from the beginning.
import { createPagesFunctionHandler } from "@remix-run/cloudflare-pages";
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore - the server build file is generated by `remix vite:build`
// eslint-disable-next-line import/no-unresolved
import * as build from "../build/server";
export const onRequest = createPagesFunctionHandler({ build });
In the previous version, it was used as a place to place the JavaScript result of the build, but in the Vite version, TypeScript has been provided from the beginning, and build/server/index.js
is loaded in it. wrangler (pages)
recognizes a directory called functions/
as Cloudflare Pages Functions, but it supports not only JavaScript but also TypeScript.
https://developers.cloudflare.com/pages/functions/typescript/
So, by doing this, we changed the method to generate Cloudflare Pages Functions that include the built JavaScript of Remix's server-side processing when running wrangler pages dev
and wrangler pages deploy
.
Note that after all, you need to remix vite:build
before start(wranlger pages dev)
will work.
As you can see, Cloudflare Pages compatible with the Vite version of Remix was made possible not only by Remix, but also by Wrangler and Vite.
Although there are some issues, the development experience with Remix has been further improved by moving to Vite, so please give it a try.
Posted on March 1, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.