UNPKG

create-bfe-cttq

Version:

CTTQ大前端脚手架项目

201 lines (186 loc) 9.97 kB
const path = require("path"); const fs = require("fs"); const recast = require("recast"); const ejs = require("ejs") const { FindImport, FindNode } = require("../cli/recast/FilterDeclaration"); module.exports = async function(api, answers) { if (!answers.capability || answers.capability.length <= 0) { return; } if (answers.capability.includes("monitor")) { api.extendPackage("monitor/package.json"); } if (answers.capability.includes("sensors")) { api.extendPackage("sensors/package.json"); } if ("PC" == answers.type) { api.onBeforeCreate((files) => { Object.keys(files).forEach(file => { if (path.basename(file) != "main.js") { return; } let ast = recast.parse(files[file]); // 找到最后一个ImportDeclaration节点 let lastImportIndex = -1; const lastImport = ast.program.body.filter(node => recast.types.namedTypes.ImportDeclaration.check(node) ).pop(); if (lastImport) { lastImportIndex = ast.program.body.indexOf(lastImport); } let vueVariableName = ""; let vueVariable; // 设置vue实例变量 recast.visit(ast, { visitExpressionStatement(path) { const node = path.node; if (recast.types.namedTypes.CallExpression.check(node.expression) && recast.types.namedTypes.MemberExpression.check(node.expression.callee) && recast.types.namedTypes.NewExpression.check(node.expression.callee.object) && recast.types.namedTypes.Identifier.check(node.expression.callee.object.callee) && node.expression.callee.object.callee.name == "Vue") { return recast.types.builders.variableDeclaration( "const", [ recast.types.builders.variableDeclarator(recast.types.builders.identifier("appVue"),recast.parse(recast.print(node).code).program.body[0].expression) ] ); } return false; } }); vueVariable = ast.program.body.filter(node => { if (recast.types.namedTypes.VariableDeclaration.check(node) && node.declarations && node.declarations.length > 0) { for (const variable of node.declarations) { if (recast.types.namedTypes.VariableDeclarator.check(variable) && recast.types.namedTypes.CallExpression.check(variable.init) && recast.types.namedTypes.MemberExpression.check(variable.init.callee) && variable.init.callee.object && variable.init.callee.object.callee && variable.init.callee.object.callee.name == "Vue") { vueVariableName = variable.id.name; return true; } } } } ).pop(); // 引入监控 if (answers.capability.includes("monitor")) { let mainContext = ejs.render(fs.readFileSync(api.templatePathAt("monitor/main.js"), 'utf-8'), { name: answers.name, userInfo: `${vueVariableName}.$store.state` }); let mainAST = recast.parse(mainContext); let imports = FindImport(mainAST); if (imports && imports.length > 0) { ast.program.body.splice(lastImportIndex + 1, 0, ...imports); } let otherNode = FindNode(mainAST, {exclude: ["ImportDeclaration"]}); if (otherNode && otherNode.length > 0) { const vueVariableIndex = ast.program.body.indexOf(vueVariable); ast.program.body.splice(vueVariableIndex + 1, 0, ...otherNode); } } // 引入埋点 if (answers.capability.includes("sensors")) { let mainContext = ejs.render(fs.readFileSync(api.templatePathAt("sensors/main.js"), 'utf-8'), { name: answers.name, description: answers.description, userInfo: "newValue" }); let mainAST = recast.parse(mainContext); let imports = FindImport(mainAST); if (imports && imports.length > 0) { ast.program.body.splice(lastImportIndex + 1, 0, ...imports); for (const importDec of imports) { mainAST.program.body.splice(mainAST.program.body.indexOf(importDec), 1); } } let otherNode = FindNode(mainAST, {exclude: ["ImportDeclaration"]}); mainContext = `${vueVariableName}.$store.watch((state) => { return (state.user || {}).userInfo; }, (newValue) => { if (newValue) { ${recast.print(mainAST).code} } })` otherNode = recast.parse(mainContext).program.body; if (otherNode && otherNode.length > 0) { const vueVariableIndex = ast.program.body.indexOf(vueVariable); ast.program.body.splice(vueVariableIndex + 1, 0, ...otherNode); } } // 将AST转换回代码字符串 files[file] = recast.prettyPrint(ast, {tabWidth: 4, useTabs: true}).code.replace(/ {4}/g, "\t") + "\n"; }); }) } if ("APP" == answers.type) { api.onBeforeCreate((files) => { Object.keys(files).forEach(file => { if (path.basename(file) != "main.js") { return; } let ast = recast.parse(files[file]); // 找到最后一个ImportDeclaration节点 let lastImportIndex = -1; const lastImport = ast.program.body.filter(node => recast.types.namedTypes.ImportDeclaration.check(node) ).pop(); if (lastImport) { lastImportIndex = ast.program.body.indexOf(lastImport); } // 引入监控 let monitorCode = ""; if (answers.capability.includes("monitor")) { let mainContext = ejs.render(fs.readFileSync(api.templatePathAt("monitor/main.js"), 'utf-8'), { name: answers.name, userInfo: `app.$store.state` }); let mainAST = recast.parse(mainContext); let imports = FindImport(mainAST); if (imports && imports.length > 0) { ast.program.body.splice(lastImportIndex + 1, 0, ...imports); for (const importDec of imports) { mainAST.program.body.splice(mainAST.program.body.indexOf(importDec), 1); } } monitorCode = recast.print(mainAST).code; } // 引入埋点 let sensorsCode = ""; if (answers.capability.includes("sensors")) { let mainContext = ejs.render(fs.readFileSync(api.templatePathAt("sensors/main.js"), 'utf-8'), { name: answers.name, description: answers.description, userInfo: "newValue" }); let mainAST = recast.parse(mainContext); let imports = FindImport(mainAST); if (imports && imports.length > 0) { ast.program.body.splice(lastImportIndex + 1, 0, ...imports); for (const importDec of imports) { mainAST.program.body.splice(mainAST.program.body.indexOf(importDec), 1); } } sensorsCode = `app.$store.watch((state) => { return (state.userInfo || {}).person; }, (newValue) => { if (newValue) { ${recast.print(mainAST).code} } });` } if (monitorCode || sensorsCode) { let injectAst = recast.parse(`Object.defineProperty(window, "$app", { get() {return this.__app;}, set(app) { this.__app = app; ${monitorCode} ${sensorsCode} }}) `).program.body; ast.program.body.splice(ast.program.body.length, 0, ...injectAst); // 将AST转换回代码字符串 files[file] = recast.prettyPrint(ast, {tabWidth: 4, useTabs: true}).code.replace(/ {4}/g, "\t") + "\n"; } }); }) } return; } module.exports.apply = { after: ["base", "cttq-app", "cttq-mobile"], }