<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: chimame</title>
    <description>The latest articles on DEV Community by chimame (@chimame).</description>
    <link>https://dev.to/chimame</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F871397%2Fa732998f-67df-4a5d-8d15-5eb18d07e113.png</url>
      <title>DEV Community: chimame</title>
      <link>https://dev.to/chimame</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chimame"/>
    <language>en</language>
    <item>
      <title>Cooperation between Cloudflare Workers has become amazing thanks to RPC support</title>
      <dc:creator>chimame</dc:creator>
      <pubDate>Tue, 09 Apr 2024 16:43:35 +0000</pubDate>
      <link>https://dev.to/chimame/cooperation-between-cloudflare-workers-has-become-amazing-thanks-to-rpc-support-4co9</link>
      <guid>https://dev.to/chimame/cooperation-between-cloudflare-workers-has-become-amazing-thanks-to-rpc-support-4co9</guid>
      <description>&lt;p&gt;On April 5, 2024, Japan time, Cloudflare announced communication between Cloudflare Workers using RPC.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz0ijrt5veh2exeqtcnyq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz0ijrt5veh2exeqtcnyq.png" alt="We've added JavaScript-native RPC to Cloudflare Workers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.cloudflare.com/javascript-native-rpc" rel="noopener noreferrer"&gt;https://blog.cloudflare.com/javascript-native-rpc&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I think it's no exaggeration to say that this has solved several issues and at the same time raised the convenience of building applications on Cloudflare not by one level, but by more than two levels.&lt;br&gt;
This RPC support has made Service Bindings even more user-friendly, so I would like to introduce it.&lt;/p&gt;

&lt;p&gt;The completed code is here, so if you don't have time, please refer to it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/chimame/connect-remix-and-prisma-d1-using-rpc-on-cloudflare-pages" rel="noopener noreferrer"&gt;https://github.com/chimame/connect-remix-and-prisma-d1-using-rpc-on-cloudflare-pages&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Bundling Remix and Prisma will exceed 1MB in size. Therefore, deployment will not complete successfully with a free Cloudflare account. I will explain this on the premise of solving the problem.&lt;br&gt;
Of course, the main topic is the content of Service Bindings using RPC announced by Cloudflare.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/chimame/remix-prisma-d1-on-cloudflare-pages" rel="noopener noreferrer"&gt;https://github.com/chimame/remix-prisma-d1-on-cloudflare-pages&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Service Bindings
&lt;/h2&gt;

&lt;p&gt;Service Bindings allow one Cloudflare Worker to call another Cloudflare Worker.&lt;/p&gt;

&lt;p&gt;The point is that you don't have all the workers in one place, you divide them up and place them so that you can call workers from one worker to another. There are also some benefits to partitioning.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cloudflare Workers file size can be kept small&lt;/li&gt;
&lt;li&gt;Cache each Cloudflare Workers process&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And so on. Of course, there are benefits to keeping it small, but if you divide it too much, there are also disadvantages similar to microservices, so be careful about that.&lt;br&gt;
However, Cloudflare Workers also has size limitations (depending on your subscription plan). If it were free, there would be a limit of 1MB in post-build (compressed) size. Serivce Bindings are also a very useful feature to avoid size constraints.&lt;/p&gt;

&lt;p&gt;However, until now, there was a problem of what to do with the interface between the two workers if they were simply split using Serivce Bindings. This problem has been solved by this RPC, so I will explain how to use it and divide it into parts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a monorepo with 2 Workers
&lt;/h2&gt;

&lt;p&gt;Currently, the size of Wasm in Prisma is a little large, so if you bundle Remix and Prisma, it will exceed 1MB. So, unfortunately, those who wanted to run the free version had to use other methods.&lt;br&gt;
However, it has become possible to smartly avoid this using the RPC that was announced this time, so I will write about it.&lt;/p&gt;

&lt;p&gt;This time, I will write an outline of the composition of the completed form below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwjhi6p9wr10fv51wy1by.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwjhi6p9wr10fv51wy1by.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Split into two Workers as above.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Workers specialized in DB access using Prisma&lt;/li&gt;
&lt;li&gt;Workers who render with received data using Remix&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the case of Remix, it uses Cloudflare Pages, so it is called Cloudflare Pages Functions, but in reality it is Cloudflare Workers, so there is little difference. So, to avoid the size limit, build the application by dividing it into two workers as shown above.&lt;/p&gt;

&lt;p&gt;Since we will be creating two Workers, we will create the project. &lt;code&gt;yarn&lt;/code&gt; I will describe it with a monorepo configuration using, but &lt;code&gt;pnpm&lt;/code&gt; you can create it with whatever you like.&lt;/p&gt;

&lt;p&gt;We will arrange it like this.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

├── README.md
├── package.json
├── yarn.lock
└── pakcages/
    ├── prisma(workers)
    └── remix(workers)


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Initialize Remix
&lt;/h3&gt;

&lt;p&gt;Place the Remix as shown below without thinking about anything in particular.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; packages/remix
&lt;span class="nb"&gt;cd &lt;/span&gt;packages/remix
npx create-remix@latest &lt;span class="nt"&gt;--template&lt;/span&gt; remix-run/remix/templates/cloudflare


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Initial setup of Prisma
&lt;/h3&gt;

