Remix.run 新手教程

程式設計師錚錚發表於2021-11-30

最近剛在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
  • Express Server
  • Architect (AWS Lambda)
  • Fly.io
  • Netlify
  • Vercel
  • Cloudflare Workers
    當然選擇原汁原味的Remix App Server了
? TypeScript or JavaScript?
TypeScript
  • JavaScript
    我選擇了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上了,後面還要繼續,和文中可能會有差異。

相關文章