Skip to content

Commit 056ca2b

Browse files
committed
ci: wip add script to install, build, and typecheck examples
Signed-off-by: Logan McAnsh <[email protected]>
1 parent 973e7b2 commit 056ca2b

File tree

17 files changed

+311
-49
lines changed

17 files changed

+311
-49
lines changed

.github/workflows/changed.yml

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: Typecheck changed examples
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
9+
jobs:
10+
typecheck:
11+
if: github.repository == 'remix-run/examples'
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- name: 🛑 Cancel Previous Runs
16+
uses: styfle/[email protected]
17+
18+
- name: ⬇️ Checkout repo
19+
uses: actions/checkout@v3
20+
21+
- name: ⎔ Setup node
22+
uses: actions/setup-node@v3
23+
with:
24+
node-version-file: ".nvmrc"
25+
cache: "yarn"
26+
27+
- name: 📥 Install deps
28+
run: yarn --frozen-lockfile
29+
30+
- name: install, build, typecheck
31+
run: node ./scripts/test.mjs

dataloader/app/data.server.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
interface User {
1+
export interface User {
22
id: string;
33
email: string;
44
name: string;

dataloader/app/loaders/userLoader.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
import { DataFunctionArgs } from "@remix-run/node";
12
import DataLoader from "dataloader";
23

34
import { db } from "~/data.server";
45

56
export const createUsersByIdLoader = () =>
67
new DataLoader(async (ids: Readonly<string[]>) => {
7-
const users = await db.user.findMany({
8+
const users = db.user.findMany({
89
where: {
910
id: {
1011
in: ids,
@@ -14,3 +15,11 @@ export const createUsersByIdLoader = () =>
1415
const userMap = new Map(users.map((user) => [user.id, user]));
1516
return ids.map((id) => userMap.get(id) ?? null);
1617
});
18+
19+
export interface DataLoaderArgs extends DataFunctionArgs {
20+
context: {
21+
loaders: {
22+
usersById: ReturnType<typeof createUsersByIdLoader>;
23+
};
24+
};
25+
}

dataloader/app/routes/users.tsx

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
import type { LoaderArgs } from "@remix-run/node";
21
import { json } from "@remix-run/node";
32
import { Outlet, useLoaderData } from "@remix-run/react";
3+
import { User } from "~/data.server";
4+
import { DataLoaderArgs } from "~/loaders/userLoader";
45

5-
export const loader = async ({ context }: LoaderArgs) => {
6+
export const loader = async ({ context }: DataLoaderArgs) => {
67
const users = await context.loaders.usersById.loadMany([
78
"ef3fcb93-0623-4d10-adbf-4dd865d6688c",
89
"2cbad877-2da6-422d-baa6-c6a96a9e085f",
910
]);
10-
return json({ users });
11+
return json({ users: users.filter((u): u is User => !!u) });
1112
};
1213

1314
export default function UserNames() {

dataloader/app/routes/users/index.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import type { LoaderArgs } from "@remix-run/node";
21
import { json } from "@remix-run/node";
32
import { useLoaderData } from "@remix-run/react";
3+
import { DataLoaderArgs } from "~/loaders/userLoader";
44

5-
export const loader = async ({ context }: LoaderArgs) => {
5+
export const loader = async ({ context }: DataLoaderArgs) => {
66
/*
77
* For demo purposes:
88
* Batching & caching also works with multiple calls to `DataLoader#load`

dataloader/package.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,17 @@
1616
"cross-env": "^7.0.3",
1717
"dataloader": "^2.0.0",
1818
"express": "^4.17.3",
19-
"morgan": "^1.10.0",
2019
"isbot": "^3.6.5",
20+
"morgan": "^1.10.0",
2121
"react": "^18.2.0",
2222
"react-dom": "^18.2.0"
2323
},
2424
"devDependencies": {
2525
"@remix-run/dev": "*",
2626
"@remix-run/eslint-config": "*",
27+
"@types/compression": "1.7.2",
28+
"@types/express": "4.17.15",
29+
"@types/morgan": "1.9.3",
2730
"@types/react": "^18.0.25",
2831
"@types/react-dom": "^18.0.8",
2932
"esbuild-register": "^3.3.2",

dataloader/server/index.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
const path = require("path");
1+
import path from "path";
22

3-
const express = require("express");
4-
const compression = require("compression");
5-
const morgan = require("morgan");
6-
const { createRequestHandler } = require("@remix-run/express");
3+
import express from "express";
4+
import compression from "compression";
5+
import morgan from "morgan";
6+
import { createRequestHandler } from "@remix-run/express";
77

8-
const { createUsersByIdLoader } = require("../app/loaders/userLoader");
8+
import { createUsersByIdLoader } from "../app/loaders/userLoader";
99

1010
const MODE = process.env.NODE_ENV;
1111
const BUILD_DIR = path.join(process.cwd(), "server/build");

dataloader/tsconfig.json

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
{
22
"include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx", "server/index.ts"],
33
"compilerOptions": {
4+
"allowJs": true,
5+
"forceConsistentCasingInFileNames": true,
46
"lib": ["DOM", "DOM.Iterable", "ES2019"],
57
"isolatedModules": true,
68
"esModuleInterop": true,

file-and-cloudinary-upload/app/routes/cloudinary-upload.tsx

+7-4
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export const action = async ({ request }: ActionArgs) => {
3333
};
3434

3535
export default function Index() {
36-
const data = useActionData<typeof action>();
36+
const actionData = useActionData<typeof action>();
3737

3838
return (
3939
<>
@@ -44,12 +44,15 @@ export default function Index() {
4444
<input id="img-desc" type="text" name="desc" />
4545
<button type="submit">upload to cloudinary</button>
4646
</Form>
47-
{data?.error ? <h2>{data.error}</h2> : null}
47+
{actionData && "error" in actionData ? <h2>{actionData.error}</h2> : null}
4848

49-
{data?.imgSrc ? (
49+
{actionData && "imgSrc" in actionData ? (
5050
<>
5151
<h2>uploaded image</h2>
52-
<img src={data.imgSrc} alt={data.imgDesc || "Upload result"} />
52+
<img
53+
src={actionData.imgSrc}
54+
alt={actionData.imgDesc || "Upload result"}
55+
/>
5356
</>
5457
) : null}
5558
</>

file-and-cloudinary-upload/app/routes/local-upload.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,20 @@ export const action = async ({ request }: ActionArgs) => {
2626
};
2727

2828
export default function Index() {
29-
const data = useActionData<typeof action>();
29+
const actionData = useActionData<typeof action>();
3030

3131
return (
3232
<>
3333
<Form method="post" encType="multipart/form-data">
3434
<input type="file" name="img" accept="image/*" />
3535
<button type="submit">upload image</button>
3636
</Form>
37-
{data?.error ? <h2>{data.error}</h2> : null}
37+
{actionData && "error" in actionData ? <h2>{actionData.error}</h2> : null}
3838

39-
{data?.imgSrc ? (
39+
{actionData && "imgSrc" in actionData ? (
4040
<>
4141
<h2>uploaded image</h2>
42-
<img alt="uploaded" src={data.imgSrc} />
42+
<img alt="uploaded" src={actionData.imgSrc} />
4343
</>
4444
) : null}
4545
</>

file-and-cloudinary-upload/app/utils/utils.server.ts

+17-15
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import cloudinary from "cloudinary";
1+
import cloudinary, { UploadApiResponse } from "cloudinary";
22
import { writeAsyncIterableToWritable } from "@remix-run/node";
33

44
cloudinary.v2.config({
@@ -8,21 +8,23 @@ cloudinary.v2.config({
88
});
99

1010
async function uploadImage(data: AsyncIterable<Uint8Array>) {
11-
const uploadPromise = new Promise(async (resolve, reject) => {
12-
const uploadStream = cloudinary.v2.uploader.upload_stream(
13-
{
14-
folder: "remix",
15-
},
16-
(error, result) => {
17-
if (error) {
18-
reject(error);
19-
return;
11+
const uploadPromise = new Promise<UploadApiResponse>(
12+
async (resolve, reject) => {
13+
const uploadStream = cloudinary.v2.uploader.upload_stream(
14+
{
15+
folder: "remix",
16+
},
17+
(error, result) => {
18+
if (error || !result) {
19+
reject(error);
20+
return;
21+
}
22+
resolve(result);
2023
}
21-
resolve(result);
22-
}
23-
);
24-
await writeAsyncIterableToWritable(data, uploadStream);
25-
});
24+
);
25+
await writeAsyncIterableToWritable(data, uploadStream);
26+
}
27+
);
2628

2729
return uploadPromise;
2830
}

package.json

+6
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,11 @@
2020
},
2121
"engines": {
2222
"node": ">=14"
23+
},
24+
"dependencies": {
25+
"@antfu/ni": "^0.18.8",
26+
"@npmcli/package-json": "^3.0.0",
27+
"execa": "^6.1.0",
28+
"fs-extra": "11.1.0"
2329
}
2430
}

pm-app/app/routes/register.tsx

+17-7
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,15 @@ export const action = async ({ request }: ActionArgs) => {
125125
};
126126

127127
export default function Register() {
128-
const actionData = useActionData<typeof action>() || {};
129-
const { fieldErrors, fields, formError } = actionData;
128+
const actionData = useActionData<typeof action>();
129+
let fieldErrors =
130+
actionData && "fieldErrors" in actionData
131+
? actionData.fieldErrors
132+
: undefined;
133+
let formError =
134+
actionData && "formError" in actionData ? actionData.formError : undefined;
135+
let fields =
136+
actionData && "fields" in actionData ? actionData.fields : undefined;
130137
const [searchParams] = useSearchParams();
131138

132139
React.useEffect(() => {
@@ -169,7 +176,7 @@ export default function Register() {
169176
id="form-error-text"
170177
role="alert"
171178
>
172-
{actionData.formError}
179+
{formError}
173180
</span>
174181
</div>
175182
) : null}
@@ -194,7 +201,7 @@ export default function Register() {
194201
error={fieldErrors?.nameFirst}
195202
>
196203
<Label>First Name</Label>
197-
<Field defaultValue={fields?.nameFirst} />
204+
<Field defaultValue={fields?.nameFirst || undefined} />
198205
<FieldError />
199206
</FieldProvider>
200207
<FieldProvider
@@ -203,7 +210,7 @@ export default function Register() {
203210
error={fieldErrors?.nameLast}
204211
>
205212
<Label>Last Name</Label>
206-
<Field defaultValue={fields?.nameLast} />
213+
<Field defaultValue={fields?.nameLast || undefined} />
207214
<FieldError />
208215
</FieldProvider>
209216
<FieldProvider
@@ -216,7 +223,7 @@ export default function Register() {
216223
<Field
217224
type="email"
218225
placeholder="[email protected]"
219-
defaultValue={fields?.email}
226+
defaultValue={fields?.email || undefined}
220227
/>
221228
<FieldError />
222229
</FieldProvider>
@@ -227,7 +234,10 @@ export default function Register() {
227234
error={fieldErrors?.password}
228235
>
229236
<Label>Password</Label>
230-
<Field type="password" defaultValue={fields?.password} />
237+
<Field
238+
type="password"
239+
defaultValue={fields?.password || undefined}
240+
/>
231241
<FieldError />
232242
</FieldProvider>
233243
<Button className="register__email-submit-button">Sign Up</Button>

pm-app/app/ui/form.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export function useFieldContext() {
99
return React.useContext(FieldContext);
1010
}
1111

12-
const FieldProvider = React.forwardRef<
12+
export const FieldProvider = React.forwardRef<
1313
HTMLDivElement,
1414
React.PropsWithChildren<FieldContextValue & { className?: string }>
1515
>(({ children, className, ...ctx }, ref) => {

pm-app/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,19 @@
22
"private": true,
33
"sideEffects": false,
44
"scripts": {
5-
"build": "run-s \"build:*\"",
65
"build:css": "npm run generate:css -- --env production",
76
"build:remix": "remix build",
7+
"build": "run-s \"build:*\"",
88
"db:check": "docker ps",
99
"db:reset": "prisma migrate reset --force",
1010
"db:start": "docker compose up -d",
1111
"db:stop": "docker compose down",
1212
"db:update": "prisma migrate dev",
1313
"deploy": "flyctl deploy",
14-
"dev": "npm run db:start && pm2-dev pm2.config.js",
1514
"dev:css": "npm run generate:css -- --watch",
1615
"dev:remix": "remix dev",
1716
"dev:server": "node server/index.js",
17+
"dev": "npm run db:start && pm2-dev pm2.config.js",
1818
"generate:css": "postcss app/styles --base app/styles --dir app/dist/styles",
1919
"start": "node server/index.js",
2020
"typecheck": "tsc"

0 commit comments

Comments
 (0)