&lt;p&gt;Last time I put it in the same package.json as Remix, but this time I'll separate it. There is no problem if you configure it from the project root using the following command.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; packages/prisma
&lt;span class="c"&gt;# Create packages/prisma/package.json with only `name` written&lt;/span&gt;
yarn workspace &amp;lt;prisma package name&amp;gt; add &lt;span class="nt"&gt;-D&lt;/span&gt; prisma
yarn workspace &amp;lt;prisma package name&amp;gt; add @prisma/client @prisma/adapter-d1
yarn workspace &amp;lt;prisma package name&amp;gt; run prisma init &lt;span class="nt"&gt;--datasource-provider&lt;/span&gt; sqlite


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;schema.prisma&lt;/code&gt; Add the following description to the last created file to complete it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

// scheme.prisma
generator client {
 provider = "prisma-client-js"
 previewFeatures = ["driverAdapters"]  // &amp;lt;-- ADD
}

datasource db {
 provider = "sqlite"
 url      = env("DATABASE_URL")
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The initial settings for Workers on the Prisma side are now complete.&lt;/p&gt;

&lt;h2&gt;
  
  
  Database migration
&lt;/h2&gt;

&lt;p&gt;Prisma's D1 support is still in Preview stage. Therefore, migration to D1 is not supported. The Prisma introductory article introduces the procedure for migrating from standard output to D1, but it is not suitable for actual operation. Therefore, if you want to use it, it would be a good idea to move Prisma's migration DDL to the D1 migration file as supported in the commit below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/chimame/connect-remix-and-prisma-d1-using-rpc-on-cloudflare-pages/commit/4718ddbeda21db2e5496dd7558d736bdd1a974f0" rel="noopener noreferrer"&gt;https://github.com/chimame/connect-remix-and-prisma-d1-using-rpc-on-cloudflare-pages/commit/4718ddbeda21db2e5496dd7558d736bdd1a974f0&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cp"&gt;

#!/usr/bin/env zx
&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="s2"&gt;`mkdir -p ./migrations`&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;packages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prisma/migrations/*/migration.sql&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;packages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;migrationName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;packages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prisma/migrations/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;existsSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`migrations/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;migrationName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.sql`&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="s2"&gt;`cp &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;packages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s2"&gt; migrations/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;migrationName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.sql`&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="s2"&gt;`yarn run wrangler d1 migrations apply prisma-rpc-db --local`&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Process creation for Prisma Workers
&lt;/h2&gt;

&lt;p&gt;First, let's write the process to access the Datebase.&lt;/p&gt;
&lt;h3&gt;
  
  
  Initial settings for Workers
&lt;/h3&gt;

&lt;p&gt;The Prisma side package only includes Prisma, so first we will add the settings for Workers to run.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

yarn workspace &amp;lt;prisma package name&amp;gt; add &lt;span class="nt"&gt;-D&lt;/span&gt; wrangler @cloudflare/workers-types
yarn workspace &amp;lt;prisma package name&amp;gt; run wrangler create D1 &amp;lt;D1 database name&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;wrangler.toml&lt;/code&gt; I will describe the settings of the D1 I created . Below is an example.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;

&lt;span class="c"&gt;# packages/prisma/wrangler.toml&lt;/span&gt;
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"prisma-d1-rpc-sample"&lt;/span&gt;
&lt;span class="py"&gt;main&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"src/index.ts"&lt;/span&gt;
&lt;span class="py"&gt;compatibility_date&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"2022-04-05"&lt;/span&gt;
&lt;span class="py"&gt;compatibility_flags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"nodejs_compat"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nn"&gt;[[d1_databases]]&lt;/span&gt;
&lt;span class="py"&gt;binding&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"DB"&lt;/span&gt; &lt;span class="c"&gt;# i.e. available in your Worker on env.DB&lt;/span&gt;
&lt;span class="py"&gt;database_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"prisma-rpc-db"&lt;/span&gt;
&lt;span class="py"&gt;database_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"__YOUR_D1_DATABASE_ID__"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Creating Workers using Prisma
&lt;/h3&gt;

&lt;p&gt;Next is the actual code for the Workers on the Prisma side, and I will write the code like this.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// pakcages/prisma/database/client.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PrismaClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@prisma/client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PrismaD1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@prisma/adapter-d1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;D1Database&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;adapter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PrismaD1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PrismaClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;adapter&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// packages/prisma/src/index.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;WorkerEntrypoint&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cloudflare:workers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./database/client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Env&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;D1Database&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserService&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;WorkerEntrypoint&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Env&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;fetchUsers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findMany&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// An error occurs when deploying this worker without register event handlers as default export.&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Healthy!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;client.ts&lt;/code&gt; I don't think there is any need to explain anything, but it simply defines a function to connect to D1 using Prisma. &lt;code&gt;src/index.ts&lt;/code&gt; The side is the code of the Workers main body. The target of Service Bindings is exporting UserService. Although it is defined using named export, there is no problem with default export. UserServicehas two functions and has defined two functions: one that returns user data fetchUsersand one that creates a user . createUserThis function uses Prisma to access D1 and perform &lt;code&gt;SELECT&lt;/code&gt; and &lt;code&gt;INSERT&lt;/code&gt; processing.&lt;br&gt;
I don't think it's particularly difficult if you just look at it. The important thing here is &lt;code&gt;WorkerEntrypoint&amp;lt;Env&amp;gt;&lt;/code&gt;. In particular Env, it makes D1 settings &lt;code&gt;this.env.DBaccessible&lt;/code&gt; by importing them, and serves as the basis for defining the RPC-compatible Service Bindings. This allows processing of D1 and Prisma to be confined to the Workers here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Remix (Pages Functions)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Configuring Service Bindings
&lt;/h3&gt;

&lt;p&gt;Remix has most of the settings in the initial setup, but this time we will be using Service Bindings using RPC, so we will need the following &lt;code&gt;wrangler.toml&lt;/code&gt; settings &lt;code&gt;Env&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;

&lt;span class="c"&gt;# packages/remix/wrangler.toml&lt;/span&gt;
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"remix-rpc-sample"&lt;/span&gt;

&lt;span class="nn"&gt;[[services]]&lt;/span&gt;
&lt;span class="py"&gt;binding&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"USER_SERVICE"&lt;/span&gt;
&lt;span class="py"&gt;service&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"prisma-d1-rpc-sample"&lt;/span&gt;
&lt;span class="py"&gt;entrypoint&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"UserService"&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// packages/remix/load-context.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PlatformProxy&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wrangler&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;UserService&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@rpc-sample/prisma/src&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Env&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;USER_SERVICE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Service&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserService&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;---ADD&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Cloudflare&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Omit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;PlatformProxy&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Env&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dispose&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;declare&lt;/span&gt; &lt;span class="kr"&gt;module&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/cloudflare&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;AppLoadContext&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;cloudflare&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Cloudflare&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;First, settings are written in &lt;code&gt;wrangler.toml&lt;/code&gt; so that Prisma's Workers can be referenced from the Remix side. By writing this, you will be able to use Service Bindigs settings locally. entrypointThis setting is specified here , but this setting is required when writing Workers to be bound by named export. Conversely, this is not necessary for default export. The content of&lt;br&gt;
&lt;code&gt;load-context.ts&lt;/code&gt; what you write &lt;code&gt;Env&lt;/code&gt; is &lt;code&gt;wrangler.toml&lt;/code&gt; defined as a type.&lt;br&gt;
By having these two things in place, the true power of Service Bindings using RPC, which will be described later, will be demonstrated.&lt;/p&gt;

&lt;p&gt;There is a point to note, although &lt;code&gt;wrangler types&lt;/code&gt; a Remix npm script is defined, it does not output the type shown &lt;code&gt;wrangler types&lt;/code&gt; above even if you use it &lt;code&gt;Service&amp;lt;UserService&amp;gt;&lt;/code&gt; . I don't think it supports RPC yet, so please correct it manually.&lt;/p&gt;

&lt;h3&gt;
  
  
  Load DB data via Service Bindings
&lt;/h3&gt;

&lt;p&gt;In Remix, &lt;code&gt;loader&lt;/code&gt; data is loaded using , but the program that loads data using the configured Service Bindings is as follows.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// packages/remix/app/routes/users/handlers/loader.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LoaderFunctionArgs&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/cloudflare&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;LoaderFunctionArgs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;using&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cloudflare&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;USER_SERVICE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchUsers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The actual data loading process is on the Workers side of Prisma, so Remix just calls it from the connection settings. But this is TypeScript. usersWhat happens to this variable?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvnny1z2427toksve4srx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvnny1z2427toksve4srx.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The type is defined like this. This is the greatness of Service Bindings that support RPC. Since type information is linked in this way, you can greatly benefit from TypeScript. This &lt;code&gt;tRPC&lt;/code&gt; means that you can implement pretty much the same thing within Cloudflare as you did a while ago .&lt;/p&gt;

&lt;p&gt;&lt;code&gt;useLoaderData&lt;/code&gt; Since we have a type , all we have to do is get the data from this as usual and render it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// packages/remix/app/routes/users/route.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Form&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useLoaderData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./handlers&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useLoaderData&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;loader&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Form&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="nx"&gt;htmlFor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;br&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="nx"&gt;htmlFor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Email&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/label&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;required&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Form&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ul&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/li&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;))}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ul&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Launching the application
&lt;/h3&gt;

&lt;p&gt;Service Bindings using this RPC could not be started using Vite ( &lt;code&gt;getPlatformProxy&lt;/code&gt; ). It seems that it is not supported yet. Therefore, we need to run it with &lt;code&gt;wrangler pages dev&lt;/code&gt;, which is the actual &lt;code&gt;start&lt;/code&gt; script, which is another startup command.&lt;/p&gt;

&lt;p&gt;Prisma's Workers will also start, so concurrentlystart them at the same time.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"concurrently &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;yarn run dev:prisma&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;yarn run dev:remix:build &amp;amp;&amp;amp; yarn run dev:remix:start&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev:prisma"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"yarn workspace @rpc-sample/prisma dev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev:remix:build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"yarn workspace @rpc-sample/remix build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev:remix:start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"yarn workspace @rpc-sample/remix start"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now, &lt;code&gt;/users&lt;/code&gt; when you access the Remix screen and access the path, you should see a screen displaying user registration and the registered user.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0te5k3af8ogbq4a01ctv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0te5k3af8ogbq4a01ctv.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The RPC announced this time makes it possible for Remix and Prisma to work together so that they can share type information while separating each worker. I tried it with a free version account and have confirmed that it can be successfully deployed and works.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;using&lt;/code&gt; What?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;loader&lt;/code&gt; During the Remix process &lt;code&gt;using&lt;/code&gt;, you will notice that it is smooth. This appeared in TypeScript 5.2, but this is a specification in Stage 3 of ECMAScript.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tc39/proposal-explicit-resource-management" rel="noopener noreferrer"&gt;https://github.com/tc39/proposal-explicit-resource-management&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you write very roughly, it will free up resources in a good way. (Seriously, I'm writing this in a rough way, so please try to understand it yourself) So why are you using it this time? That's explained in detail in this document.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.cloudflare.com/workers/runtime-apis/rpc/lifecycle/" rel="noopener noreferrer"&gt;https://developers.cloudflare.com/workers/runtime-apis/rpc/lifecycle/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's too long to read it all, so I'll summarize it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;using&lt;/code&gt; is a Stage 3 specification, but it will also be incorporated into V8 soon.&lt;/li&gt;
&lt;li&gt;The return value of Cloudflare Workers' RPC is held in memory on the server side (Prisma side Workers in this article).&lt;/li&gt;
&lt;li&gt;To explicitly release memory on the server side, &lt;code&gt;Symbol.dispose&lt;/code&gt; call the so-called disposer from the client side (Remix side in this article) and instruct the server side to release it.&lt;/li&gt;
&lt;li&gt;If you want to keep the variable on the client side, &lt;code&gt;dup&lt;/code&gt; copy it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it. That's right. The value returned from this RPC is not held in the caller's memory space, but on the server side. (The person who implemented it is amazing) is done &lt;code&gt;using&lt;/code&gt; when freeing memory. Therefore, this specification is also used &lt;code&gt;Symbol.dispose&lt;/code&gt; to release memory on the server side.&lt;br&gt;
In other words, Service Bindings are not exchanging data using a protocol like http, but rather the Workers connected using Service Bindings are running on some other host. It may be close to something like that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finally
&lt;/h2&gt;

&lt;p&gt;Announcing RPC greatly improves the usability of Cloudflare Workers' Serivce Bindings. It is far beyond imagination that so much can be implemented using just the smart writing style of the class syntax. It should now be much easier to implement the front end and back end with just Cloudflare Workers.&lt;br&gt;
Please try using it when you come up with a design that requires collaboration between Cloudflare Workers.&lt;/p&gt;

</description>
      <category>remix</category>
      <category>cloudflare</category>
      <category>prisma</category>
      <category>rpc</category>
    </item>
    <item>
      <title>Understanding how to make Cloudflare Pages compatible with Vite, which became stable with Remix 2.7</title>
      <dc:creator>chimame</dc:creator>
      <pubDate>Fri, 01 Mar 2024 02:33:35 +0000</pubDate>
      <link>https://dev.to/chimame/understanding-how-to-make-cloudflare-pages-compatible-with-vite-which-became-stable-with-remix-27-15h4</link>
      <guid>https://dev.to/chimame/understanding-how-to-make-cloudflare-pages-compatible-with-vite-which-became-stable-with-remix-27-15h4</guid>
      <description>&lt;p&gt;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.&lt;br&gt;
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.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/remix-run/remix/blob/main/CHANGELOG.md#v270"&gt;https://github.com/remix-run/remix/blob/main/CHANGELOG.md#v270&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;br&gt;
Also, there is an official document for migrating to the Vite version, so I think reading it will help you understand better.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://remix.run/docs/en/main/future/vite#migrating"&gt;https://remix.run/docs/en/main/future/vite#migrating&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Differences in initial &lt;code&gt;package.json&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;First, let's compare the differences in the initial packages between the conventional version and the Vite version.&lt;/p&gt;
&lt;h3&gt;
  
  
  Differences in installation commands
&lt;/h3&gt;

&lt;p&gt;Please note that the templates are separate, so the traditional version and the Vite version are different.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-remix@latest &lt;span class="nt"&gt;--template&lt;/span&gt; remix-run/remix/templates/cloudflare-pages
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-remix@latest &lt;span class="nt"&gt;--template&lt;/span&gt; remix-run/remix/templates/vite-cloudflare
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Difference between npm script and npm packages
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;package.json&lt;/code&gt; actually generated from the above command differs as follows.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F54hqltbdmrhoqsyurw6z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F54hqltbdmrhoqsyurw6z.png" alt="Difference between npm script and npm packages" width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Added npm scripts for &lt;code&gt;deploy&lt;/code&gt; &lt;code&gt;postinstall&lt;/code&gt; and &lt;code&gt;typegen&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;dev&lt;/code&gt; and change &lt;code&gt;start&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There have been many changes, and I will explain each of the changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are &lt;code&gt;typegen&lt;/code&gt; and &lt;code&gt;postinstall&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;First, I will explain the additional npm scripts &lt;code&gt;typegen&lt;/code&gt; and &lt;code&gt;postinstall&lt;/code&gt;.&lt;br&gt;
&lt;code&gt;postinstall&lt;/code&gt; allows you to define commands that are automatically started after executing the npm install command. Therefore, in the Vite version, the script defined in &lt;code&gt;postinstall&lt;/code&gt; will be executed by executing the command equivalent to npm install. The important content of &lt;code&gt;postinstall&lt;/code&gt; is simply reading the &lt;code&gt;typegen&lt;/code&gt; npm script. So the main body is a &lt;code&gt;typegen&lt;/code&gt; npm script.&lt;/p&gt;
&lt;h3&gt;
  
  
  The true identity of &lt;code&gt;typegen&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;I'm hitting a command called &lt;code&gt;wrangler types&lt;/code&gt; which is what &lt;code&gt;typegen&lt;/code&gt; is doing. You can understand what this is doing by reading the Wrangler documentation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.cloudflare.com/workers/wrangler/commands/#types"&gt;https://developers.cloudflare.com/workers/wrangler/commands/#types&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In short, it generates &lt;code&gt;worker-configuration.d.ts&lt;/code&gt;, the type file required for the application, from the &lt;code&gt;wrangler.toml&lt;/code&gt; file used in Cloudflare's development environment and deployment.&lt;/p&gt;

&lt;p&gt;Specifically, if you have a &lt;code&gt;wrangler.toml&lt;/code&gt; file like the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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" }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Env&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;MY_KV&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;KVNamespace&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;API_HOST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;D1Database&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;worker-configuration.d.ts&lt;/code&gt; type file is very important as it will be used later in Remix. This is because this file corresponds to the previous version, &lt;code&gt;remix.env.d.ts&lt;/code&gt;. The Vite version does not use &lt;code&gt;remix.env.d.ts&lt;/code&gt;, so be sure to generate it as written in the migrate documentation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Notes on type generation
&lt;/h3&gt;

&lt;p&gt;It's convenient because it automatically generates a type file, but there are some things to keep in mind.&lt;br&gt;
What it is is the way &lt;code&gt;wrangler.toml&lt;/code&gt; is written. In the previous example, there are two ways to write &lt;code&gt;vars&lt;/code&gt;, and I wrote one of them, but the other is written as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# Changed vars = { API_HOST = "example.com" }&lt;/span&gt;
&lt;span class="nn"&gt;[vars]&lt;/span&gt;
&lt;span class="py"&gt;API_HOST&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"example.com"&lt;/span&gt;

&lt;span class="py"&gt;kv_namespaces&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="err"&gt;{&lt;/span&gt; &lt;span class="py"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"MY_KV"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"MY_KV"&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="py"&gt;d1_databases&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="err"&gt;{&lt;/span&gt; &lt;span class="py"&gt;binding&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"DB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;database_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"TestDB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;database_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"test-db-id"&lt;/span&gt; &lt;span class="err"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is also a correct description, but if you run &lt;code&gt;typegen&lt;/code&gt;'s npm script in this state, &lt;code&gt;worker-configuration.d.ts&lt;/code&gt; like the following will be created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Env&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;API_HOST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;kv_namespaces&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;MY_KV&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;binding&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;MY_KV&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}];&lt;/span&gt;
    &lt;span class="nl"&gt;d1_databases&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;binding&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DB&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;database_name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TestDB&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;database_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test-db-id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not the type file format that Remix is aiming for, so be careful when writing it.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;wrangler.toml&lt;/code&gt; trap in Cloudflare Pages
&lt;/h3&gt;

&lt;p&gt;A very big trap lurks. The README of Cloudflare Pages, which is compatible with the Vite version of Remix, has the following description.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!WARNING]  &lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; Cloudflare does _not_ use `wrangler.toml` to configure deployment bindings.&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; You **MUST** [configure deployment bindings manually in the Cloudflare dashboard][bindings].&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since it generates the form, wouldn't it also be reflected during deployment? For some reason, &lt;code&gt;wrangler pages deploy&lt;/code&gt; does not reflect the contents of &lt;code&gt;wrangler.toml&lt;/code&gt;. So, I'm telling you to first configure it on the Cloudflare console.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two ways to launch a development environment
&lt;/h2&gt;

&lt;p&gt;In the Vite version of 2.7, there are two methods. That's the modified &lt;code&gt;dev&lt;/code&gt; and &lt;code&gt;start&lt;/code&gt; npm script. The previous version of dev's npm script is written as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"remix dev --manual -c &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;npm run start&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"wrangler pages dev --compatibility-date=2023-06-21 ./public"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, if you start &lt;code&gt;dev&lt;/code&gt;, it will start up to &lt;code&gt;start&lt;/code&gt;. (The conventional version is also built using &lt;code&gt;remix dev&lt;/code&gt;.) So, what's going on with the Vite version?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"remix vite:dev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"wrangler pages dev ./build/client"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;dev&lt;/code&gt; and &lt;code&gt;start&lt;/code&gt; are not linked. Works as separate commands. Regarding &lt;code&gt;dev&lt;/code&gt;, some commands that work with Vite are defined. As for &lt;code&gt;start&lt;/code&gt;, the command to start with &lt;code&gt;wrangler&lt;/code&gt; is defined in the built file as before.&lt;br&gt;
So what has changed here is that &lt;code&gt;start&lt;/code&gt; starts the development environment using &lt;code&gt;wrangler&lt;/code&gt;, which is almost the same as the previous version, and &lt;code&gt;dev&lt;/code&gt; is the command to start the development environment with the newly added Vite.&lt;/p&gt;
&lt;h3&gt;
  
  
  The reality of &lt;code&gt;remix vite:dev&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Let's find out what the newly added &lt;code&gt;remix vite:dev&lt;/code&gt; is. The explanation will be long if you follow from the cli command, so I will only write the main points.&lt;br&gt;
Since it is the Vite version, when you look at the Vite configuration &lt;code&gt;vite.config.ts&lt;/code&gt;, you will see the following description for Cloudflare called &lt;code&gt;cloudflareDevProxyVitePlugin&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;vitePlugin&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;remix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;cloudflareDevProxyVitePlugin&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;remixCloudflareDevProxy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/dev&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vite&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;tsconfigPaths&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vite-tsconfig-paths&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;remixCloudflareDevProxy&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nf"&gt;remix&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nf"&gt;tsconfigPaths&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this guy's code, we get to the reality of Vite Server, a so-called development environment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/remix-run/remix/blob/df0a668d416014f19313419dc7701ddcbe4ee312/packages/remix-dev/vite/cloudflare-proxy-plugin.ts#L59-L85"&gt;https://github.com/remix-run/remix/blob/df0a668d416014f19313419dc7701ddcbe4ee312/packages/remix-dev/vite/cloudflare-proxy-plugin.ts#L59-L85&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this &lt;code&gt;configureServer&lt;/code&gt;, we call the &lt;code&gt;wranlger&lt;/code&gt; API called &lt;code&gt;getPlatformProxy&lt;/code&gt;. It is no exaggeration to say that this is the reality of &lt;code&gt;remix vite:dev&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.cloudflare.com/workers/wrangler/api/#getplatformproxy"&gt;https://developers.cloudflare.com/workers/wrangler/api/#getplatformproxy&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Simply put, &lt;code&gt;wrangler&lt;/code&gt; acts as a proxy, and Vite Server actually runs. So, why does &lt;code&gt;wrangler&lt;/code&gt; need to act as a proxy? What is returned from this &lt;code&gt;getPlatformProxy&lt;/code&gt; 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 &lt;code&gt;getPlatformProxy&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Notes on &lt;code&gt;remix vite:dev&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;If you have read this far and have the following questions, you are in good hands.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I want to check the operation in a workerd environment.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;that's right. It's still the same as &lt;code&gt;wrangler&lt;/code&gt; providing Cloudflare's API and running on Vite Server, that is, Node server. Therefore, since it is not a &lt;code&gt;wranglerd&lt;/code&gt; environment, code that depends on Node's API will run without doing anything.&lt;br&gt;
I think that's one of the reasons why the &lt;code&gt;start&lt;/code&gt; npm script remains in order to finally check the operation. On the &lt;code&gt;start&lt;/code&gt; side, we will use &lt;code&gt;wrangler&lt;/code&gt; to raise the development environment, so we will check the operation in the workerd environment.&lt;/p&gt;

&lt;p&gt;“Then why don’t we just say &lt;code&gt;start&lt;/code&gt;?”&lt;/p&gt;

&lt;p&gt;I certainly think so. However, there are other problems with &lt;code&gt;start&lt;/code&gt;, and you need to be careful if you use it regularly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/remix-run/remix/issues/7466"&gt;https://github.com/remix-run/remix/issues/7466&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;
&lt;h2&gt;
  
  
  Build process up to deployment in Vite version
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;
&lt;h3&gt;
  
  
  The reality of &lt;code&gt;remix vite:build&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;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 &lt;code&gt;vite.config.ts&lt;/code&gt; in the same way as &lt;code&gt;remix vite:dev&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;vitePlugin&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;remix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;cloudflareDevProxyVitePlugin&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;remixCloudflareDevProxy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/dev&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vite&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;tsconfigPaths&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vite-tsconfig-paths&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;remixCloudflareDevProxy&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nf"&gt;remix&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nf"&gt;tsconfigPaths&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we set something called &lt;code&gt;vitePlugin&lt;/code&gt; as a Vite plugin. This is the main body that contains the settings for building.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/remix-run/remix/blob/df0a668d416014f19313419dc7701ddcbe4ee312/packages/remix-dev/vite/plugin.ts#L530"&gt;https://github.com/remix-run/remix/blob/df0a668d416014f19313419dc7701ddcbe4ee312/packages/remix-dev/vite/plugin.ts#L530&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;name: "remix"&lt;/code&gt;: which returns the Vite build config settings&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;name: "remix-virtual-modules"&lt;/code&gt;: Regenerates server-side code to build only Remix server-side code.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;name: "remix-dot-server"&lt;/code&gt;: Validates Remix's &lt;code&gt;.server&lt;/code&gt; file from being mixed into client code.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;name: "remix-dot-client"&lt;/code&gt;: Validates Remix's &lt;code&gt;.client&lt;/code&gt; file in server code.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, if you want to customize the options for building with Vite, you can also change the return value of &lt;code&gt;name: "remix"&lt;/code&gt; that is returned at the beginning of the array.&lt;br&gt;
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.&lt;/p&gt;

&lt;p&gt;This will build it with Vite and generate client code and server code in &lt;code&gt;build/client/&lt;/code&gt; and &lt;code&gt;build/server/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;By the way, in order to build for the server, I am doing something quite clumsy to build the files in &lt;code&gt;app/routes&lt;/code&gt; as one file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/remix-run/remix/blob/df0a668d416014f19313419dc7701ddcbe4ee312/packages/remix-dev/vite/plugin.ts#L704-L750"&gt;https://github.com/remix-run/remix/blob/df0a668d416014f19313419dc7701ddcbe4ee312/packages/remix-dev/vite/plugin.ts#L704-L750&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, the build method has changed in the Vite version, not only for Cloudflare.&lt;/p&gt;
&lt;h3&gt;
  
  
  Build for Cloudflare Pages
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;However, the Vite version provides a file called &lt;code&gt;functions/[[path]].ts&lt;/code&gt; from the beginning.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createPagesFunctionHandler&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@remix-run/cloudflare-pages&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// eslint-disable-next-line @typescript-eslint/ban-ts-comment&lt;/span&gt;
&lt;span class="c1"&gt;// @ts-ignore - the server build file is generated by `remix vite:build`&lt;/span&gt;
&lt;span class="c1"&gt;// eslint-disable-next-line import/no-unresolved&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;build&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../build/server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createPagesFunctionHandler&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;build&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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 &lt;code&gt;build/server/index.js&lt;/code&gt; is loaded in it. &lt;code&gt;wrangler (pages)&lt;/code&gt; recognizes a directory called &lt;code&gt;functions/&lt;/code&gt; as Cloudflare Pages Functions, but it supports not only JavaScript but also TypeScript.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.cloudflare.com/pages/functions/typescript/"&gt;https://developers.cloudflare.com/pages/functions/typescript/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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 &lt;code&gt;wrangler pages dev&lt;/code&gt; and &lt;code&gt;wrangler pages deploy&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Note that after all, you need to &lt;code&gt;remix vite:build&lt;/code&gt; before &lt;code&gt;start(wranlger pages dev)&lt;/code&gt; will work.&lt;/p&gt;

&lt;p&gt;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.&lt;br&gt;
Although there are some issues, the development experience with Remix has been further improved by moving to Vite, so please give it a try.&lt;/p&gt;

</description>
      <category>react</category>
      <category>remix</category>
      <category>cloudflare</category>
      <category>vite</category>
    </item>
    <item>
      <title>Allow Cloudflare D1 to be used like an O/R mapper with type-safe</title>
      <dc:creator>chimame</dc:creator>
      <pubDate>Sun, 15 Jan 2023 17:27:39 +0000</pubDate>
      <link>https://dev.to/chimame/allow-cloudflare-d1-to-be-used-like-an-or-mapper-with-type-safe-b96</link>
      <guid>https://dev.to/chimame/allow-cloudflare-d1-to-be-used-like-an-or-mapper-with-type-safe-b96</guid>
      <description>&lt;p&gt;Cloudflare D1 (hereafter: D1) was released as an alpha version last year, but it is only an alpha version, so I feel that it does not scratch the itch. It is not only the functionality as a DB, such as transactions, but also the writing style as a program is a bit more complicated. (The main reason for this is that I have actually written SQL.)&lt;/p&gt;

&lt;p&gt;The main topic of this article is to try to deal with the writing style of D1, especially SQL and types.&lt;/p&gt;

&lt;p&gt;Prerequisites&lt;br&gt;
&lt;a href="https://github.com/chimame/workers-remix-d1" rel="noopener noreferrer"&gt;https://github.com/chimame/workers-remix-d1&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The complete program used in this article can be found at &lt;a href="https://github.com/chimame/workers-remix-d1" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;In addition to D1, Cloudflare Pages is also used.&lt;/li&gt;
&lt;li&gt;The program to deploy to Cloudflare is &lt;a href="https://remix.run/" rel="noopener noreferrer"&gt;Remix&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;I will describe D1 and the programs around it, but I will not describe everything in detail.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Summary.
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/koskimas/kysely" rel="noopener noreferrer"&gt;kysely&lt;/a&gt; &lt;a href="https://github.com/RobinBlomberg/kysely-codegen" rel="noopener noreferrer"&gt;kysely-codegen&lt;/a&gt; &lt;a href="//https://%20github.com/aidenwallis/kysely-d1"&gt;kysely-d1&lt;/a&gt; allows access to D1 while using SQL Builder.&lt;/li&gt;
&lt;li&gt;It is even easier to use D1 than the standard &lt;code&gt;DB.prepare(&amp;lt;SQL&amp;gt;).all()&lt;/code&gt; because the type is automatically populated.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  What is Cloudflare D1?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.cloudflare.com/press-releases/2022/cloudflare-announces-d1-first-integrated-database/" rel="noopener noreferrer"&gt;https://www.cloudflare.com/press-releases/2022/cloudflare-announces-d1-first-integrated-database/&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Unlike other databases on the market, Cloudflare D1 will use Cloudflare's global network to optimize a businesses' database by locating it as close as possible to their customers, providing the fastest possible experience to users.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In layman's terms, you can build your DB on the edge (CDN, etc.) and have it quickly accessible from applications running on the edge. Edge computing has the advantage of being close to the client (access source), but when accessing the DB, the program running on the edge will eventually access the DB behind it. In this case, the need for DB access diminishes the advantage of being close to the client. Therefore, it is inevitable that if a program runs on the edge of edge computing, the DB should also be on the edge. D1 is the solution to this problem.&lt;/p&gt;
&lt;h2&gt;
  
  
  Access program to D1
&lt;/h2&gt;
&lt;h3&gt;
  
  
  &lt;a href="https://developers.cloudflare.com/d1/get-started/#write-queries-within-your-worker" rel="noopener noreferrer"&gt;standard&lt;/a&gt; version
&lt;/h3&gt;

&lt;p&gt;The following is a program to access D1.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SELECT * FROM User&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data.results&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// #=&amp;gt; [&lt;/span&gt;
&lt;span class="c1"&gt;// { id: &amp;lt;number&amp;gt;, email: &amp;lt;string&amp;gt;, name: &amp;lt;string | null&amp;gt; }&lt;/span&gt;
&lt;span class="c1"&gt;// { id: &amp;lt;number&amp;gt;, email: &amp;lt;string&amp;gt;, name: &amp;lt;string | null&amp;gt; }&lt;/span&gt;
&lt;span class="c1"&gt;// ] type will be unkown[] | unkown&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What do you think? I guess what I mean is like this&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need to write SQL.&lt;/li&gt;
&lt;li&gt;You need to specify the type in generics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The "need to write SQL" is a bit troublesome when using O/R mappers such as Prisma or TypeORM, for example. But even if you allow it, the trouble with writing code in TypeScript is that the return value (&lt;code&gt;data.results&lt;/code&gt;) does not have a type. In other words, the type cannot be assigned without interpreting the SQL to be executed by &lt;code&gt;prepare&lt;/code&gt;. So, in the above code, you need to define the type of the return value yourself with generics in the &lt;code&gt;all&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SELECT * FROM User&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Currently it's &lt;strong&gt;Alpha version&lt;/strong&gt;, so it could be improved, but I still don't want to write double SQL and type.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/koskimas/kysely" rel="noopener noreferrer"&gt;Kysely&lt;/a&gt; version
&lt;/h3&gt;

&lt;p&gt;There is a TypeScript SQL builder called Kysely.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://koskimas.github.io/kysely/" rel="noopener noreferrer"&gt;https://koskimas.github.io/kysely/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kysely supports PostgreSQL, MySQL, and SQLite as standard. However, Kysely also requires generic type specification for stand-alone use.&lt;/p&gt;

&lt;p&gt;As you can see in &lt;a href="https://github.com/koskimas/kysely#minimal-example" rel="noopener noreferrer"&gt;this example&lt;/a&gt;, you define the database table list to the columns by yourself. I would also like to somehow omit this generics specification.&lt;/p&gt;

&lt;h4&gt;
  
  
  Automatic generation of table and column types
&lt;/h4&gt;

&lt;p&gt;So use &lt;a href="https://github.com/RobinBlomberg/kysely-codegen" rel="noopener noreferrer"&gt;Kysely-codegen&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/RobinBlomberg/kysely-codegen" rel="noopener noreferrer"&gt;https://github.com/RobinBlomberg/kysely-codegen&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As the name suggests, Kysely-codegen generates types for Kysely from the database. For example, for local development using D1, the SQLite database file is located at&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;project root&amp;gt;/.wrangler/state/d1/&amp;lt;database Binding name&amp;gt;.sqlite3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So if you use kysely-codegen to do it like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ DATABASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt; /.wrangler/state/d1/DB.sqlite3 npx kysely-codegen
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;type, which makes it very easy to use Kysely with that type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DB&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kysely-codegen&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Kysely&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SqliteDialect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kysely&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Database&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;better-sqlite3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Kysely&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;dialect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SqliteDialect&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;. /.wrangler/state/d1/DB.sqlite3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Using Kysely with D1
&lt;/h4&gt;

&lt;p&gt;Now that the table and column types have been automatically generated, we need a way to use Kysely in D1. So now we will use &lt;a href="https://github.com/aidenwallis/kysely-d1" rel="noopener noreferrer"&gt;Kysely-D1&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/aidenwallis/kysely-d1" rel="noopener noreferrer"&gt;https://github.com/aidenwallis/kysely-d1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is an adapter that allows Kysely to handle D1. By the way, there are several adapters for Kysely.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/serverless-stack/kysely-data-api" rel="noopener noreferrer"&gt;https://github.com/serverless-stack/kysely-data-api&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/depot/kysely-planetscale" rel="noopener noreferrer"&gt;https://github.com/depot/kysely-planetscale&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kysely-D1 allows Kysely to handle D1, and the code looks like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//const data = await env.DB.prepare('SELECT * FROM User').all&amp;lt;{&lt;/span&gt;
&lt;span class="c1"&gt;// id: number,&lt;/span&gt;
&lt;span class="c1"&gt;// email: string,&lt;/span&gt;
&lt;span class="c1"&gt;// name: string | null&lt;/span&gt;
&lt;span class="c1"&gt;//}&amp;gt;()&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DB&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kysely-codegen&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Kysely&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kysely&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;D1Dialect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kysely-d1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Kysely&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DB&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;dialect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;D1Dialect&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;selectFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;selectAll&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// #=&amp;gt; [&lt;/span&gt;
&lt;span class="c1"&gt;// { id: &amp;lt;number&amp;gt;, email: &amp;lt;string&amp;gt;, name: &amp;lt;string | null&amp;gt; }&lt;/span&gt;
&lt;span class="c1"&gt;// { id: &amp;lt;number&amp;gt;, email: &amp;lt;string&amp;gt;, name: &amp;lt;string | null&amp;gt; }&lt;/span&gt;
&lt;span class="c1"&gt;// ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What do you think? Doesn't this make it look a lot more like an O/R mapper? The type completion is also auto-completed, so I think it's easier to use now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;How was it? Whether you use Kysely or Prisma, my feeling is that you are writing SQL, so it is easier to automatically define SQL results as a type.&lt;/p&gt;

&lt;p&gt;Of course, D1 is still in its alpha version, so there is a possibility that they will fix these points. If you want to play with D1, please refer to this page.&lt;/p&gt;

&lt;p&gt;By the way, I have also made a repository that uses &lt;a href="https://github.com/k0kubun/sqldef" rel="noopener noreferrer"&gt;sqldef&lt;/a&gt; as a migration tool to make migration as easy as possible, so please take a look at it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>discuss</category>
      <category>motivation</category>
    </item>
  </channel>
</rss>
