一点都不低成本的转码器
一个低成本兼容现有业务系统的 Vue & PHP 直出方案,然而此刻发现它不是那么的实用,因为这个方案的出发点就很浑浊。
#为什么
基本上是纯粹的工作需要,需要重构公司 X 项目,老项目 jQuery vue.js Vue2 鱼龙混杂,由于历史和实际原因,无法在生产环境上 Node.js,所以需要探索一套方案,满足下面需求:
- 保证以
vue-cli初始化的 Webpack 项目作为基本开发方式 - 满足服务端渲染的需求
- 保证服务端稳定、高可用
#做什么
实际上业务中的需求有这些:
- 路由由服务端管理,也意味着客户端一般都是以单页面应用为单位
- 仅需要服务端渲染关键性数据,可以循环渐进地实现转换
- 有可能需要转换出多语言版本的模板,所以工具需要可配置
#谁做了
总结了下,目前社区能找到的各种方案及我要实现的方案如下:
#1. SPA
也就是官方的 SPA 模式,不多赘述。
#2. node-ssr-render
也是基于官方提供的 SSR 解决方案,由于一些设计和实现问题,目前运行效率太低,CPU 和 内存一定会牺牲一个参数,基本无法用于生产环境。
#3. php-ssr-render
来自 GitHub 的国内开发者可发的 PHP 版本的 Vue 渲染器,简单说就是把 node-ssr-render 的核心渲染机制用 PHP 重新实现一边,但是由于开发跟进和兼容等问题,无法满足稳定高可用的需求。
项目及地址: vue-php
#4. node-transfer
也就是我正在做的事,简单说就是写一个 Node.js 解析器,把 .vue 文件转码为 .php 模板文件,拿去给 PHP 渲染输出,同时加载 Vue SPA 项目本身的 Js 脚本,剩下的流程就和 vue ssr render 基本一致了。
最新补充:其实这件事不是想的那么简单,严格说应该是 SSR + Transfer。
#怎么做
OK,Js 脚本问题通过 Webpack 本身就可以解决了,剩下的就是解析器怎么做。
首先,将 .vue 文件解析为 .php 可以有三个思路:
#1. 正则
将 .vue 文件的模板模板读取,直接使用正则将不同的指令替换为 PHP 相关语句,如遇到类似组件之类的,则根据配置好的路径对相应组件进行替换,同时需要对 props 进行处理。
此方法可能无法实现完全的转换,如遇到 slot 之类的组件就懵逼了。
#2. AST
同样的读取模板,将模板使用工具转换为 AST(抽象语法树),之前尝试了一些开源的解析器去解析,但是目前探索到的最佳方案应该是 Vue 官方提供的 vue-template-compiler 。
严格说这是一个编译器,能把我们的单文件 Vue 组件编译为 render 函数,同时也支持 AST 模板数据的输出。
抽象为 AST 后,所有的组件就变成一个 JSON 树,我们就可以对这个树进行递归循环处理,最终产出 PHP 代码。
#3. VNODE
上图中的 4 种方案里,3 和 4 都是自建了 vDom 环境,将各种组件之间的关系计算完成后输出的 HTML,实际上自建 vDom 就意味着又遇到了上面的 开发跟进、兼容性问题上,而且 vDom 的最终输出可能并不是我们所需要的 “模板”,所以这个方法暂时不考虑。
2017-09-07 补充:
这件事比我想象中的复杂大概有10倍,最终代码大概 1500 行,耗时一个月。
最终使用了一个比较 “复杂” 的方案:
.vue组件 >vue-template-compiler>ssrRenderssrRender>esprima>js-astjs-ast>estraverse(各种替换/解析处理)>result-js-astresult-js-ast>escodegen>result-ssrRenderresult-ssrRender>vue-server-rander>html-php-code- 递归处理
html-php-code中无法解析的vnode(component)>html-php-code
其中还涉及针对组件本身的依赖和解析的复杂处理
相关工具:
- esprima: link (将代码转换为标准 AST)
- espree: link
- escodegen: link (将 AST 生成为标准 Code)
- estraverse: link (遍历并且更新抽象语法树)
相关资料:
AST 三板斧:
- 通过
esprima把源码转化为 AST - 通过
estraverse遍历并更新 AST - 通过
escodegen将 AST 重新生成源码
esprima 文档:
- http://esprima.readthedocs.io/en/latest/getting-started.html#using-node-js-to-play-with-esprima
- http://www.cnblogs.com/ziyunfei/p/3183325.html
- http://blog.csdn.net/dear_mr/article/details/72587908
已有实践:
- flowjs: https://github.com/channg/flowjs/blob/master/src/esparse.js
- js2php: https://github.com/endel/js2php/blob/master/index.js#L1
剩下的,我抽时间写一个详细的实现思路。
完。






~~~
回复:
哇哦~
大神,收下小弟的膝盖
grbrgg
😃
...
哈哈 加油 博主棒棒哒
这是你大半夜不睡觉的理由么。。。