最近用 Next.js 和 typeorm 完成了前端小白的第一个全栈项目,本文会记录我在做项目的过程中学习到的一些知识点,和遇到的那些奇奇怪怪的 Bug

Github - 献上源码地址

博客系统 - 献上预览地址,喜欢的话就留下一篇博客吧

上篇文章 - 记录了初始化项目的过程,这么文章初始化数据库


初始化数据库

什么是 ORM

ORM 是 Object–relational mapping 的简称,这个技术的作用是通过实例对象的语法,完成关系型数据库的操作的技术 从这个例子可以看出,ORM 的写法,明显更方便简洁

SELECT id, first_name, last_name, phone, birth_date, sex
 FROM persons 
 WHERE id = 10------ 改成 ORM 的写法
p = Person.get(10);
name = p.first_name;复制代码

TypeORM

Typeorm 是一个可以使用 JavaScript 和 Typescript 来操作数据库的库,目前是 0.2.30 版本,还没发布 v1.0.0 我本打算用 Sequelize.js,但是发现它对 TS 支持不好,于是选用了这个库,它有以下特点

  • 默认支持 TypeSciprt
  • 支持关联 Associations
  • 支持事物 Transactions
  • 支持数据库迁移 Migration

简单的介绍旧就说到着,开始敲代码吧

创建数据库

创建数据库目录

  1. 在项目目录里创建 blog-data 目录
  2. .gitignore 里添加 /blog-data/

启动 PostgreSQL

一句命令启动 pg

docker run -v "$PWD/blog-data":/var/lib/postgresql/data -p 5432:5432 -e POSTGRES_USER=blog -e POSTGRES_HOST_AUTH_METHOD=trust -d postgres:12.2复制代码

如果报错,可以看这篇教程,或者直接google 搜索吧

如果下载速度慢 先搜阿里云 Docker 镜像 (要登录阿里云),再搜 Docker 加速

启动完成后

docker ps -a // 这句话查看容器状态
docker logs 容器id 这句话查看启动日志复制代码

SQL 创建

一个成熟的 orm 框架一般会提供创建数据的 API,但是 Typeorm 并没有,那就只能手动了 ????

进入 docker 容器

docker exec -it 容器id bash 
// 容器id 可以通过 docker ps -a 查询复制代码

进入 pg

psql -U blog -W复制代码

由于启动 pg 的时候,设置成无需密码了,所以直接回车就能进入 如果需要加密码,可在 docker run 选项里面的 -e POSTGRES_HOST_AUTH_METHOD=trust 替换成 -e POSTGRES_PASSWORD=123456

创建数据库

按照正式的开发流程,我们需要创建三个数据库: 开发、测试、生产

分别是 blog_development、blog_test、 blog_production

CREATE DATABASE blog_development ENCODING 'UTF8' LC_COLLATE 'en_US.utf8' LC_CTYPE 'en_US.utf8';复制代码

一些常用的 pg 命令

\l 用于 list databases,展示数据库
\c 用于连接数据库
\dt 用于展示数据库中的table复制代码

此时使用 \l 命令,看到这样就是成功啦~Next.js + typerom 实践 - 博客系统(中)_Next.js

安装 TypeORM

安装依赖

yarn add typeorm reflect-metadata @types/node pg复制代码

修改 tsconfig

"compilerOptions": {"emitDecoratorMetadata": true,"experimentalDecorators": true,
}复制代码

运行 npx typeorm init --database postgres 初始化 Typeorm

这个命令会帮我们创建一些文件包括:

src
│   ├── entity        // 实体
│   │   └── User.ts
│   ├── index.ts
│   └── migration     // 迁移复制代码

其中 index.ts 和 User.ts 都是官方的例子,我们可以先删掉,后面根据自己需求再创建

最后在 ormconfig.json 中配置我们的数据库信息:

"username": "blog","password": "","database": "blog_development"复制代码

禁用 sync -- 重要配置

在 ormconfig.json 文件中将 "synchronize": "ture" 改为 "false"

如果是 true,那么在连接数据库时,typeorm 会自动根据 entity 目录来修改数据表

假设 entity 里面有 User,就会自动创建 User 表

看起来很方便呀,为什么要禁用呢

因为 sync 功能可能会在我们修改 User 时直接删数据Next.js + typerom 实践 - 博客系统(中)_typerom _02

这种行为绝对不能发生在生产环境,所以我们要一开始就杜绝 sync 功能

如何运行 TypeScript

矛盾

Next.js 默认使用 babel 来将 TS 编译为 JS (内置功能)

TypeORM 推荐使用 ts-node 来编译 (没有内置)

babel 和 ts-node 对 TS 的支持并非完全一致

所以我们统一使用 babel 来编译 TS

安装 babel

先将 Node.js 升级到 v14,然后安装 @babel/cli yarn @babel/cli

然后使用 babel 将 src 中的 TS 文件编译为 JS

npx babel ./src --out-dir dist --extensions ".ts,.tsx"复制代码

敲击回车,啪,很快哟

但是没成功,还报了一堆错

Next.js + typerom 实践 - 博客系统(中)_Next.js_03

经验告诉我,遇到错误不要慌

抓住错误使劲搜

Support for the experimental syntax 'decorators-legacy' isn't currently enabled

经过几个小时的搜索终于有结果了 ????

Next.js + typerom 实践 - 博客系统(中)_Next.js_04

I had the same problem

那就跟着操作做吧

安装插件

yarn add --dev @babel/plugin-proposal-decorators复制代码

接着是修改 .babelrc 文件,我们没有,那就创建一个

现在在 next.js 的官网中,查到默认配置,然后加上答案的配置

{ "presets": ["next/babel"], "plugins": [
  ["@babel/plugin-proposal-decorators", { "legacy": true }]
 ]
}复制代码

重新运行刚刚失败的命令Next.js + typerom 实践 - 博客系统(中)_typerom _05

成功啦~

那么问题来了,编译后的 JS 代码在哪里呢?

--out-dir dist --extensions ".ts,.tsx" 看看运行的命令 --out-dir dist 那当然是 dist 文件了

此时直接运行 node dist/index.js 还是出现报错了

修改 ormconfig.json

因为ormconfig.json 还是默认配置,我们运行 node dist/index.js 还是会运行 src 下的 entity、migrations、subscribers  文件

修改 ormconfig

"entities": [  "dist/entity/**/*.js"],"migrations": [  "dist/migration/**/*.js"],"subscribers": [  "dist/subscriber/**/*.js"]复制代码

再次运行 node dist/index.js 成功啦!

工作流总结

步骤

  • 统一让 Next.js 和 TypeORM 使用 babel 翻译 TS
  • 每次修改 src 的 TS 代码后,翻译为 dist 里面的 JS
  • 使用 node 运行 dist 里面的 JS,执行 TypeORM 任务

Next.js + typerom 实践 - 博客系统(中)_typerom _06


这篇文章记录了数据库的初始化过程,那么下篇文章一起来使用 TypoORM 操作数据库吧