在 ts + react 系列 中,数据都是本地的
mock
,那么如何搭建一个真实的
API server
呢?
按照惯例,先搭建一个基于
ts + express
的服务端开发环境:
初始化
express-generator
express-generator:快速创建 Express
应用程序框架。
可以使用
npx
命令(在
Node.js 8.2.0
中可用)运行应用程序生成器。
$ npx express-generator ts-express
对于早期的
Node
版本,可将应用程序生成器作为全局
npm
软件包安装,然后启动它。
$ npm install -g express-generator
$ express ts-express
typescript
安装 typescript
$ npm i -D typescript
生成配置文件 tsconfig.json
$ tsc --init
工程改造(js2ts)
将工程里的
.js
文件 都重命名为
.ts
文件。
bin/www
是整个服务端的启动脚本。
// bin/www
// 修改服务端端口 3000 -> 40001
var port = normalizePort(process.env.PORT || "4001");
改完之后,肯定出现了大量报错,莫慌,我们一起来修改:
Cannot find name ‘require’.
require
未定义,因为缺少声明文件
$ npm i --save-dev @types/node @types/express
参数类型未定义
express
声明文件最终的导出方式是
export =
,它对应的导入方式是
import =
/
import from
/*
** node_modules/@types/express/index.d.ts
*/
...
export = e;
而我们的导入方式是
require
/*
** app.ts
*/
var express = require("express");
统一将模块的导入改为
import from
,并安装声明文件
$ npm i -D @types/http-errors @types/cookie-parser @types/morgan @types/debug
app.use
export interface IRouterHandler<T> {
(...handlers: RequestHandler[]): T;
(...handlers: RequestHandlerParams[]): T;
}
app.use
参数的类型是一个函数重载,但是
error handler
传入四个参数时,并没成功定位到
ErrorRequestHandler
类型。所以我们加一个类型断言
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get("env") === "development" ? err : {};
// render the error page
res.status(err.status || 500);
res.render("error");
} as express.ErrorRequestHandler);
对象可能为 null
添加类型保护
addr?
function onListening() {
var addr = server.address();
var bind = typeof addr === "string" ? "pipe " + addr : "port " + addr?.port;
debug("Listening on " + bind);
}
参数 “val” 隐式具有 “any” 类型
指定
string
类型
function normalizePort(val: string) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
参数 “error” 隐式具有 “any” 类型
指定
any
类型
function onError(error: any) {
...
}
编译 ts2js
因为
node
是不可以编译
ts
文件的,所以
build
时需要编译
.ts
为
.js
- 指定输出目录
// tsconfig.json { "compilerOptions": { "outDir": "./dist" } }
- 添加脚本
{ "scripts": { "build-ts": "tsc" } }
拷贝静态资源/模版文件
文件的拷贝工作通过
shell
脚本实现。
- 安装
shelljs
npm i -D shelljs @types/shelljs
- 在根目录上新建
copyStatic.ts
// copyStatic.ts import * as shelljs from "shelljs"; // -R:递归 shelljs.cp("-R", "public", "dist"); shelljs.cp("-R", "views", "dist");
- 添加运行脚本
// package.json { "script": { "copy-static": "ts-node copyStatic.ts" } }
需要提前安装ts-node
$ npm i -D ts-node
npm run build
添加
build
脚本
// package.json
{
"script": {
"build-ts": "tsc",
"copy-static": "ts-node copyStatic.ts",
"build": "npm run build-ts && npm run copy-static"
}
}
编译时,排除
copyStatic.ts
// tsconfig.json
{
"exclude": ["copyStatic.ts"]
}
启动服务器
// package.json
{
"script": {
"start": "node /dist/bin/server.js"
}
}
$ npm start
打开
http://localhost:4001/
,就可以看到
express
页面了。
watch 监控模式
是一个自动重启
nodemon
应用的工具,当监听的文件或监听目录下的文件发生修改时,自动重启应用。
node
我们修改文件后,第一步需要重新
build
,第二步需要重启服务。
nodemon
让我们开发时只需关注代码即可,不再需要手动重启服务。
- 安装
nodemon
$ npm i nodemon -D
- 配置脚本
// package.json { "script": { "start": "node ./dist/bin/server.js", "watch": "nodemon ./dist/bin/server.js" } }