获取到vue模板字符串生成对应页面信息
这里主要针对注册路由形式,嵌套页面同理。
1. 获取默认的vue模板字符串
let code = `
<template><div class="container">{{text}}</div></template>
<script>
export default {
data(){
return {
text:"测试"
}
}
}
</script>
<style lang="scss" scoped>
.container{
color:red
}
</style>`
2.解析vue模板
//依赖信息
import * as Babel from "@babel/core";
import * as VueTemplateCompiler from "vue-template-compiler";
import less from "less";
import Sass from "sass.js"
//解析单文件
const vue = (preprocessor, code, importMap) => {
return new Promise(async (resolve, reject) => {
try {
let componentData;
let parseData;
switch (preprocessor) {
case "vue2":
componentData = VueTemplateCompiler.parseComponent(code);
parseData = await parseVueComponentData(
componentData,
parseVue2ScriptPlugin,
"vue2",
importMap
);
resolve(parseData);
break;
default:
resolve({
useImport: false,
js: ""
});
break;
}
} catch (error) {
reject(error);
}
});
};
//Sass 的编译
function PromiseScssToCss(sssStr) {
return new Promise((resolve, reject) => {
Sass.compile(sssStr, function(result) {
if (result.status === 0) {
let cssStr =
typeof result.text === "string" && result.text.replace(/;/g, ";\n");
resolve(cssStr);
} else {
reject({
code: 1,
...result
});
}
});
});
}
/**
* @Desc: 编译css
*/
const css = async (preprocessor, code) => {
if (preprocessor === "css") {
return code;
} else if (preprocessor === "less") {
const output = await less.render(code);
return output.css;
} else if (preprocessor === "sass" || preprocessor === "scss") {
if (typeof code === "string") {
let codeWraper = `.app-wrapper{.preview-workbench{${code}}}`;
let cssStr = "";
try {
if (code) {
cssStr = await PromiseScssToCss(codeWraper);
return cssStr;
} else {
return "";
}
} catch (e) {
let { line, column, message } = e;
console.log(
`scss样式中第${line}行,第${column}列,有错误,错误信息:${message}。请在设计器中核查,并修改`
);
return false;
}
}
}
};
/**
* @Desc: 解析出html、js、css
*/
const parseVueComponentData = async (
data,
parseVueScriptPlugin,
version,
importMap
) => {
// html就直接渲染一个挂载vue实例的节点
let htmlStr = `<div id="app"></div>`;
// 加载babel解析器
// await load(['babel'])
// babel编译,通过编写插件来完成对ast的修改
let jsData = {
useImport: false,
js: ""
};
if (data.script) {
// Vue2支持全局变量的方式及ESM方式,Vue3只支持ESM方式
if (
(version === "vue2" && checkIsHasImport(data.script.content)) ||
version === "vue3"
) {
jsData = {
useImport: true,
js: Babel.transform(data.script.content, {
plugins: [parseJsImportPlugin(importMap), parseVueScriptPlugin(data)]
}).code
};
} else {
jsData = {
useImport: true,
js: Babel.transformSync(data.script.content, {
// presets: ["@babel/preset-env"],
plugins: [parseVueScriptPlugin(data)]
}).code
};
}
}
// 编译css
let cssStr = "";
for (let i = 0; i < data.styles.length; i++) {
let style = data.styles[i];
let preprocessor = style.lang || "css";
cssStr = await tranform.css(preprocessor, style.content);
}
return {
html: htmlStr,
js: jsData,
css: cssStr
};
};
/**
* @Desc: 解析vue2 script语法
*/
const parseVue2ScriptPlugin = data => {
return function(babel) {
let t = babel.types;
return {
visitor: {
// 解析export default模块语法
ExportDefaultDeclaration(path) {
path.replaceWith(t.ReturnStatement(path.get("declaration").node));
// 添加el和template属性
traverseVue2AddProperty(path, t, data);
},
// 解析module.exports模块语法
AssignmentExpression(path) {
try {
let objectNode = path.get("left.object.name");
let propertyNode = path.get("left.property.name");
if (
objectNode &&
objectNode.node === "module" &&
propertyNode &&
propertyNode.node === "exports"
) {
path.replaceWith(
t.newExpression(t.identifier("Vue"), [path.get("right").node])
);
// 添加el和template属性
traverseVue2AddProperty(path, t, data);
}
} catch (error) {
// console.log(error)
}
}
}
};
};
};
3.注册组件信息
import router from "vue-router";
router.addRoutes({
path:"/",
component:()=>{
new Promise(async (resolve) => {
try {
const template = await vue(
"vue2",
code//第一步的vue模板
);
resolve(new Function(template.js.js)());
} catch (e) {
console.log(e);
}
})
}
})