在我们的 vue 项目中(特别是后台系统),总会出现一些需要多业务线共同开发同一个项目的场景,如果各业务团队向框架中提供一些私有的展示组件,但是这些组件并不能和框架一起打包,因为框架不能因为某个私有模块的频繁变更而重复构建发布。在这种场景下我们需要一个加载远程异步代码的组件来完成将这些组件加载到框架中。
vue-cli 作为 Vue 官方推荐的项目构建脚手架,它提供了开发过程中常用的,热重载,构建,调试,单元测试,代码检测等功能。我们本次的异步远端组件将基于 vue-cli 开发。
需求分析
如何加载远端的代码? 如何注册加载后的代码到框架中。 父组件如何和远端引入的组件通信。 远端代码如何复用框架中已引入的库。 避免因远端代码被类似 v-for 多次调用导致的不必要请求。加载远端代码
远端代码应该存储在一个可访问的 URL 上,这样我们通过 Axios 类似的 HTTP client 请求这个链接拿到源码。
import Axios from 'axios';export default { name: 'SyncComponent', props: { // 父组件提供请求地址 url: { type: String, default: '' } }, data() { return { resData: '' }; }, async mounted() { if (!this.url) return; const res = await Axios.get(this.url); // 我们在组件挂载完成时,请求远端代码并存储结果。 this.resData = res.data; }};
以上是基础代码 为了方便 一下例子中 我将省略重复的代码部分。
注册代码到框架中
这部分有些繁琐,涉及到多个问题:
浏览器并不支持 .vue 模板 或 ES.next 语法,模块需要编译后才可以使用。
处理这部分比较简单,我们自己定义一个webpack配置文件来打包这些模板。
// 在 build 目录下新建 webpack.sync-components.prod.conf.js 文件const webpack = require('webpack');const path = require('path');const utils = require('./utils');const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')function resolve(dir) { return path.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-loader v13 更新 默认值为 true v12及之前版本为 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: [ new webpack.DefinePlugin({ 'process.env.NODE_ENV': '"production"' }), // 压缩JS new webpack.optimize.UglifyJsPlugin({ compress: false, sourceMap: true }), // 压缩CSS 注意不做提取 new OptimizeCSSPlugin({ cssProcessorOptions: { safe: true } }) ]};
新闻热点
疑难解答