加载 vue 远程代码的组件实例详解
在我们的vue项目中(特别是后台系统),总会出现一些需要多业务线共同开发同一个项目的场景,如果各业务团队向框架中提供一些私有的展示组件,但是这些组件并不能和框架一起打包,因为框架不能因为某个私有模块的频繁变更而重复构建发布。在这种场景下我们需要一个加载远程异步代码的组件来完成将这些组件加载到框架中。
vue-cli作为Vue官方推荐的项目构建脚手架,它提供了开发过程中常用的,热重载,构建,调试,单元测试,代码检测等功能。我们本次的异步远端组件将基于vue-cli开发。
需求分析
- 如何加载远端的代码?
- 如何注册加载后的代码到框架中。
- 父组件如何和远端引入的组件通信。
- 远端代码如何复用框架中已引入的库。
- 避免因远端代码被类似v-for多次调用导致的不必要请求。
加载远端代码
远端代码应该存储在一个可访问的URL上,这样我们通过Axios类似的HTTPclient请求这个链接拿到源码。
importAxiosfrom'axios'; exportdefault{ name:'SyncComponent', props:{ //父组件提供请求地址 url:{ type:String, default:'' } }, data(){ return{ resData:'' }; }, asyncmounted(){ if(!this.url)return; constres=awaitAxios.get(this.url);//我们在组件挂载完成时,请求远端代码并存储结果。 this.resData=res.data; } };
以上是基础代码为了方便一下例子中我将省略重复的代码部分。
注册代码到框架中
这部分有些繁琐,涉及到多个问题:
浏览器并不支持.vue模板或ES.next语法,模块需要编译后才可以使用。
处理这部分比较简单,我们自己定义一个webpack配置文件来打包这些模板。
//在build目录下新建webpack.sync-components.prod.conf.js文件 constwebpack=require('webpack'); constpath=require('path'); constutils=require('./utils'); constOptimizeCSSPlugin=require('optimize-css-assets-webpack-plugin') functionresolve(dir){ returnpath.join(__dirname,'..',dir) } module.exports={ //此处引入要打包的组件 entry:{ componentA:resolve('/src/views/component-a.vue') }, //输出到静态目录下 output:{ path:resolve('/static/'), filename:'[name].js', }, resolve:{ extensions:['.js','.vue','.json'], alias:{ 'vue$':'vue/dist/vue.esm.js', '@':resolve('src'), } }, module:{ rules:[ { test:/\.vue$/, loader:'vue-loader', options:{ esModule:false,//******vue-loaderv13更新默认值为truev12及之前版本为false,此项配置影响vue自身异步组件写法以及webpack打包结果 loaders:utils.cssLoaders({ sourceMap:true, extract:false//css不做提取 }), transformToRequire:{ video:'src', source:'src', img:'src', image:'xlink:href' } } }, { test:/\.js$/, loader:'babel-loader', include:[resolve('src'),resolve('test')] }, { test:/\.(png|jpe?g|gif|svg)(\?.*)?$/, loader:'url-loader', options:{ limit:10000, name:utils.assetsPath('img/[name].[hash:7].[ext]') } }, { test:/\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, loader:'url-loader', options:{ limit:10000, name:utils.assetsPath('media/[name].[hash:7].[ext]') } }, { test:/\.(woff2?|eot|ttf|otf)(\?.*)?$/, loader:'url-loader', options:{ limit:10000, name:utils.assetsPath('fonts/[name].[hash:7].[ext]') } } ] }, plugins:[ newwebpack.DefinePlugin({ 'process.env.NODE_ENV':'"production"' }), //压缩JS newwebpack.optimize.UglifyJsPlugin({ compress:false, sourceMap:true }), //压缩CSS注意不做提取 newOptimizeCSSPlugin({ cssProcessorOptions:{ safe:true } }) ] };
至此我们的模块已经被编译成框架可以识别的文件。
1.如何将字符串转换成js对象。
newFunction。 asyncmounted(){ if(!this.url)return; constres=awaitAxios.get(this.url); letFn=Function; this.mode=newFn(`return${res.data}`)(); }
1.转换后的js对象并不能被vue识别。
有两种可能会导致这个问题:
//vue-loaderv13esModule更新默认值为true,v12及之前版本为false,此项配置影响vue自身异步组件写法以及webpack打包结果 { test:/\.vue$/, loader:'vue-loader', options:{ esModule:false ...以下省略千军万码 } } //UglifyJs需要取消变量名替换配置,此配置并不会极大影响压缩率 newwebpack.optimize.UglifyJsPlugin({ compress:false, sourceMap:true })
至此远程组件就被引入到框架中了。
父组件如何和远端引入的组件通信
这里有一个问题,从view组件到远程异步加载组件再到实际业务组件通信一共三层,中间层远程异步组件作为公共组件不可被修改,需要view组件直接向实际业务组件通信。vuex和eventBus方案都过于繁琐,这里我们采用$attrs和$listeners(vuev2.4+),来实现“fallthrough”(vue组件跨层级通信)。
//修改sync-component.vue组件 //新增v-bind="$attrs"v-on="$listeners"//inheritAttrs:true exportdefault{ name:'SyncComponent', props:{ //父组件提供请求地址 url:{ type:String, default:'' } }, inheritAttrs:true ...以下省略千军万码 }
远端代码如何复用框架中已引入的库
我们不希望看到远端组件和框架中存在较大库或插件的重复的引入,这部分内容尚处在实践阶段,主要思路是把公共库挂载到Vue原型链上实现组件公共复用Vue.prototype.$xxx。
//全局添加axios对象 importaxiosfrom'axios'; Vue.prototype.$http=axios;
引入的远程组件可以访问到框架中的公共包了,这时候还需要配置webpack使远程组件打包时不要包含公共包的代码。
//webpack.sync-components.prod.conf.js添加 externals:{ vue:'vue', 'element-ui':'element-ui', axios:'axios' }
避免因远端代码被类似v-for多次调用导致的不必要请求。
这部分我们直接用一个全局变量做字典,存储以请求地址:数据为子项的数组。
asyncmounted(){ if(!this.url)return; //Cache缓存根据url参数 if(!window.SyncComponentCache){ window.SyncComponentCache={}; } letres; if(!window.SyncComponentCache[this.url]){ window.SyncComponentCache[this.url]=Axios.get(this.url); res=awaitwindow.SyncComponentCache[this.url]; }else{ res=awaitwindow.SyncComponentCache[this.url]; } letFn=Function; this.mode=newFn(`return${res.data}`)(); console.log(this.mode); }
至此,异步远程组件就可以加载并和框架进行通信了。
本文中的源码请访问github获取,组件已经发布到NPM上,可以直接安装。
总结
以上所述是小编给大家介绍的加载vue远程代码的组件,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!