Remix-run 新手教程

最近剛在 JavaScript Weekly 看到了 Remix.run(以下簡稱 Remix) 準備開源發布 1.0 版本。沒過兩天就看到 Remix 飆到 Github Trending 趨勢榜第一了。感覺是已經火了啊,不知道後續跟 Next.js 比怎麼樣。不過看起來不算太複雜,很多東西都封裝起來了,語法很輕。所以準備學習一下,順便做點學習筆記。

創建項目

從 npm 下載 remix 最新版並生成項目。

npx create-remix@latest

? Where would you like to create your app? my-cv

我準備做個展示簡曆的 Web 應用,動態顯示項目經曆,這樣還算有點需求,不然單純只是個 Demo,畢竟沒有需求就沒法好好深入學習。而且 SSR(Server Side Render 服務端渲染) 的特色就是方便 SEO,做個展示動態數據類的應用是最適合的。命名my-cv

? Where do you want to deploy? Choose Remix if you're unsure, it's easy to change deployment targets.

當然選擇原汁原味的 Remix App Server 了

? TypeScript or JavaScript? TypeScript

我選擇了 TypeScript。其實我個人的項目一般不選擇 TypeScript,不過這次還需要學習以下,就盡量模擬的更正式一些。對於個人開發者來說 TypeScript 弊大於利,雖然確實可以有效減少錯誤,和找錯誤的時間成本,但是定義類型等啟動項目時準備的時間更多,還有好不容易找到的冷門庫不支持 TS 的風險。

? Do you want me to run npm install? Y

最後安裝就行了。

啟動項目

進入項目目錄

cd my-cv

啟動起來看看

npm run dev

這裏 Node 版本 12 會報錯,16 沒問題。

"Could not locate @remix-run/serve. Please verify you have it installed to use the dev command."

可以訪問http://localhost:3000了。 直接帶有一個 Demo,展示了路由的各種狀態,404,401 之類的,還有帶參數的路由。可以留著參考,也可以刪掉。

創建頁面

這個 Demo 樣式還行,就留著了,反正自己寫樣式對於學習 Remix 沒有太大意義。所以我把導航改成中文,然後第二個頁面改成一個新路由,一會可以創建它,用來展示簡曆。然後第三個 Github 的連接改成自己的了。

<ul>
  <li>
    <Link to="/">首頁</Link>
  </li>
  <li>
    <Link to="/resume">簡曆</Link>
  </li>
  <li>
    <a href="https://github.com/tychio">GitHub</a>
  </li>
</ul>
複制代碼

然後,創建對應的頁面。

mkdir app/routes/resume
touch app/routes/resume/index.tsx
複制代碼

然後填入一些靜態文本,名字和介紹。還有技能,這個可以用載入動態數據來做,先做前端部分,直接從字面量返回。利用useLoaderData返回數據。

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>
  );
}
複制代碼

注意:這裏的loader是被後端 API 鉤子useLoaderData調用的,所以看不到使用

我還定義了ResumeData類型用於該頁面的動態數據,它包含了skills

使用數據庫 ORM

下一步,找一個 ORM,把數據徹底放在數據庫裏。我選擇了 Prisma,

npm install --save-dev prisma

npm install @prisma/client

初始化 ORM

npx prisma init --datasource-provider mysql

我選擇了 mysql,你可以直接使用 SQL Lite npx prisma init --datasource-provider sqlite

然後在添加的.env文件裏設置DATABASE_URL

mysql://<username>:<password>@<host | localhost>:<port>/<database_name>

然後執行 npx prisma db pull 讀取數據庫並自動生成 schema。

再執行npx prisma generate生成客戶端。 這樣就可以通過以下代碼使用 ORM。

import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
複制代碼

創建錶

我提前創建了 skills 錶,所以剛才 pull 的時候,在prisma/schema.prisma文件裏就有了 model。

model skills {
  id   Int     @id @default(autoincrement())
  name String? @db.VarChar(30)
}
複制代碼

如果數據庫中沒有的錶,先在這裏寫上 model schema,再執行npx prisma db push就可以在數據庫中創建對應的錶。

記得在.gitignore裏添加.env。如果使用的 SQLite,還有/prisma/xxx.db

插入數據

創建prisma/seed.ts文件,用於最初的數據。

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'
    },
    ...
  ]
}
複制代碼

安裝ts-node包執行 seed。

npm install --save-dev ts-node

方便起見,在package.json中加入

"prisma": {
  "seed": "ts-node prisma/seed.ts"
},
複制代碼

然後執行 seed

npx prisma db seed

使用數據

在 app 目錄下創建 utils 目錄,以及文件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環境的區別是緩存了連接實例,這樣不會每次重啟

在之前的resume/index.tsx頁面使用它。

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

~是默認在 Remix 的模板中 tsconfig.json 配置的,代錶 app 目錄。

更新 loader 方法

export const loader: LoaderFunction = async () => {
  const data: ResumeData = {
    skills: await db.skills.findMany()
  };
  return data;
}
複制代碼

這樣基本的 Remix 流程就走通了。從數據庫到頁面。

另外我還替換了原來的 logo。穀歌繪圖 製作 svg 還挺好用。

代碼放到 Github 上了,後面還要繼續,和文中可能會有差異。

版權聲明
本文爲 [程序員錚錚] 所創,轉載請帶上原文鏈接,感謝
https://cdmana.com/2021/11/20211126154131610t.html

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://cdmana.com/2021/11/20211126154131610t.html