SoFunction
Updated on 2025-03-03

Detailed explanation of the idea of ​​remote loading of sfc components for vue

question

In our vue project (especially backend systems), there will always be some scenarios where multiple business lines need to jointly develop the same project. If each business team provides some public business components to the project, these components cannot be packaged together with the project, because the project cannot be repeatedly built and released due to frequent changes of a private module.

^_^ is not recommended for use in production environments, the code contains eval

Ideas

In this scenario, we need to deploy the public business components to the server, and the client requests and renders the components.

Server-side parsing .vue files

Use vue-template-compiler template parser to parse SFC (single-file component)

const compile = require('vue-template-compiler')

// Get the source code of the sfc componentconst str = ((__dirname, `../components/`), 'utf-8')

// vue-loader is built-in and is now used to parse SFC (single-file component)let sfc = (str)

// Get the sfc component configurationlet sfcOptions = getComponentOption(sfc)

getComponentOption Get sfc component configuration

import { uuid } from 'utilscore'
import stylus from 'stylus'
import sass from 'sass'
import less from 'less'
const getComponentOption = sfc => {
  // Generate data-u-id  const componentId = uuid(8, 16).toLocaleLowerCase()  
  // Add data-u-id attribute to the tag  const template =  ? tagToUuid(, componentId) : ''  
  // Convert style (less, sass, styleus)  let styles = []  
  (sty => {    
    switch () {      
      case 'stylus':        
        (, (err, css) => (formatStyl(sty, css, componentId)))        
        break;      
      case 'sass':      
      case 'scss':        
        (formatStyl(sty, ({ data:  }).(), componentId))        
        break;      
      case 'less':        
        (, (err, css) => (formatStyl(sty, css, componentId)))        
        break;    
    }  
  })  
  let options = {    
    script:  ? $require(null, ) : {},    
    styles,    
    template  
  }  
  return (options, (k, v) => {
    if(typeof(v) === 'function') {
      let _fn = ()
      return /^function()/.test(_fn) ? _fn : (/^/,'function ')
    }
    return v
  })
}

tagToUuid  Append data-u-id to the tag in template

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

formatStyl handles the scope of the style

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

$require executes the JavaScript code inside it and returns the value

const $require = (filepath, scriptContext) => {
  const filename = (__dirname, `../${filepath}`);  
  const module = { exports: {} }  
  let code = scriptContext ? scriptContext : (filename, 'utf-8')  
  let exports =   
  code = `(function($require,module,exports,__dirname,filename){$[code]})($require,module,exports,__dirname,filename)`  
  eval(code)  
  return 
} 

The client requests the component and renders it

Encapsulate front-end remote components-

&lt;template&gt; 
  &lt;component :is="remote" v-bind="$attrs" v-on="$listeners"&gt;&lt;/component&gt;
&lt;/template&gt;
&lt;script&gt;
import Vue from "vue";
export default { 
  data() {  
    return {   
      remote: null  
    }
  }, 
  props: {  
    tagName: {   
      type: String,   
      defualt: "componentName"  
    } 
  }, 
  created() {  
    fetch("http://localhost:3000/getComponent/"+)
      .then(res =&gt; ())   
      .then(sfc =&gt; {    
        let options = (sfc);    
        (css =&gt; (css));    
         = ({ 
          ...,     
          name:  || ,     
          template:     
        });   
      }); 
   }, 
   methods: {  
    isObject(v) {   
      return (v).includes("Object");  
    },  
    parseObj(data) {   
      if ((data)) return (row =&gt; (row));   
      if ((data)) {    
        let ret = {};    
        for (let k in data) {     
          ret[k] = (data[k]);    
         }    return ret;   
      }   
      try {    
        let pattern = /function ([\w]+)\(\) \{ \[native code\] \}/;    
        if ((data)) {     
          return window[(data)[1]];    
        } else {     
          let evalData = eval(`(${data})`);     
          return typeof evalData == "function" ? evalData : data;    
        }   
      } catch (err) {    
        return data;   
      }  
    },  
    appendSty(css) { // Generate component styles      let style = ("style");   
      ("type", "text/css");   
      var cssText = (css);   
      (cssText);   
      var head = ("head");   
      (style);  
    } 
}};
&lt;/script&gt;

Remote Component Practice

Server SFC component, note that JavaScript blocks should be exported, and the script should be introduced using $require

&lt;template&gt; 
  &lt;div class="test"&gt;  
    &lt;div&gt;   
      &lt;p @click='$emit("handleClick",'Click me')'&gt;Remote Components--{{msg}}--{{text}}&lt;/p&gt;  
      &lt;/div&gt; 
    &lt;/div&gt;
&lt;/template&gt;
&lt;script&gt;
// Load js scriptlet {a} = $require('utils/') 
 = { 
  data: function() {  
    return {   
      msg: "remote component",
      ...a,
    } 
  }, 
  props: {  
    text: {   
      type: Boolean,   
      default: true  
    } 
  },
  mounted:function(){
    ('prop text is',)
  }
};
&lt;/script&gt;
&lt;style lang="stylus" scoped&gt;
.test { 
  .test2 {  
     color: red; 
  } 
  p{  
     color:red 
  }
}
&lt;/style&gt;

Client Rendering

// temolate
&lt;remote text='123456' @handleClick='handleClick'/&gt;

// script 
methods:{
 handleClick(v){
   (v) // Click me }}

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.