通过上图可以看出,为了处理组件化的单页面SEO功能,我们不得不添加一个node Serve 层,然后把后端接口在serve层渲染一遍,再对比客户端渲染,然后展现出界面。如果不去计较性能,通过实践证明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会调用控制器配置,每个路由的方法名称必须和控制器里的文件名称匹配。
const 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配置代码如下:
const 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
const 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的功能。