当前位置 主页 > 服务器问题 > Linux/apache问题 >

    vue远程加载sfc组件思路详解

    栏目:Linux/apache问题 时间:2019-12-25 23:39

    问题

    在我们的 vue 项目中(特别是后台系统),总会出现一些需要多业务线共同开发同一个项目的场景,如果各业务团队向项目中提供一些公共业务组件,但是这些组件并不能和项目一起打包,因为项目中不能因为某个私有模块的频繁变更而重复构建发布。

    ^_^不建议在生产环境使用,代码包含eval 

    思路

    在这种场景下我们需要将公共的业务组件部署到服务端,由客户端请求并渲染组件。

    服务端解析.vue文件

    使用vue-template-compiler 模板解析器,解析SFC(单文件组件)

    const compile = require('vue-template-compiler')
    
    // 获取sfc组件的源码
    const str = fs.readFileSync(path.resolve(__dirname, `../components/sfc.vue`), 'utf-8')
    
    // vue-loader内置,现在用来解析SFC(单文件组件)
    let sfc = compile.parseComponent(str)
    
    // 获取sfc组件配置
    let sfcOptions = getComponentOption(sfc)
    

    getComponentOption 获取sfc组件配置

    import { uuid } from 'utilscore'
    import stylus from 'stylus'
    import sass from 'sass'
    import less from 'less'
    const getComponentOption = sfc => {
      // 生成data-u-id 
      const componentId = uuid(8, 16).toLocaleLowerCase()  
      // 标签添加data-u-id属性  
      const template = sfc.template ? tagToUuid(sfc.template.content, componentId) : ''  
      // 转化style(less、sass、stylus)  
      let styles = []  
      sfc.styles.forEach(sty => {    
        switch (sty.lang) {      
          case 'stylus':        
            stylus.render(sty.content, (err, css) => styles.push(formatStyl(sty, css, componentId)))        
            break;      
          case 'sass':      
          case 'scss':        
            styles.push(formatStyl(sty, sass.renderSync({ data: sty.content }).css.toString(), componentId))        
            break;      
          case 'less':        
            less.render(sty.content, (err, css) => styles.push(formatStyl(sty, css, componentId)))        
            break;    
        }  
      })  
      let options = {    
        script: sfc.script ? $require(null, sfc.script.content) : {},    
        styles,    
        template  
      }  
      return JSON.stringify(options, (k, v) => {
        if(typeof(v) === 'function') {
          let _fn = v.toString()
          return /^function()/.test(_fn) ? _fn : fn.replace(/^/,'function ')
        }
        return v
      })
    }

    tagToUuid  给template 中的标签追加data-u-id 

    const tagToUuid = (tpl, id) => {  
      var pattern = /<[^\/]("[^"]*"|'[^']*'|[^'">])*>/g  
      return tpl.replace(pattern, $1 => {    
        return $1.replace(/<([\w\-]+)/i, ($2, $3) => `<${$3} data-u-${id}`)  
      })
    }

    formatStyl 处理样式的scoped

    const formatStyl = (sty, css, componentId) => {  
      let cssText = css  
      if (sty.scoped) {    
        cssText = css.replace(/[\.\w\>\s]+{/g, $1 => {      
        if (/>>>/.test($1)) return $1.replace(/\s+>>>/, `[data-u-${componentId}]`)      
        return $1.replace(/\s+{/g, $2 => `[data-u-${componentId}]${$2}`)    
        })  
      }  
      return cssText
    }
    
    

    $require 执行其中的的 JavaScript 代码,并返回值