Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(remix-dev/cli): add DX improvements for migrate command & replace-remix-imports migration #2670

Merged
merged 31 commits into from
Apr 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
92806cf
refactor(cli/migrate): remove "client" terminology
pcattori Apr 5, 2022
5503f17
refactor(cli/migrate): reuse `Flag` type
pcattori Apr 5, 2022
cca42d7
fix(cli/migrate): only show jscodeshift args when `--debug` flag is set
pcattori Apr 5, 2022
5756be3
refactor(cli/migrate): make `adapter` option optional for `replace-re…
pcattori Apr 6, 2022
f40c42b
feat(cli/migrate): improve runtime/adapter resolution for `replace-re…
pcattori Apr 6, 2022
8080bb1
chore(cli/migrate): silence warnings about mixing default/named expor…
pcattori Apr 6, 2022
2bf5f20
feat(cli/migrate): do not modify user's `package.json`, instead ask t…
pcattori Apr 6, 2022
45558e6
refactor(cli/migrate): check git status as soon as possible
pcattori Apr 6, 2022
928d1af
test(cli): add `--debug` flag for `migrate` command in tests
pcattori Apr 6, 2022
11bdc74
refactor(cli/migrate): combine imports from same module
pcattori Apr 6, 2022
87a6a47
feat(cli/migrate): auto-detect `node` runtime if `@remix-run/serve` i…
pcattori Apr 6, 2022
c57111a
feat(cli/migrate): show `npm` commands for manual steps in `replace-r…
pcattori Apr 6, 2022
6553122
feat(cli/migrate): handle `remix setup` without runtime arg in `repla…
pcattori Apr 6, 2022
6a38e76
feat(cli/migrate): auto-detect server runtime from presence of server…
pcattori Apr 7, 2022
9a04568
feat(cli/migrate): automatically update package.json
pcattori Apr 9, 2022
c4d0481
refactor(cli/migrate): convenience function for resolving general all…
pcattori Apr 9, 2022
4372234
feat(cli/migrate): user-friendly cli output for `replace-remix-imports`
pcattori Apr 10, 2022
5dc8c6a
refactor(cli/migrate): remove unused import
pcattori Apr 11, 2022
048f26e
refactor(cli/migrate): explicit type for `adapterToRuntime` converter
pcattori Apr 11, 2022
b262977
refactor(cli/migrate): remove redundant check for migration id
pcattori Apr 11, 2022
659c6a3
refactor(cli/migrate): explicitly type `detectedRuntime` utility with…
pcattori Apr 11, 2022
738f414
test(cli/migrate): `replace-remix-imports` runs successfully on (old)…
pcattori Apr 11, 2022
6d8bcea
style: ignore test fixtures
pcattori Apr 11, 2022
d6a7181
chore(dev): remove reference to non-existant `@mdx-js/mdx` types
pcattori Apr 11, 2022
053b8f8
refactor(cli/migrate): ignore missing types for `@npmcli/package-json`
pcattori Apr 11, 2022
a2495ab
fix(cli/migrate): only print colorful output if terminal supports it …
pcattori Apr 11, 2022
a6b98d0
test(cli/migrate): check that `replace-remix-imports` remove all `rem…
pcattori Apr 11, 2022
96e5bfe
fix(cli/migrate): `replace-remix-imports` ensures `@remix-run/dev` is…
pcattori Apr 11, 2022
1c9051b
fix(cli/migrate): package.json already exists, so refer to it as "upd…
pcattori Apr 11, 2022
6a7a688
refactor(cli/migrate): separate transform-related exports from the tr…
pcattori Apr 11, 2022
6963bcb
fix(cli/migrate): fix all jscodeshift non-supported typescript syntax…
pcattori Apr 11, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
templates/deno
.tmp
/playground
**/__tests__/fixtures
1 change: 1 addition & 0 deletions packages/remix-dev/__tests__/cli-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ describe("remix CLI", () => {
\`routes\` Options:
--json Print the routes as JSON
\`migrate\` Options:
--debug Show debugging logs
--dry Dry run (no changes are made to files)
--force Bypass Git safety checks and forcibly run migration
--migration, -m Name of the migration to run
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { PrismaClient } from "@prisma/client";

let prisma: PrismaClient;

declare global {
var __db__: PrismaClient;
}

// 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") {
prisma = new PrismaClient();
} else {
if (!global.__db__) {
global.__db__ = new PrismaClient();
}
prisma = global.__db__;
}

export { prisma };
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { hydrate } from "react-dom";
import { RemixBrowser } from "remix";

hydrate(<RemixBrowser />, document);
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { renderToString } from "react-dom/server";
import { RemixServer } from "remix";
import type { EntryContext } from "remix";

export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
const markup = renderToString(
<RemixServer context={remixContext} url={request.url} />
);

responseHeaders.set("Content-Type", "text/html");

return new Response("<!DOCTYPE html>" + markup, {
status: responseStatusCode,
headers: responseHeaders,
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import type { User, Note } from "@prisma/client";

import { prisma } from "~/db.server";

export type { Note } from "@prisma/client";

export function getNote({
id,
userId,
}: Pick<Note, "id"> & {
userId: User["id"];
}) {
return prisma.note.findFirst({
where: { id, userId },
});
}

export function getNoteListItems({ userId }: { userId: User["id"] }) {
return prisma.note.findMany({
where: { userId },
select: { id: true, title: true },
orderBy: { updatedAt: "desc" },
});
}

export function createNote({
body,
title,
userId,
}: Pick<Note, "body" | "title"> & {
userId: User["id"];
}) {
return prisma.note.create({
data: {
title,
body,
user: {
connect: {
id: userId,
},
},
},
});
}

export function deleteNote({
id,
userId,
}: Pick<Note, "id"> & { userId: User["id"] }) {
return prisma.note.deleteMany({
where: { id, userId },
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { prisma } from "~/db.server";
import type { Post } from "@prisma/client";
export type { Post };

export async function getPosts() {
return prisma.post.findMany();
}

export async function getPost(slug: string) {
return prisma.post.findUnique({ where: { slug } });
}

export async function createPost(
post: Pick<Post, "slug" | "title" | "markdown">
) {
return prisma.post.create({ data: post });
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import type { Password, User } from "@prisma/client";
import bcrypt from "@node-rs/bcrypt";

import { prisma } from "~/db.server";

export type { User } from "@prisma/client";

export async function getUserById(id: User["id"]) {
return prisma.user.findUnique({ where: { id } });
}

export async function getUserByEmail(email: User["email"]) {
return prisma.user.findUnique({ where: { email } });
}

export async function createUser(email: User["email"], password: string) {
const hashedPassword = await bcrypt.hash(password, 10);

return prisma.user.create({
data: {
email,
password: {
create: {
hash: hashedPassword,
},
},
},
});
}

export async function deleteUserByEmail(email: User["email"]) {
return prisma.user.delete({ where: { email } });
}

export async function verifyLogin(
email: User["email"],
password: Password["hash"]
) {
const userWithPassword = await prisma.user.findUnique({
where: { email },
include: {
password: true,
},
});

if (!userWithPassword || !userWithPassword.password) {
return null;
}

const isValid = await bcrypt.verify(password, userWithPassword.password.hash);

if (!isValid) {
return null;
}

const { password: _password, ...userWithoutPassword } = userWithPassword;

return userWithoutPassword;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
json,
Links,
LiveReload,
Meta,
Outlet,
Scripts,
ScrollRestoration,
} from "remix";
import type { LinksFunction, MetaFunction, LoaderFunction } from "remix";

import tailwindStylesheetUrl from "./styles/tailwind.css";
import { getUser } from "./session.server";

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

export const meta: MetaFunction = () => ({
charset: "utf-8",
title: "Remix Notes",
viewport: "width=device-width,initial-scale=1",
});

type LoaderData = {
user: Awaited<ReturnType<typeof getUser>>;
};

export const loader: LoaderFunction = async ({ request }) => {
return json<LoaderData>({
user: await getUser(request),
});
};

export default function App() {
return (
<html lang="en" className="h-full">
<head>
<Meta />
<Links />
</head>
<body className="h-full">
<Outlet />
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// learn more: https://fly.io/docs/reference/configuration/#services-http_checks
import type { LoaderFunction } from "remix";
import { prisma } from "~/db.server";

export const loader: LoaderFunction = async ({ request }) => {
const host =
request.headers.get("X-Forwarded-Host") ?? request.headers.get("host");

try {
// if we can connect to the database and make a simple query
// and make a HEAD request to ourselves, then we're good.
await Promise.all([
prisma.user.count(),
fetch(`http://${host}`, { method: "HEAD" }).then((r) => {
if (!r.ok) return Promise.reject(r);
}),
]);
return new Response("OK");
} catch (error: unknown) {
console.log("healthcheck ❌", { error });
return new Response("ERROR", { status: 500 });
}
};
Loading