首页 > 技术文章 > koa+ts搭建ssr后端

thyong 2020-07-13 00:22 原文

前言

此文为ssr三步曲的第三部,前文在这
这篇文章的代码有2个分支:tag-v3-pretag-v3

搭建步骤

之前写过一篇文章,koa+mongodb搭建后端,里面写的更详细一些,有兴趣的可以翻出来看看,只不过文末一部分一直搁置未完篇,因为一行行写起来比较繁琐,后面又比较忙。(说白了,是懒,哈哈)

此处我们简单一点,用koa+koa-router搞一个后端路由出来即可,话不多说,那就开始吧。。

安装依赖

npm i koa @koa/router koa-bodyparser koa-static art-template koa-art-template log4js chalk

node端的模板引擎推荐art和nunjucks,art简洁、速度快,而nunjucks属于富功能模板引擎,功能更加强大,有layout、block、全局函数/变量、模板继承等等。
不过事情刚开始嘛,我们的需求是很简单的,杀鸡焉用牛刀,所以选择art

@koa/router,是koa团队接手了koa-router之后维护的类库,koa-router停留在了7.x,而@koa/router也是直接从8.x开始

log4js: 日志是少不了的,所以log4js来一个吧

chalk: 让控制台输出更漂亮

再安装一下types

npm i -D @types/koa @types/koa__router @types/koa-bodyparser @types/chalk

接下来就不贴具体的代码了,只阐述一下思路,代码在github上有按分支存档,文中会对应说明

如何运行

如果是普通nodejs,我们可以用nodemon+ts-node来调试:

npm i ts-node
// nodemon很多地方用的上,所以直接全局安装吧
"devServer": "nodemon --watch src -e ts,tsx,js,json --exec node --inspect=127.0.0.1:9229 -r ts-node/register ./src/server/app.ts",

最简单的一个例子就是koa路由里,使用renderToString,来渲染一个jsx,返回渲染后的string给前端。
但如果直接运行的话,是会报错的,因为有以下几个问题需要解决:

  1. nodejs不支持import/export语法

    两个方案:

    1. 使用babel转,速度会拖慢
    2. node9开始多了一个特性:--experimental-modules,node运行的时候启用这个选项,并且文件名需要为.mjs后缀
  2. nodejs不支持tsx语法
  3. 组件内部导入scss之类的文件在node端会报错
  4. 打包出来的js, css如何注入
  5. 服务端数据如何注入到客户端

node是没办法对tsx, scss之类的做处理的,所以,webpack登场了,除了前端代码,后端代码同样需要用webpack来进行打包,主要有以下几点区别:

webpack:

  1. webpack的target需要设置成node
  2. css、scss使用ignore-loader忽略掉
  3. 使用loadable来拆分文件、做服务端渲染

    loadable真是神器,没有这个的话,就只能用manifest loader来生成资源清单,并且没有拆分功能

  4. 服务端数据注入到客户端比较简单了,直接往window对象插入一个对象,比如ssrData = {},然后前端初始化store的时候合并一下initState即可

初始版本

总的来说,我们需要跑3个命令:

  1. 编译客户端并watch
  2. 编译服务端并watch,服务端对client端生成的文件做静态资源处理
  3. 用nodemon之类的工具,watch服务端生成的文件,有变更时自动重启

到这里,其实生产环境的ssr已经完成了,因为ssr我们就是对客户端、服务端分别进行打包,然后node运行服务端的代码启动服务。
这个版本的代码详见:https://github.com/Thyiad/react-ssr/tree/tag-v3-pre

进化版本

上一个版本在生产环境没问题,开发环境简直不能忍啊。因为css更新不会自动刷新、js更新不会自动刷新,干啥都需要手动刷新一下浏览器。。
所以我们想办法改良一下,用一个脚本解决,这个命令干了这两个事情:

  1. webpack编译客户端,并手动启一个webpackDevServer
  2. webpack编译服务端,并监听hooks.done,在done之后启一个node,启动服务

    启动新进程可以用child_process.spawn或者cluster,此处我们使用child_process即可。
    cluster是基于child_process.fork启动若干子进程,再有一个agent来调配,通过IPC通信,功能更强大,但貌似官方其实不是很推荐,我看到生产中更多人选择的是pm2等工具。
    就算css变更也同样会触发hooks.done,所以我们改进一下,nodemon只监听后端生成的js,有变更才杀掉旧的子进程,启动一个新的子进程

这个版本同样进行了一些其他的优化,比如把配置文件提取到一个create-config.js中,客户端服务端都调用该函数生成config。同时命令简化成2条,dev和build分别用来启动本地调试和打包生产代码。
这个版本的代码详见:https://github.com/Thyiad/react-ssr/tree/tag-v3

还欠缺的

  • 前文中所述的服务端数据注入到客户端、服务端获取数据

    这两个其实都比较简单,所以只加了todo备注,没有填充代码

  • ui库加入

    比如可以加入ant design,还有最近发现微软的fluentui也不错,感觉可以后面试用一下

  • 封装成一个cli工具

    在上述完善后,可以封装一个cli工具,支持生成spa、ssr、不同ui的项目代码

小结

整个过程其实也踩了不少坑,webpack的配置还是挺多的,不过只要你耐心根据需要把官网文档翻一遍,基本上也没啥问题。

上次看到有人开玩笑说现在多了一个工种:webpack配置工程师..

vue生态的vite最近更新特别频繁,等稳定下来可以尝试一下,这些工具都是一代比一代简化,希望以后在配置方面能更简化、节省精力吧。。

推荐阅读