/技术
分类:技术最近更新:2026-04-15浏览:1169
目前公司很多项目都是 SaaS,或者 PaaS 平台,我们能够很熟练的通过 React 或者 Vue 脚手架实现单页面 SPA 的方式实现项目功能。如果有天需求 SEO,要求网页方便搜索引擎优化的时候,前后端分离的架构方式就会受到阻碍。为了解决这样的问题,市场上出现了 Nuxt、Next、SSR 等,在界面、接口中间添加了一层服务器预渲染的过程。
大部分逻辑如下图:

通过上图可以看出,为了处理组件化的单页面 SEO 功能,我们不得不添加一个 Node Server 层,然后把后端接口在 Server 层渲染一遍,再对比客户端渲染,然后展现出界面。如果不去计较性能,通过实践证明 SEO 效果并不是特别理想。如我们的公司国际官网和公司官网。在开发的过程我们发现,我们只是为了实现目的而做这样的事情,而忽略了 SEO 类型的网站本身应该用什么样的方式处理最好,所以我们开始怀恋最原始的 PHP 生成的伪静态,或者其他后端语言直接嵌套 HTML 代码,回到那个 JQ 流行的时代。
所以我们决定回到原点,重新思考以后公司前端 SEO 网站的框架该如何选型,前后端分离肯定以成定局,如果要实现伪静态的方式,必须借助 Node 服务做中间层,然后选择一个好的前端模板引擎,就能实现 SEO 效果,这也是最近流行技术 BFF 的应用。如下图

如图所示,客户端请求页面,路由受 koa-router 控制,匹配到路径规则后,加载控制器,控制器中获得后端接口提供的数据并把数据变量整合到 art 模板引擎里,配合其他静态资源返回给客户端。
目前市场上的模板引擎已经很多,对比了很多引擎,觉得 art-template 相对合适。主要看中的还是它的渲染速度。art 开发文档说明

仓库地址:https://github.com/chanlan253/253ssr
Node、Gulp、Koa、jQuery、Less
配置文件 gulpfile.js,主要打包 js、css、图片等静态资源,src/views/static 的静态资源打包到目标目录 dist 里,注意 dist 是 git 忽略目录。Gulp 分开发环境和打包环境,开发环境有监听能力,静态资源有变化就会重新编译资源。
路由配置放在目录 src/router 里,pageRouter.js 控制,apiRouter.js 是调试用的,可以忽略。pageRouter.js 会调用控制器配置,每个路由的方法名称必须和控制器里的文件名称匹配。
javascriptconst Router = require("@koa/router"); const PageRouter = new Router(); const controller = require("../controller"); PageRouter.get(["/", "/home"], controller.home); PageRouter.get("*", controller["404"]); module.exports = PageRouter;
控制器全部放置在目录 /src/controller 里,除 index.js 其他后缀名为 .js 的文件都会加载成控制器的方法,index.js 配置代码如下:
javascriptconst fs = require("fs"); const path = require("path"); const fileLists = fs.readdirSync(path.join(__dirname, "./")); const ctrlList = fileLists.filter(item => { return /^(?!.*index).*\.js$/i.test(item); }); let controller = {}; ctrlList.forEach(item => { let namekey = item.replace(/\.js$/, ""); controller[namekey] = require(`./${item}`); }); module.exports = controller;
控制器函数参数(ctx, next)ctx 在 Koa 的基础上添加了 $http 和 render 方法;
ctx.$http 实现 axios 所有功能,方便向后端接口请求数据源。
ctx.render 实现了模板引擎控制的功能,并把数据源结合到模板里。
art-template 配置文件在 /src/config/artTemp.config.js
javascriptconst path = require("path"); const isDev = process.env.NODE_ENV == "development"; module.exports = { root: path.join(__dirname, "../views/template"), extname: ".art", htmlMinifierOptions: { collapseWhitespace: true, minifyCSS: !isDev, minifyJS: !isDev, ignoreCustomFragments: [] }, minimize: !isDev, cache: !isDev, debug: isDev };
仓库就是一个简单的案例,可以根据项目需求进行调整。比如 Gulp 很多时可以添加子文件配置。控制器目录可以添加目录作为命名空间,apiRouter 可以扩展数据库,实现类似 Egg 的功能。
下一篇:前端脚手架如何搭建