Skip to content

Commit

Permalink
docs(tutorials/jokes): update to be compatible with v2_dev
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaelDeBoey committed Aug 22, 2023
1 parent a873056 commit 9dfd6e6
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 66 deletions.
31 changes: 17 additions & 14 deletions docs/guides/manual-mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,30 +264,33 @@ That includes things like database connections, caches, in-memory data structure

Here's a utility that remembers any in-memory values you want to keep around across rebuilds:

```ts filename=app/utils/remember.ts
// adapted from https://github.com/jenseng/abuse-the-platform/blob/main/app/utils/singleton.ts
// thanks @jenseng!

export function remember<T>(
key: string,
getValue: () => T
) {
```ts filename=app/utils/singleton.server.ts
// Borrowed & modified from https://github.com/jenseng/abuse-the-platform/blob/main/app/utils/singleton.ts
// Thanks @jenseng!

export const singleton = <Value>(
name: string,
valueFactory: () => Value
): Value => {
const g = global as any;
g.__remember ??= {};
g.__remember[key] ??= getValue();
return g.__remember[key];
}
g.__singletons ??= {};
g.__singletons[name] ??= valueFactory();
return g.__singletons[name];
};
```

For example, to reuse a Prisma client across rebuilds:

```ts filename=app/db.server.ts
import { PrismaClient } from "@prisma/client";

import { remember } from "~/utils/remember";
import { singleton } from "~/utils/singleton.server";

// hard-code a unique key so we can look up the client when this module gets re-imported
export const db = remember("db", () => new PrismaClient());
export const db = singleton(
"prisma",
() => new PrismaClient()
);
```

[mental-model]: https://www.youtube.com/watch?v=zTrjaUt9hLo
Expand Down
103 changes: 51 additions & 52 deletions docs/tutorials/jokes.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ You can follow along with this tutorial on [CodeSandbox][code-sandbox] (a fantas
- [npm][npm] 7 or greater
- A code editor ([VSCode][vs-code] is a nice one)

If you'd like to follow along with the deploy step at the end, you'll also want an account on [Fly.io][fly-io].
If you'd like to follow along with the deployment step at the end, you'll also want an account on [Fly.io][fly-io].

We'll also be executing commands in your system command line/terminal interface. So you'll want to be familiar with that.

Expand All @@ -84,7 +84,7 @@ If you're planning on using CodeSandbox, you can use [the Basic example][the-bas

💿 Open your terminal and run this command:

```sh
```shellscript nonumber
npx create-remix@latest
```

Expand All @@ -110,7 +110,7 @@ Once the `npm install` has completed, we'll change into the `remix-jokes` direct

💿 Run this command

```sh
```shellscript nonumber
cd remix-jokes
```

Expand Down Expand Up @@ -147,12 +147,12 @@ Let's talk briefly about a few of these files:
- `app/entry.server.tsx` - This is the first bit of your JavaScript that will run when a request hits your server. Remix handles loading all the necessary data, and you're responsible for sending back the response. We'll use this file to render our React app to a string/stream and send that as our response to the client.
- `app/root.tsx` - This is where we put the root component for our application. You render the `<html>` element here.
- `app/routes/` - This is where all your "route modules" will go. Remix uses the files in this directory to create the URL routes for your app based on the name of the files.
- `public/` - This is where your static assets go (images/fonts/etc)
- `public/` - This is where your static assets go (images/fonts/etc.)
- `remix.config.js` - Remix has a handful of configuration options you can set in this file.

💿 Let's go ahead and run the build:

```sh
```shellscript nonumber
npm run build
```

