Recently, I saw Remix.run (hereinafter referred to as Remix) at JavaScript Weekly that it is preparing to release version 1.0 as an open source. Within two days, I saw Remix soaring to the top of the Github Trending trend list. It feels like it's already on fire. I don't know how it compares with Next.js. But it doesn't look too complicated, many things are encapsulated, and the syntax is very light. So prepare to study and take some study notes by the way.
Create project
Download the latest version of remix from npm and generate the project.
npx create-remix@latest
? Where would you like to create your app?
my-cv
I am going to make a web application that displays resumes and dynamically display project experience. This is still a bit demanding, otherwise it's just a demo. After all, there is no need to study in depth. Moreover, the feature of SSR (Server Side Render) is to facilitate SEO, and it is most suitable to be an application that displays dynamic data. Named my-cv
.
? Where do you want to deploy? Choose Remix if you're unsure, it's easy to change deployment targets.
- Remix App Server
- Express Server
- Architect (AWS Lambda)
- Fly.io
- Netlify
- Vercel
- Cloudflare Workers
Of course choose the original Remix App Server
? TypeScript or JavaScript?
TypeScript
- JavaScript
I chose TypeScript. In fact, I generally don't choose TypeScript for my personal projects, but I still need to learn the following this time, so I try to simulate it more formally. For individual developers, TypeScript does more harm than good. Although it can effectively reduce errors and the time cost of finding errors, it takes more time to prepare when starting projects such as defining types. There are also unpopular libraries that are hard to find that do not support TS. risk.
? Do you want me to runnpm install
?Y
Finally, install it.
Startup project
Enter the project directory
cd my-cv
Start up and have a look
npm run dev
Here Node version 12 will report an error, 16 is no problem.
"Could not locate @remix-run/serve. Please verify you have it installed to use the dev command."
Can visit http://localhost:3000
now.
Directly comes with a Demo, which shows the various states of the route, such as 404, 401, and routes with parameters. You can keep it for reference or delete it.
Create page
This Demo style is okay, so I just keep it. Anyway, writing styles by myself doesn't make much sense for learning Remix. So I changed the navigation to Chinese, and then changed the second page to a new route, which can be created later to display resumes. Then the third Github link was changed to my own.
<ul>
<li>
<Link to="/">首页</Link>
</li>
<li>
<Link to="/resume">简历</Link>
</li>
<li>
<a href="https://github.com/tychio">GitHub</a>
</li>
</ul>
Then, create the corresponding page.
mkdir app/routes/resume
touch app/routes/resume/index.tsx
Then fill in some static text, name and introduction. There are also skills, this can be done by loading dynamic data, first do the front-end part, and return directly from the literal. Use useLoaderData
to return data.
import type { LoaderFunction } from "remix";
import { useLoaderData, json } from "remix";
type ResumeData = {
skills: Array<{ name: string }>;
};
export const loader: LoaderFunction = () => {
const data: ResumeData = {
skills: [
'JavaScript', 'CSS/HTML', 'React', 'Remix'
]
};
return json(data);
}
export default function ResumeIndex() {
const resume = useLoaderData<ResumeData>();
return (
<div>
<h1>Zhang Zhengzheng</h1>
<p>
A full-stack developer, Senior consultant, Freelancer.
</p>
<p>
{resume.skills.map((skill, index) => (
<span>{index !== 0 ? ', ' : ''}{skill.name}</span>
))}
</p>
</div>
);
}
Note: Theloader
here is called by the back-end API hookuseLoaderData
, so you can’t see the usage
I also defined the ResumeData
for the dynamic data of the page, which includes skills
.
Use database ORM
Next, find an ORM and put the data completely in the database. I chose Prisma,
npm install --save-dev prisma
npm install @prisma/client
Initialize ORM
npx prisma init --datasource-provider mysql
I chose mysql, you can use SQL Lite npx prisma init --datasource-provider sqlite
directly.
Then add .env
settings file DATABASE_URL
mysql://<username>:<password>@<host | localhost>:<port>/<database_name>
Then execute npx prisma db pull
read the database and automatically generate the schema.
Then execute npx prisma generate
generate the client.
In this way, ORM can be used with the following code.
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
Create table
I created the skills table in advance, so when I prisma/schema.prisma
it just now, there was a model in the 061a6043ec17f2 file.
model skills {
id Int @id @default(autoincrement())
name String? @db.VarChar(30)
}
If there is no table in the database, write the model schema here first, and then execute npx prisma db push
to create the corresponding table in the database.
Remember.gitignore
added in.env
. If you are using SQLite, there is also/prisma/xxx.db
.
Insert data
Create the prisma/seed.ts
file for the initial data.
import { PrismaClient } from "@prisma/client";
let db = new PrismaClient();
async function seed() {
await Promise.all(
getSkills().map(joke => {
return db.skills.create({ data: joke });
})
);
}
seed();
function getSkills() {
return [
{
name: 'JavaScript'
},
...
]
}
Install the ts-node
package and execute the seed.
npm install --save-dev ts-node
For convenience, add package.json
"prisma": {
"seed": "ts-node prisma/seed.ts"
},
Then execute seed
npx prisma db seed
Use data
Create a utils directory under the app directory, and file utils/db.server.ts
import { PrismaClient } from "@prisma/client";
let db: PrismaClient;
declare global {
var __db: PrismaClient | undefined;
}
if (process.env.NODE_ENV === "production") {
db = new PrismaClient();
db.$connect();
} else {
if (!global.__db) {
global.__db = new PrismaClient();
global.__db.$connect();
}
db = global.__db;
}
export { db };
development
environment is that the connection instance is cached so that it will not restart every time
Use it on the previous resume/index.tsx
import { db } from "~/utils/db.server";
~
is configured by default in tsconfig.json in the Remix template, which represents the app directory.
Update loader method
export const loader: LoaderFunction = async () => {
const data: ResumeData = {
skills: await db.skills.findMany()
};
return data;
}
In this way, the basic Remix process goes through. From database to page.
In addition, I also replaced the original logo. Google drawing makes svg pretty easy to use.
code put on Github, and it will be continued later, there may be differences from the text.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。