在我們的 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 } }) ]};
新聞熱點
疑難解答