Expand All @@ -167,7 +167,7 @@ Now you should also have a `.cache/` directory (something used internally by Rem

💿 Let's run the built app now:

```sh
```shellscript nonumber
npm start
```

Expand Down Expand Up @@ -197,7 +197,7 @@ export default function App() {
<meta charSet="utf-8" />
<meta
name="viewport"
content="width=device-width,initial-scale=1"
content="width=device-width, initial-scale=1"
/>
<title>Remix: So great, it's funny!</title>
</head>
Expand Down Expand Up @@ -227,7 +227,7 @@ app

💿 With that set up, go ahead and start the dev server up with this command:

```sh
```shellscript nonumber
npm run dev
```

Expand Down Expand Up @@ -285,7 +285,7 @@ export default function App() {
<meta charSet="utf-8" />
<meta
name="viewport"
content="width=device-width,initial-scale=1"
content="width=device-width, initial-scale=1"
/>
<title>Remix: So great, it's funny!</title>
</head>
Expand Down Expand Up @@ -506,7 +506,7 @@ export default function App() {
<meta charSet="utf-8" />
<meta
name="viewport"
content="width=device-width,initial-scale=1"
content="width=device-width, initial-scale=1"
/>
<title>Remix: So great, it's funny!</title>
<Links />
Expand Down Expand Up @@ -1216,7 +1216,7 @@ export default function App() {
<meta charSet="utf-8" />
<meta
name="viewport"
content="width=device-width,initial-scale=1"
content="width=device-width, initial-scale=1"
/>
<title>Remix: So great, it's funny!</title>
<Links />
Expand Down Expand Up @@ -1352,14 +1352,14 @@ There are two packages that we need to get started:

💿 Install the Prisma packages:

```sh
```shellscript nonumber
npm install --save-dev prisma
npm install @prisma/client
```

💿 Now we can initialize Prisma with SQLite:

```sh
```shellscript nonumber
npx prisma init --datasource-provider sqlite
```

Expand Down Expand Up @@ -1406,7 +1406,7 @@ model Joke {

💿 With that in place, run this:

```sh
```shellscript nonumber
npx prisma db push
```

Expand Down Expand Up @@ -1439,7 +1439,7 @@ node_modules
/prisma/dev.db
```

<docs-warning>If your database gets messed up, you can always delete the `prisma/dev.db` file and run `npx prisma db push` again. Remember to also restart your dev server with `npm run dev`.</docs-warning>
<docs-warning>If your database gets messed up, you can always delete the `prisma/dev.db` file and run `npx prisma db push` again.</docs-warning>

Next, we're going to write a little file that will "seed" our database with test data. Again, this isn't really remix-specific stuff, so I'll just give this to you (don't worry, we'll get back to remix soon):

Expand Down Expand Up @@ -1501,13 +1501,13 @@ Now we just need to run this file. We wrote it in TypeScript to get type safety

💿 Install `ts-node` and `tsconfig-paths` as dev dependencies:

```sh
```shellscript nonumber
npm install --save-dev ts-node tsconfig-paths
```

💿 And now we can run our `seed.ts` file with that:

```sh
```shellscript nonumber
npx ts-node --require tsconfig-paths/register prisma/seed.ts
```

Expand Down Expand Up @@ -1542,32 +1542,30 @@ This works just fine, but the problem is, during development, we don't want to c
So we've got a bit of extra work to do to avoid this development time problem.

Note that this isn't a remix-only problem. Any time you have "live reload" of server code, you're going to have to either disconnect and reconnect to databases (which can be slow) or do the workaround I'm about to show you.
Note that this isn't a remix-only problem. Any time you have "live reload" of server code, you're going to have to either disconnect and reconnect to databases (which can be slow) or use the [`global` singleton workaround][global-singleton-workaround].

💿 Copy this into a new file called `app/utils/db.server.ts`
💿 Copy this into two new files called `app/utils/singleton.server.ts` & `app/utils/db.server.ts`

```ts filename=app/utils/singleton.server.ts
export const singleton = <Value>(
name: string,
valueFactory: () => Value
): Value => {
const g = global as any;
g.__singletons ??= {};
g.__singletons[name] ??= valueFactory();
return g.__singletons[name];
};
```

```ts filename=app/utils/db.server.ts
import { PrismaClient } from "@prisma/client";

let db: PrismaClient;
import { singleton } from "./singleton.server";

declare global {
var __db__: PrismaClient | undefined;
}

// This is needed because in development we don't want to restart
// the server with every change, but we want to make sure we don't
// create a new connection to the DB with every change either.
// In production, we'll have a single connection to the DB.
if (process.env.NODE_ENV === "production") {
db = new PrismaClient();
} else {
if (!global.__db__) {
global.__db__ = new PrismaClient();
}
db = global.__db__;
db.$connect();
}
// Hard-code a unique key, so we can look up the client when this module gets re-imported
const db = singleton("prisma", () => new PrismaClient());
db.$connect();

export { db };
```
Expand Down Expand Up @@ -2199,7 +2197,7 @@ With that updated, let's go ahead and reset our database to this schema:

💿 Run this:

```sh
```shellscript nonumber
npx prisma db push
```

Expand Down Expand Up @@ -2291,7 +2289,7 @@ function getJokes() {

💿 Great, now run the seed again:

```sh
```shellscript nonumber
npx prisma db seed
```

Expand All @@ -2312,13 +2310,13 @@ So our authentication will be of the traditional username/password variety. We'l

💿 Go ahead and get that installed right now, so we don't forget:

```sh
```shellscript nonumber
npm install bcryptjs
```

💿 The `bcryptjs` library has TypeScript definitions in DefinitelyTyped, so let's install those as well:

```sh
```shellscript nonumber
npm install --save-dev @types/bcryptjs
```

Expand Down Expand Up @@ -4029,7 +4027,7 @@ function Document({
<meta charSet="utf-8" />
<meta
name="viewport"
content="width=device-width,initial-scale=1"
content="width=device-width, initial-scale=1"
/>
<title>{title}</title>
<Links />
Expand Down Expand Up @@ -4169,7 +4167,7 @@ With that understanding, we're going to add a `isRouteErrorResponse` check to th
- `app/root.tsx` - Just as a last resort fallback.
- `app/routes/jokes.$jokeId.tsx` - When a user tries to access a joke that doesn't exist (404).
- `app/routes/jokes.new.tsx` - When a user tries to go to this page without being authenticated (401). Right now they'll just get redirected to the login if they try to submit it without authenticating. That would be super annoying to spend time writing a joke only to get redirected. Rather than inexplicably redirecting them, we could render a message that says they need to authenticate first.
- `app/routes/jokes._index.tsx` - If there are no jokes in the database then a random joke is 404-not found. (simulate this by deleting the `prisma/dev.db` and running `npx prisma db push`. Don't forget to run `npx prisma db seed` afterwards to get your seed data back.)
- `app/routes/jokes._index.tsx` - If there are no jokes in the database then a random joke is 404-not found. (simulate this by deleting the `prisma/dev.db` and running `npx prisma db push`. Don't forget to run `npx prisma db seed` afterward to get your seed data back.)

💿 Let's add these `isRouteErrorResponse` checks to the routes.

Expand Down Expand Up @@ -4216,7 +4214,7 @@ function Document({
<meta charSet="utf-8" />
<meta
name="viewport"
content="width=device-width,initial-scale=1"
content="width=device-width, initial-scale=1"
/>
<title>{title}</title>
<Links />
Expand Down Expand Up @@ -4943,7 +4941,7 @@ function Document({
<meta charSet="utf-8" />
<meta
name="viewport"
content="width=device-width,initial-scale=1"
content="width=device-width, initial-scale=1"
/>
<meta name="keywords" content="Remix,jokes" />
<meta
Expand Down Expand Up @@ -5763,7 +5761,7 @@ function Document({
<meta charSet="utf-8" />
<meta
name="viewport"
content="width=device-width,initial-scale=1"
content="width=device-width, initial-scale=1"
/>
<meta name="keywords" content="Remix,jokes" />
<meta
Expand Down Expand Up @@ -5895,7 +5893,7 @@ function Document({
<meta charSet="utf-8" />
<meta
name="viewport"
content="width=device-width,initial-scale=1"
content="width=device-width, initial-scale=1"
/>
<meta name="keywords" content="Remix,jokes" />
<meta
Expand Down Expand Up @@ -7610,7 +7608,7 @@ I feel pretty great about the user experience we've created here. So let's get t

💿 Once you've done that, run this command from within your project directory:

```sh
```shellscript nonumber
fly launch
```

Expand Down Expand Up @@ -7654,7 +7652,7 @@ Fly generated a few files for us:

💿 Now set the `SESSION_SECRET` environment variable by running this command:

```sh
```shellscript nonumber
fly secrets set SESSION_SECRET=your-secret-here
```

Expand All @@ -7664,7 +7662,7 @@ One other thing we need to do is get Prisma ready to set up our database for the

💿 Run this command:

```sh
```shellscript nonumber
npx prisma migrate dev
```

Expand Down Expand Up @@ -7703,15 +7701,15 @@ Running seed command `ts-node --require tsconfig-paths/register prisma/seed.ts`

💿 If you did get an error when running the seed, you can run it manually now:

```sh
```shellscript nonumber
npx prisma db seed
```

With that done, you're ready to deploy.

💿 Run this command:

```sh
```shellscript nonumber
fly deploy
```

Expand Down Expand Up @@ -7833,3 +7831,4 @@ Phew! And there we have it. If you made it through this whole thing then I'm rea
[their-blog-article]: https://fly.io/blog/free-postgres/#a-note-about-credit-cards
[fly-io-apps]: https://fly.io/apps
[tweet-your-success]: https://twitter.com/intent/tweet?text=I%20went%20through%20the%20whole%20remix.run%20jokes%20tutorial!%20%F0%9F%92%BF%20And%20now%20I%20love%20@remix_run!&url=https://remix.run/tutorials/jokes
[global-singleton-workaround]: ../guides/manual-mode#keeping-in-memory-server-state-across-rebuilds

0 comments on commit 9dfd6e6

Please sign in to comment.