{"id":13564378,"url":"https://github.com/surmon-china/vue2any","last_synced_at":"2025-10-03T01:31:23.776Z","repository":{"id":66215116,"uuid":"123084819","full_name":"surmon-china/vue2any","owner":"surmon-china","description":"把 vue 组件转换为任何 web 类模板","archived":true,"fork":false,"pushed_at":"2018-11-05T05:00:08.000Z","size":2513,"stargazers_count":33,"open_issues_count":0,"forks_count":3,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-09-29T07:21:28.416Z","etag":null,"topics":["ast","ejs","escodegen","esprima-ast","estraverse","html-template","js2php","php","surmon","surmon-china","template","vue"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/surmon-china.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-02-27T06:38:03.000Z","updated_at":"2023-11-03T17:13:16.000Z","dependencies_parsed_at":null,"dependency_job_id":"6a532fc4-ac76-4e5b-aa37-2dec4cf320b3","html_url":"https://github.com/surmon-china/vue2any","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/surmon-china%2Fvue2any","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/surmon-china%2Fvue2any/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/surmon-china%2Fvue2any/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/surmon-china%2Fvue2any/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/surmon-china","download_url":"https://codeload.github.com/surmon-china/vue2any/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235059234,"owners_count":18929279,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ast","ejs","escodegen","esprima-ast","estraverse","html-template","js2php","php","surmon","surmon-china","template","vue"],"created_at":"2024-08-01T13:01:30.398Z","updated_at":"2025-10-03T01:31:23.370Z","avatar_url":"https://github.com/surmon-china.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# vue2any\nTransfer vue file to any language code.\n\n## 解决方案\n\n1. ast（已暂停）\n2. ssrRender（已暂停）\n3. ssrRenderAst（最终方案）\n\n## todo\n\n1. ~~v-if v-else-if v-else 三目运算 AST的抽象及转译~~\n2. ~~list 内部嵌套的解析~~\n3. ~~组件的嵌套解析~~\n4. ~~slot的解析处理~~\n5. ~~局部组件依赖的处理（组件会被解析为一个`vnode`而非`string` + `vue`文件内的依赖需要转化）~~\n6. ~~全局组件的处理~~\n7. ~~组件 + v-if 的处理（三目运算的计算从正则迁移至AST即可解决）~~\n8. ~~动态组件 \u003ccomponent :is=\"componentName\"\u003e\u003c/component\u003e~~\n9. 特殊工具方法的处理\n\n## 工作原理\n\n1. `.vue` 组件 =\u003e `vue-template-compiler` =\u003e `ssrRender`\n2. `ssrRender` =\u003e `esprima` =\u003e `js-ast`\n3. `js-ast` =\u003e `estraverse(各种替换/解析处理)` =\u003e `result-js-ast`\n4. `result-js-ast` =\u003e `escodegen` =\u003e `result-ssrRender`\n5. `result-ssrRender` =\u003e `vue-server-rander` =\u003e `html-php-code`\n6. 递归处理 `html-php-code` 中无法解析的 `vnode(component)` =\u003e `html-php-code`\n\n**核心问题：**\n\n1. js 方法无法转换为 PHP 方法\n2. 组件的依赖无法被捕获\n\n**相关工具：**\n- esprima: http://esprima.org/demo/parse.html#(将代码转换为标准 ast)\n- espree: https://github.com/eslint/espree\n- escodegen: https://github.com/estools/escodegen(将ast生成为标准code)\n- estraverse: https://github.com/estools/estraverse(遍历并且更新抽象语法树)\n\n**相关资料:**\n\nAST三板斧：\n\n- 通过 esprima 把源码转化为AST\n- 通过 estraverse 遍历并更新AST\n- 通过 escodegen 将AST重新生成源码\n\nesprima文档: http://esprima.readthedocs.io/en/latest/getting-started.html#using-node-js-to-play-with-esprima\nhttp://www.cnblogs.com/ziyunfei/p/3183325.html\nhttp://blog.csdn.net/dear_mr/article/details/72587908\n\n**已有实践：**\n- flowjs: https://github.com/channg/flowjs/blob/master/src/esparse.js\n- js2php: https://github.com/endel/js2php/blob/master/index.js#L1\n\n解决痛点：通过专业的语法解析工具，避免了单薄可用性低的正则匹配，且可以根据不同的(ES默认方)法来定制转译后的 PHP 方法，以支持 PHP 基本方法的使用，可以参考 js2php\n\n## 如何安装\n\n```bash\nnpm i vue-to-any --save\n```\n\n## 基础使用\n\n```javascript\nconst VueToAny = require('vue-to-any')\n\n// 实例化（options部分可选）\nconst vueToAny = new VueToAny({\n\n  // 目标语言（default: php）\n  language: 'php',\n\n  // 转译使用的服务端通讯字段，无需$等特殊符（default: PHPDATA）\n  variable: 'PHPDATA',\n\n  // 文件是否压缩后输出（default: false）\n  minify: false,\n\n  // 是否展示调试信息\n  debug: false,\n\n  // 是否输出进度\n  progress: true,\n\n  // 分别为 [ 入口/出口 ] 文件的 [ 路径和文件名字 ]（必须指定，默认指向开发文件夹）\n  entryFile: path.join(__dirname, '/..', '/test', '/vue/', 'Test.vue'),\n  outFile: path.join(__dirname, '/..', '/test', '/out/', 'test.php')\n})\n\n// 执行转换输出转换\nvueToAny.generate()\n```\n\n## 进阶使用\n\n```javascript\nconsole.log(vueToAny)\n\n// 插件/中间件（可选），方便分别对 [ 转译前/后 ] 的数据进行中间处理\n\n// 处理转译前的 [ ssrRender ] 数据\nvueToAny.useMiddleware('before', ssrRender =\u003e {\n  return ssrRender\n})\n\n// 处理转译后的 [ targetLangCode ] 数据\nvueToAny.useMiddleware('after', resultTemplate =\u003e {\n  return resultTemplate\n})\n\n// 移除指定中间件（注意：如果要想移除指定某个中间件，则之前 use 时需要传入函数名字，而不是一个匿名函数实体）\nvueToAny.delMiddleware('after', oldAfterMiddleware)\n\n// 移除所有编译后中间件\nvueToAny.delMiddleware('after')\n\n// 移除所有中间件\nvueToAny.delMiddleware()\n\n// 添加不同语言版本的转译器（参考：transfers/php.js）\nvueToAny.addTransfer({\n  'ejs': ejsTransfer\n})\n\n// 设置使用哪个语言版本进行工作\nvueToAny.setTransfer('ejs')\n\n// 更新实例配置对象\nvueToAny.updateOptions({ ...newOptions })\n```\n\n## 使用限制（待完善）\n\n1. 所有组件内数据的引用均不受任何限制\n2. 所有组件内引用的服务端数据（即约定通信字段），均不能 [ 包含  ] 任何 js 计算\n3. 暂时不支持组件内部引入包含依赖`window`对象的js文件或库\n4. 组件内部对外部资源的引用比如遵循下面规则：\n    - 引用组件必须用 `import` 语句引入 `.vue`结尾的相对路径\n    - 引用其他资源必须用`require`语句 \n    - 全局组件由于转译器不能识别，所以要自己加一个叫 `config`的`block`，以`json`的形式配置路径\n\n**假设以`SERVERDATA`字段为约定字段：**\n\n### 不支持的形式：\n\n```html\n\u003cdiv v-text=\"parseMethod(SERVERDATA.xxx.content)\"\u003e\u003c/div\u003e\n\u003cdiv\u003e{{ SERVERDATA.xxx.content + '222' }}\u003c/div\u003e\n\u003cimg class=\"php-img\" :src=\"SERVERDATA.imgSrc || '22'\" alt=\"a image\"\u003e\n\u003cimg class=\"php-img\" :src=\"SERVERDATA.imgSrc ? SERVERDATA.imgSrc : localImage\"\u003e\n\u003cul\u003e\n  \u003cli class=\"item\" v-for=\"(item, key) in SERVERDATA.arr.filter(a =\u003e !!a.id)\"\u003e\n    \u003cdiv\u003e{{ item.abc + 'string' }}\u003c/div\u003e\n  \u003c/li\u003e\n\u003c/ul\u003e\n```\n\n\n### 支持的形式：\n\n- 数据输出\n- 数据绑定\n- 数据翻转 (!PHPDATA.xxx)\n- 基本的计算符 (PHPDATA.xxx === 'xxx') (PHPDATA.xxx \u003c 'xxx')\n- 动态 class、style 在 object || array 形式的时候允许和本地数据混合使用\n- 列表输出\n- 各种嵌套\n- 依赖的组件调用\n- transition-group 里的 v-for 元素（包括组件），要加属性：`trnasfer=\"group\"`\n\n```html\n\u003cdiv\u003e{{ SERVERDATA.name }}\u003c/div\u003e\n\u003cinput type=\"text\" v-model=\"SERVERDATA.name.model\"\u003e\n\u003cdiv v-text=\"SERVERDATA.arr.content\"\u003e\u003c/div\u003e\n\u003cdiv v-html=\"SERVERDATA.arr.xxx\"\u003e\u003c/div\u003e\n\u003cdiv v-show=\"SERVERDATA.isShow\"\u003eshow\u003c/div\u003e\n\u003cdiv v-if=\"SERVERDATA.isRender\"\u003eshow\u003c/div\u003e\n\u003cdiv v-else-if=\"SERVERDATA.isRenderElse\"\u003eshow\u003c/div\u003e\n\u003cdiv v-else\u003enot show\u003c/div\u003e\n\u003cdiv class=\"static-class\" :class=\"{ \n  active: SERVERDATA.active, first: localData \n}\"\u003e\u003c/div\u003e\n\u003cdiv class=\"static-class\" :class=\"[\n  SERVERDATA.active ? 'active': '', 'static-class', localFitst ? 'first' : ''\n]\"\u003e\u003c/div\u003e\n\u003cdiv class=\"static-class\" :style=\"{ \n  background: SERVERDATA.bg,\n  fontSize: localData.fontSize\n}\"\u003e\u003c/div\u003e\n\u003cul\u003e\n  \u003cli class=\"item\" v-for=\"item in SERVERDATA.arr\"\u003e\n    \u003cdiv\u003e{{ item.abc }}string\u003c/div\u003e\n  \u003c/li\u003e\n\u003c/ul\u003e\n\u003cul\u003e\n  \u003cli class=\"item\" v-for=\"(item, key) in SERVERDATA.arr\"\u003e\n    \u003cdiv\u003e{{ item.abc }} - {{ key }}\u003c/div\u003e\n    \u003cdiv\u003e嵌套循环\u003c/div\u003e\n      \u003cdiv v-for=\"children in item.childrens\"\u003e\n        {{ children.name }}\n      \u003c/div\u003e\n    \u003c/div\u003e\n  \u003c/li\u003e\n\u003c/ul\u003e\n```\n\n## 相关指令\n\n```bash\n# 安装依赖\nnpm install\n\n# 进入开发模式\nnpm run dev\n\n# 构建\nnpm run build\n\n# 测试脚本\nnpm run test\n```\n\n## 目录结构\n\n```\nnuxt.js-blog/\n   |\n   ├──src/                     * 主程序\n   │   │\n   │   │──index.js             * 核心类\n   │   │\n   │   └──transfers            * 不同语言的转译器方法\n   │   │\n   │   └──solution(render-ast) * 核心解决方案\n   │       │\n   │       │──build.js         * vue-server-render 的衍生版\n   │       │\n   │       │──parses.js        * 对 ast 函数的匹配和替换\n   │       │\n   │       └──generate.js      * ast 抽象 + vm 创建 / 文件分析 / 依赖分析 / 转换执行\n   │\n   │──test/                    * 测试用的文件\n   │   │\n   │   ├──dev.js               * 开发脚本\n   │   │\n   │   └──test.js              * 测试脚本\n   │   │\n   │   ├──vue                  * 用于测试/开发的 vue 组件\n   │   │\n   │   └──out                  * 测试/开发输出的 php 脚本\n   │\n   │──package.json             * 包信息\n   │\n   │──.babelrc                 * Babel配置\n   │\n   │──.gitignore               * Git忽略文件配置\n   │\n   └──.editorconfig            * 编码风格配置\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsurmon-china%2Fvue2any","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsurmon-china%2Fvue2any","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsurmon-china%2Fvue2any/lists"}