vue动态编译模板,代码字符串生成对应路由信息

获取到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);
	         }
	      })
	}
})
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值