-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added Remix Accelerate Example App (#6151)
* (feat) Added Remix Accelerate Example App * Added seed command * Updated Readme and added GIF * Updated Readme file and added screenshot * Removed log * Resolved whitespaces * Removed as `any` * Updated the .env.example * Added new GIF
- Loading branch information
Showing
44 changed files
with
1,367 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
DIRECT_DATABASE_URL="__YOUR_DATABASE_CONNECTION_STRING__" | ||
DATABASE_URL="__YOUR_ACCELERATE_CONNECTION_STRING__" | ||
NODE_ENV="development" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
.cache | ||
build | ||
public/build | ||
app/styles | ||
dist/ | ||
node_modules | ||
api/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
{ | ||
"parser": "@typescript-eslint/parser", | ||
"globals": { | ||
"module": true, | ||
"require": true, | ||
"process": true, | ||
"exports": true | ||
}, | ||
"settings": { | ||
"react": { | ||
"version": "detect" | ||
}, | ||
"formComponents": ["Form"], | ||
"linkComponents": [ | ||
{ "name": "Link", "linkAttribute": "to" }, | ||
{ "name": "NavLink", "linkAttribute": "to" } | ||
] | ||
}, | ||
"plugins": [ | ||
"prettier", | ||
"@typescript-eslint", | ||
"jsx-a11y", | ||
"import", | ||
"react", | ||
"react-hooks", | ||
"lodash" | ||
], | ||
"extends": [ | ||
"eslint:recommended", | ||
"prettier", | ||
"plugin:prettier/recommended", | ||
"plugin:@typescript-eslint/recommended", | ||
"plugin:jsx-a11y/recommended", | ||
"plugin:import/recommended", | ||
"plugin:import/typescript", | ||
"plugin:react/jsx-runtime", | ||
"plugin:react/recommended", | ||
"plugin:react-hooks/recommended", | ||
"@remix-run/eslint-config/node" | ||
], | ||
"rules": { | ||
"lodash/import-scope": [2, "method"], | ||
"prettier/prettier": "error", | ||
"import/no-unresolved": "off", | ||
"@typescript-eslint/no-unused-vars": [ | ||
"error", | ||
{ "argsIgnorePattern": "^_", "varsIgnorePattern": "^_" } | ||
], | ||
"jsx-a11y/anchor-is-valid": [ | ||
"error", | ||
{ | ||
"components": ["Link", "NavLink"], | ||
"specialLink": ["to"] | ||
} | ||
], | ||
"react/boolean-prop-naming": "error", | ||
"react/react-in-jsx-scope": "off", | ||
"react/button-has-type": "error", | ||
"react/jsx-no-target-blank": [ | ||
"error", | ||
{ | ||
"warnOnSpreadAttributes": true, | ||
"links": true, | ||
"forms": true | ||
} | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
node_modules | ||
.cache | ||
.output | ||
build | ||
public/build | ||
api/* | ||
.env | ||
test-results/ | ||
playwright-report/ | ||
.eslintcache | ||
|
||
!.env.example |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
auto-install-peers=false | ||
shamefully-hoist=true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"trailingComma": "all" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
nodejs 20.14.0 |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
# Prisma Accelerate Example: Remix Starter | ||
|
||
This project showcases how to use Prisma ORM with Prisma Accelerate in a Remix application. It [demonstrates](./app/routes/_index.tsx#L10-13) every available [caching strategy in Accelerate](https://www.prisma.io/docs/data-platform/accelerate/concepts#cache-strategies). | ||
|
||
## Prerequisites | ||
|
||
To successfully run the project, you will need the following: | ||
|
||
- The **connection string** of a publicly accessible database. | ||
- Your **Accelerate connection string** (containing your **Accelerate API key**) which you can get by enabling Accelerate in a project in your [Prisma Data Platform](https://pris.ly/pdp) account (learn more in the [docs](https://www.prisma.io/docs/platform/concepts/environments#api-keys)). | ||
|
||
## Getting started | ||
|
||
### 1. Clone the repository | ||
|
||
Clone the repository, navigate into it and install dependencies: | ||
|
||
``` | ||
git clone [email protected]:prisma/prisma-examples.git --depth=1 | ||
cd prisma-examples/accelerate/remix-starter | ||
npm install | ||
``` | ||
|
||
### 2. Configure environment variables | ||
|
||
Copy the `.env.example` env file in the root of the project directory: | ||
|
||
```bash | ||
cp .env.example .env | ||
``` | ||
|
||
Now, open the `.env` file and set the `DIRECT_DATABASE_URL` and `DATABASE_URL` environment variables with the values of your connection string and your Accelerate connection string respectively: | ||
|
||
```bash | ||
# .env | ||
|
||
# Accelerate connection string (used for queries by Prisma Client) | ||
DATABASE_URL="__YOUR_ACCELERATE_CONNECTION_STRING__" | ||
|
||
# Database connection string (used for migrations by Prisma Migrate) | ||
DIRECT_DATABASE_URL="__YOUR_DATABASE_CONNECTION_STRING__" | ||
|
||
``` | ||
|
||
Note that `__YOUR_DATABASE_CONNECTION_STRING__` and `__YOUR_ACCELERATE_CONNECTION_STRING__` are placeholder values that you need to replace with the values of your database and Accelerate connection strings. Notice that the Accelerate connection string has the following structure: `prisma://accelerate.prisma-data.net/?api_key=__YOUR_ACCELERATE_API_KEY__`. | ||
|
||
### 3. Run a migration to create the `Quotes` table and seed the database | ||
|
||
The Prisma schema file contains a single `Quotes` model. You can map this model to the database and create the corresponding `Quotes` table using the following command: | ||
|
||
``` | ||
npx prisma migrate dev --name init | ||
``` | ||
|
||
You now have an empty `Quotes` table in your database. Next, run the [seed script](./prisma/seed.ts) to create some sample records in the table: | ||
|
||
``` | ||
npx prisma db seed | ||
``` | ||
|
||
### 4. Generate Prisma Client for Accelerate | ||
|
||
When using Accelerate, Prisma Client doesn't need a query engine. That's why you should generate it as follows: | ||
|
||
``` | ||
npx prisma generate --no-engine | ||
``` | ||
|
||
### 5. Start the app | ||
|
||
You can run the app with the following command: | ||
|
||
``` | ||
npm run dev | ||
``` | ||
|
||
The application will start on PORT 5173 and you should be able to see the performance and other stats (e.g. cache/hit) for the different Accelerate cache strategies at the bottom of the UI: | ||
|
||
 | ||
|
||
This application queries the most recent Quote with all the different cache strategies available in Accelerate. | ||
|
||
Optionally, to add your own quote and see the caching strategies in action, you can add a new quote through Prisma Studio by running the following command: | ||
|
||
``` | ||
npx prisma studio | ||
``` | ||
|
||
Once the Prisma Studio is running, you can add a new quote by clicking on the `Quotes` table and then the `Add Record` button as shown in the screenshot below. | ||
|
||
 | ||
|
||
After adding a new record, you can refresh the Remix application to see the new quote and the caching strategies in action. | ||
|
||
## Resources | ||
|
||
- [Accelerate Speed Test](https://accelerate-speed-test.vercel.app/) | ||
- [Accelerate documentation](https://www.prisma.io/docs/accelerate) | ||
- [Prisma Discord](https://pris.ly/discord) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
/* eslint-disable react/prop-types */ | ||
import { QuoteWrapper } from "./QuoteWrapper"; | ||
import { QuoteCacheType, QuoteResult } from "./../../lib/types"; | ||
import pkg from "openflights-cached"; | ||
const { findIATA } = pkg; | ||
|
||
export const Quote: React.FC<{ | ||
title: string; | ||
type: QuoteCacheType; | ||
result: QuoteResult; | ||
}> = ({ title, type, result }) => { | ||
const [{ id, quote, createdAt }, { cacheStatus, region, lastModified }] = [ | ||
result.data, | ||
result.info, | ||
]; | ||
|
||
return ( | ||
<QuoteWrapper title={title} type={type}> | ||
<div className="flex flex-col"> | ||
<p className="text-lg"> | ||
<span className="text-green-300">ID {id} </span>⸺ {'"'} | ||
{quote} | ||
{'"'} | ||
</p> | ||
<br /> | ||
<p className="text-lg"> | ||
<span className="font-bold mt-3.5">Created At</span> ⸺ | ||
{new Date(createdAt).toLocaleString("en-US")} | ||
</p> | ||
|
||
<div className="my-2 h-0.5 border-t-0 bg-neutral-100 opacity-100 dark:opacity-50"></div> | ||
|
||
<div> | ||
<br /> | ||
<p> | ||
Cache Node Region ⸺ | ||
<span className="font-bold" style={{ marginLeft: "4px" }}> | ||
{findIATA(region)?.city ?? region} | ||
</span> | ||
</p> | ||
<br /> | ||
<p> | ||
Cached Modified at ⸺ | ||
<span className="font-bold" style={{ marginLeft: "4px" }}> | ||
{new Date(lastModified).toLocaleString("en-US")} | ||
</span> | ||
</p> | ||
<br /> | ||
<p> | ||
Cache status ⸺ | ||
<span | ||
className={`font-bold ${ | ||
cacheStatus === "swr" || cacheStatus === "ttl" | ||
? "text-green-400" | ||
: "text-red-400" | ||
}`} | ||
style={{ marginLeft: "4px" }} | ||
> | ||
{cacheStatus | ||
.toUpperCase() | ||
.concat( | ||
cacheStatus === "swr" || cacheStatus === "ttl" | ||
? " CACHE HIT" | ||
: "", | ||
)} | ||
</span> | ||
</p> | ||
<br /> | ||
<p> | ||
Time taken: <span className="font-bold"> {result.time}ms</span> | ||
</p> | ||
<br /> | ||
</div> | ||
</div> | ||
</QuoteWrapper> | ||
); | ||
}; |
24 changes: 24 additions & 0 deletions
24
accelerate/remix-starter/app/components/Quote/QuoteWrapper.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/* eslint-disable react/prop-types */ | ||
import { QuoteCacheType } from "../../lib/types"; | ||
import { ReactNode } from "react"; | ||
|
||
export const QuoteWrapper: React.FC<{ | ||
title: string; | ||
type: QuoteCacheType; | ||
children: ReactNode; | ||
}> = ({ title, type, children }) => { | ||
return ( | ||
<div className="w-full h-full bg-white border border-gray-200 rounded-lg shadow p-4 dark:bg-gray-800 dark:border-gray-700"> | ||
<div className="flex items-center justify-between"> | ||
<h5 className="text-xl font-bold leading-none text-gray-900 dark:text-white"> | ||
{title} | ||
</h5> | ||
<div className="w-16"></div> | ||
<p className="text-xl font-medium text-blue-600 dark:text-blue-500"> | ||
{type} | ||
</p> | ||
</div> | ||
<div>{children}</div> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// app/components/Quotes.tsx | ||
import { Quote } from "./Quote"; | ||
import { QuoteResult } from "~/lib/types"; | ||
|
||
interface QuotesProps { | ||
ttl: QuoteResult; | ||
swr: QuoteResult; | ||
both: QuoteResult; | ||
none: QuoteResult; | ||
} | ||
|
||
export default function Quotes({ ttl, swr, both, none }: QuotesProps) { | ||
return ( | ||
<div className="w-full grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4"> | ||
<Quote title="Cached Quote" type="TTL" result={ttl}></Quote> | ||
<Quote title="Cached Quote" type="SWR" result={swr}></Quote> | ||
<Quote title="Cached Quote" type="TTL + SWR" result={both}></Quote> | ||
<Quote title="Quote" type="No caching" result={none}></Quote> | ||
</div> | ||
); | ||
} |
17 changes: 17 additions & 0 deletions
17
accelerate/remix-starter/app/components/Quote/RefreshQuote.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { Toaster } from "react-hot-toast"; | ||
|
||
export const RefreshQuote = () => { | ||
return ( | ||
<> | ||
<Toaster position="top-center" reverseOrder={false} /> | ||
|
||
<button | ||
type="button" | ||
onClick={() => window.location.reload()} | ||
className="focus:outline-none text-white bg-green-700 hover:bg-green-800 focus:ring-4 focus:ring-green-300 font-medium rounded-lg text-sm px-5 py-2.5 mr-2 mb-2 dark:bg-green-600 dark:hover:bg-green-700 dark:focus:ring-green-800" | ||
> | ||
Refresh | ||
</button> | ||
</> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import prisma from "./utils/prisma.server"; | ||
import { CacheStrategy } from "../lib/types"; | ||
|
||
export const getQuotes = async (strategy?: CacheStrategy) => { | ||
const start = Date.now(); | ||
|
||
const result = await prisma.quotes | ||
.findMany({ | ||
// You can find the `cacheStrategy` options [here](https://www.prisma.io/docs/accelerate/caching#cache-strategies). The `cacheStrategy` can also be undefined, which would mean only connection pooling is being used. | ||
cacheStrategy: strategy, | ||
orderBy: { | ||
id: "desc", | ||
}, | ||
take: 1, | ||
}) | ||
.withAccelerateInfo(); | ||
|
||
return { | ||
data: result?.data?.[0], | ||
info: result.info, | ||
time: Date.now() - start, | ||
}; | ||
}; |
Oops, something went wrong.