iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🌀

Pitfalls of Configuring Remix on Cloudflare Workers

に公開

During this New Year's holiday, I was playing around with Remix on Cloudflare Workers.
None of these would have been issues if I had read the official documentation thoroughly, but in my case, I struggled a bit, so I'm writing this down as an article. Here are the four things I got stuck on:

  1. Handling environment variables on both the server and frontend sides
  2. Using Tailwind CSS
  3. Deploying using GitHub Actions
  4. Not being able to use certain Node.js libraries

Development Environment Setup

Setup was very easy.
The development environment for Remix on Cloudflare Workers can be easily set up with the following command:

$ npx create-remix@latest

When you run the command above, you will be asked where you want to deploy, so select Cloudflare Workers.

? Where do you want to deploy? Choose Remix if you're unsure, it's easy to change deployment targets. 
  Express Server 
  Architect (AWS Lambda) 
  Fly.io 
  Netlify 
  Vercel 
  Cloudflare Pages 
❯ Cloudflare Workers 
(Move up and down to reveal more choices)

Also, you need to install Wrangler separately as a tool for building functions and deploying to Cloudflare. You can install it using npm.

$ npm install -g @cloudflare/wrangler

1. Handling environment variables on the server and frontend

In local development, you can use .env files as follows.
However, instead of extracting environment variables from process.env like process.env.API_KEY, constants are defined globally as they are on the server side.

Therefore, when using TypeScript, it was necessary to define the types for the environment variables used in global.d.ts or similar.

global.d.ts
declare const SUPABASE_ANON_KEY: string

When using environment variables on the Cloudflare Workers side, you need to define them using Wrangler.

$ wrangler secret put SUPABASE_ANON_KEY

However, since these environment variables cannot be used on the frontend side, it was necessary to pass them to the frontend using a loader as shown below. This is a bit inconvenient.

https://remix.run/docs/en/v1/guides/envvars

root.tsx
export function loader() {
  return {
    ENV: {
      SUPABASE_URL: SUPABASE_URL,
      SUPABASE_ANON_KEY: SUPABASE_ANON_KEY,
    }
  }
}

export function Root() {
  const data = useLoaderData();
  return (
    <html>
      <head>
        <Meta />
        <Links />
      </head>
      <body>
        <Outlet />
        <script
          dangerouslySetInnerHTML={{
            __html: `window.ENV = ${JSON.stringify(
              data.ENV
            )}`
          }}
        />
        <Scripts />
      </body>
    </html>
  );
}

By doing this, you can retrieve environment variables from the frontend side in the form of window.ENV.SUPABASE_URL.
Therefore, when using TypeScript, define the environment variable types on the window side for the frontend as well, as follows:

global.dts
interface Window {
  ENV: {
    SUPABASE_ANON_KEY: string
  }
}

2. Using Tailwind CSS

When npx create-remix@latest is executed, a package.json is automatically generated. Modify this package.json slightly so that tailwind.css is built when running npm run start, outputting the result to ./app/styles/tailwind.css.

  "scripts": {
-    "build": "remix build",
+    "build": "npm run build:css && npm run build:remix",
+    "build:remix": "remix build",
+    "build:css": "tailwindcss --output ./app/styles/tailwind.css --minify",
    "dev": "remix watch",
    "postinstall": "remix setup cloudflare-workers",
    "build:worker": "esbuild --define:process.env.NODE_ENV='\"production\"' --minify --bundle --sourcemap --outdir=dist ./worker",
    "dev:worker": "esbuild --define:process.env.NODE_ENV='\"development\"' --bundle --sourcemap --outdir=dist ./worker",
-    "start": "miniflare --build-command \"npm run dev:worker\" --watch",
+    "start": "npm-run-all -p start:*",
+    "start:css": "tailwindcss --output ./app/styles/tailwind.css --watch",
+    "start:miniflare": "miniflare --build-command \"npm run dev:worker\" --watch",
    "deploy": "npm run build && wrangler publish"
  },

Import the outputted CSS in root.tsx as follows.

root.tsx
import tailwindStyles from "~/styles/tailwind.css";

export const links: LinksFunction = () => {
  return [
    { rel: "stylesheet", href: tailwindStyles },
  ];
};

3. Automating deployment using GitHub Actions

Install Wrangler globally on CI as shown below, and set CF_EMAIL and CF_API_TOKEN as GitHub environment variables.

steps:
  - name: checkout
    uses: actions/checkout@v1
  - name: setup Node
    uses: actions/setup-node@v1
    with:
      node-version: 16.x
      registry-url: 'https://registry.npmjs.org'
  - name: install
    run: npm ci
  - name: install wrangler
    run: npm i @cloudflare/wrangler -g
  - name: set env
    run: |
      echo "CF_EMAIL=${CF_EMAIL}" >> $GITHUB_ENV
      echo "CF_API_TOKEN=${CF_API_TOKEN}" >> $GITHUB_ENV
    env:
      CF_EMAIL: ${{secrets.CLOUDFLARE_EMAIL}}
      CF_API_TOKEN: ${{secrets.WRANGLER_API_KEY}}
  - name: publish
    run: npm run deploy

CF_EMAIL is the email address used to log in to Cloudflare, and CF_API_TOKEN is the API token obtained from the Cloudflare dashboard.

Issuing an API Token

You can issue a token from the following page.
You can easily generate a token by selecting the "Edit Cloudflare Workers" template.

https://dash.cloudflare.com/profile/api-tokens

4. Some Node.js libraries cannot be used

This was entirely due to my own lack of research, but since Cloudflare Workers is different from Node, standard Node libraries such as fs and net/http cannot be used. Consequently, libraries that depend on those standard libraries also could not be used.

https://workers.cloudflare.com/works

Many packages that require Node dependencies, such as fs or net/http, aren't supported in Workers because Workers isn't Node—it's built on V8.

Conclusion

These three things were the points I got stuck on while working with Remix. Since I'm so used to Next.js, I faced various challenges.
I'll add more to this article if I encounter any other issues with the Remix on Cloudflare Workers configuration.

Discussion