加載 vue 遠程代碼的組件實例詳解
在我們的 vue 項目中(特別是后臺系統(tǒng)),總會出現一些需要多業(yè)務線共同開發(fā)同一個項目的場景,如果各業(yè)務團隊向框架中提供一些私有的展示組件,但是這些組件并不能和框架一起打包,因為框架不能因為某個私有模塊的頻繁變更而重復構建發(fā)布。在這種場景下我們需要一個加載遠程異步代碼的組件來完成將這些組件加載到框架中。
vue-cli 作為 Vue 官方推薦的項目構建腳手架,它提供了開發(fā)過程中常用的,熱重載,構建,調試,單元測試,代碼檢測等功能。我們本次的異步遠端組件將基于 vue-cli 開發(fā)。
需求分析
- 如何加載遠端的代碼?
- 如何注冊加載后的代碼到框架中。
- 父組件如何和遠端引入的組件通信。
- 遠端代碼如何復用框架中已引入的庫。
- 避免因遠端代碼被類似 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') }, // 輸出到靜態(tài)目錄下 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 } }) ] };
至此我們的模塊已經被編譯成框架可以識別的文件。
1.如何將字符串轉換成js對象。
new Function。 async mounted() { if (!this.url) return; const res = await Axios.get(this.url); let Fn = Function; this.mode = new Fn(`return ${res.data}`)(); }
1.轉換后的js對象并不能被vue識別。
有兩種可能會導致這個問題:
// vue-loader v13 esModule 更新 默認值為 true, v12及之前版本為 false, 此項配置影響 vue 自身異步組件寫法以及 webpack 打包結果 { test: /\.vue$/, loader: 'vue-loader', options: { esModule: false ... 以下省略千軍萬碼 } } // UglifyJs 需要取消變量名替換配置,此配置并不會極大影響壓縮率 new webpack.optimize.UglifyJsPlugin({ compress: false, sourceMap: true })
至此 遠程組件就被引入到框架中了。
父組件如何和遠端引入的組件通信
這里有一個問題,從 view組件 到 遠程異步加載組件 再到 實際業(yè)務組件 通信一共三層,中間層 遠程異步組件 作為公共組件不可被修改,需要 view組件 直接向 實際業(yè)務組件 通信。vuex 和 eventBus 方案都過于繁瑣,這里我們采用 $attrs 和 $listeners(vue v2.4+), 來實現 “fallthrough”(vue組件跨層級通信)。
// 修改 sync-component.vue 組件 // 新增 v-bind="$attrs" v-on="$listeners" <component :is="mode" v-bind="$attrs" v-on="$listeners"> </component> // inheritAttrs: true export default { name: 'SyncComponent', props: { // 父組件提供請求地址 url: { type: String, default: '' } }, inheritAttrs: true ... 以下省略千軍萬碼 }
遠端代碼如何復用框架中已引入的庫
我們不希望看到遠端組件和框架中存在較大庫或插件的重復的引入,這部分內容尚處在實踐階段,主要思路是把公共庫掛載到Vue原型鏈上實現組件公共復用 Vue.prototype.$xxx。
// 全局添加 axios 對象 import axios from 'axios'; Vue.prototype.$http = axios;
引入的遠程組件可以訪問到框架中的公共包了,這時候還需要配置 webpack 使遠程組件打包時不要包含公共包的代碼。
// webpack.sync-components.prod.conf.js 添加 externals: { vue: 'vue', 'element-ui': 'element-ui', axios: 'axios' }
避免因遠端代碼被類似 v-for 多次調用導致的不必要請求。
這部分我們直接用一個全局變量做字典,存儲 以 請求地址:數據 為子項的數組。
async mounted() { if (!this.url) return; // Cache 緩存 根據 url 參數 if (!window.SyncComponentCache) { window.SyncComponentCache = {}; } let res; if (!window.SyncComponentCache[this.url]) { window.SyncComponentCache[this.url] = Axios.get(this.url); res = await window.SyncComponentCache[this.url]; } else { res = await window.SyncComponentCache[this.url]; } let Fn = Function; this.mode = new Fn(`return ${res.data}`)(); console.log(this.mode); }
至此,異步遠程組件就可以加載并和框架進行通信了。
本文中的源碼請訪問 github 獲取,組件已經發(fā)布到NPM 上,可以直接安裝。
總結
以上所述是小編給大家介紹的加載 vue 遠程代碼的組件,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網站的支持!
相關文章
vue 路由懶加載中給 Webpack Chunks 命名的方法
這篇文章主要介紹了在 vue 路由懶加載中給 Webpack Chunks 命名的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-04-04vuex中this.$store.commit和this.$store.dispatch的基本用法實例
在vue的項目里常常會遇到父子組件間需要進行數據傳遞的情況,下面這篇文章主要給大家介紹了關于vuex中this.$store.commit和this.$store.dispatch的基本用法的相關資料,需要的朋友可以參考下2023-01-01詳解vuejs中執(zhí)行npm run dev出現頁面cannot GET/問題
這篇文章主要介紹了詳解vuejs中執(zhí)行npm run dev出現頁面cannot GET/問題,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-04-04vue3?+?async-validator實現表單驗證的示例代碼
表單驗證可以有效的過濾不合格的數據,減少服務器的開銷,并提升用戶的使用體驗,今天我們使用?vue3?來做一個表單驗證的例子,需要的朋友跟隨小編一起學習下吧2022-06-06