最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • vue3单文件组件编译过程

    正文概述 掘金(Mr火叶)   2021-06-01   645

    最近产品给我提了一个非常好玩(e xin)的需求:用户输入单文件组件(sfc)的代码就能显示对应的界面。具体可以参考vue playground。

    提出问题

    作为一个成熟的前端,要善于挖掘产品的隐含意思:

    ok,需求弄清楚了咱们开始做技术调研。

    技术调研

    用户输入代码可以使用vscode的web版编辑器monaco-editor,这个很简单。主要问题是输入的代码怎么显示出对应的界面呢?

    createApp

    vue3中,我们通常会在main.js中通过下面的代码,将根组件挂载到dom节点中:

    import { createApp } from 'vue'
    import App from './App.vue'
    
    createApp(App).mount('#app');
    

    createApp可以接收不同的参数,在optional的写法中,只要将sfc的template,data,methods这些对象获取到传入其中,不就可以显示出界面了嘛。

    // 伪代码
    let code = monacoInstance.getValue()  // 用户输入的代码字符串
    // 假设compile函数是对code做一系列正则匹配,用于获取template,data等内容
    let { template,data,methods } = compile(code)
    createApp({
        template,
        data,
        methods
    }).mount('#container');
    

    这么干确实可以把界面显示出来,但是有一个问题,compile函数超级难写,因为我们要支持多种不同的写法,自己写这个compile不太现实,有没有现成的库可以用呢?

    @vue/compiler-sfc

    当然有了,不然vue怎么去编译sfc呢,在vue3中编译sfc主要会使用@vue/compiler-sfc这个包,大概的流程是这样的:

                                      +--------------------+
                                      |                    |
                                      |  script transform  |
                               +----->+                    |
                               |      +--------------------+
                               |
    +--------------------+     |      +--------------------+
    |                    |     |      |                    |
    |  facade transform  +----------->+ template transform |
    |                    |     |      |                    |
    +--------------------+     |      +--------------------+
                               |
                               |      +--------------------+
                               +----->+                    |
                                      |  style transform   |
                                      |                    |
                                      +--------------------+
    

    用伪代码再描述一下:

    import { parse,compileTemplate,compileScript,compileStyleAsync } from '@vue/compiler-sfc'
    
    let code = monacoInstance.getValue()  // 用户输入的代码字符串
    
    const descriptor = parse(code) //  facade transform,生成的descriptor中已经可以找到我们所需要的tempplate,但是methods,data这些数据还无法获取
    
    const compiledScript = compileScript(descriptor)
    
    const result = rewriteDefault(compiledScript.content) // result是一个字符串,通过动态生成script来执行字符串的内容,最后会返回一个__sfc__,这也就是我们需要传入到createApp里面的
    

    上述这段伪代码的思路,来自于sfc-playground这个项目,有兴趣可以去读一下。

    原本我以为,要提取data,methods等传入createApp中才能显示出一个完成的sfc,实际上如果你输入的代码中包含setup,并不会有data,methods这些属性,而是会产生一个setup函数,这个函数会返回data和methods,将这个setup函数传入createApp即可。

    @vue/compiler-sfc有broswer版本,也有nodejs的版本,我选择在服务端编译,因为在使用broswer版本中爆了一些我无法解决的错误,能力有限,希望有人能出一个broswer版本的使用教程。

    在做完这些后,已经可以将用户输入的sfc显示出来了,但是还有一个问题,如果输入的代码中有UI库组件,则编译不出来,例如使用了el-button。

    UI库组件的不显示

    我发现当使用optional的写法,传入createApp中是template,data,methods这些的时候,只需要这样写就可以正常显示出UI库的组件:

    import { createApp,nextTick } from 'vue'
    let app = createApp({
        template,
        methods,
        ...
    })
    nextTick(async () => {
        // 根据条件判断,导入哪些依赖
        const ElementPlus = await import('element-plus');
        _app.use(ElementPlus).mount(#container)
    })
    

    而使用setup则会导致UI库的组件无法渲染,这个问题其实很简单。使用setup之后会__sfc__会包含一个render函数,我们知道sfc的编译过程,其实就是将template编译成render函数,我们传入template可以显示出UI组件,而传入render函数无法显示UI组件,那么原因就是当传入createApp中存在render函数时,不会再次进行compile。

    如果希望use(ElementPlus)能成功执行,则需要在前端再compile一次,这时只需将传入createApp中的render设置为null,以及传入从descriptor中获取的template即可。另外:

    // 如果设置inlineTemplate为true,那么setup函数返回的并不是data,methods这些对象而是一个render函数
    const compiledScript = SFCCompiler.compileScript(descriptor, {
        inlineTemplate: true
    })
    

    在sfc-playground中,解析< script setup>的代码,inlineTemplate是为true的,所以setup中会返回render函数。设置inlineTemplate为false,则会生成单独的render函数,设置这个render函数为null,就可以触发前端的compile。

    最后

    如果你也遇到类似的需求,我建议可以先看看@vue/compiler-sfc和sfc-playground的源码。


    起源地下载网 » vue3单文件组件编译过程

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元