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
  • 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还挺好用。

remix.png

代码放到Github上了,后面还要继续,和文中可能会有差异。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容