Vue動態注冊異步組件(非同一個工程的組件)


  前言:最近在掘金逛的時候,無意中看到前滴滴前端架構黃軼大佬,看到了大佬分享的一篇博客 滴滴 webapp 5.0 Vue 2.0 重構經驗分享 ,對於其中第5個問題(異步加載的業務線組件,如何動態注冊?)的解決辦法深為震撼。

  滴滴的首屏展示的同步業務線組件,對於一些業務線(比如順風車,出租車,快車),這些業務線其實都可以成為單獨spa應用,由於種種原因(我感覺組件化應該是很大的一個原因,構建包很小只打核心和初始化給用戶顯示的,剩下的業務線通過Vue異步組件注冊引入)。Vue2提供的有異步注冊組件

  我們注意到,官方提供的demo是異步引入本工程下的組件,對於滴滴(每個業務線是一個工程,在不同的git倉庫存儲)。滴滴的做法是將不同的業務線單獨構建,構建的每個業務線是一個Vue實例(不知道這塊是否理解有錯,歡迎指正),然后將其傳遞給resolve函數(我感覺滴滴在這塊的處理特別秒:比如全局的Vue,Vuex,公共業務組件的共享,異步業務組件的全局掛載,動態路由注冊很是妙哉,希望大家去原地址查看,我這里就不贅述了)。下面是我自己的一個嘗試:

  首先,在一個目錄下運行 vue init webpack-simple async-component , 新建一個工程,用來開發需要異步注冊的組件,在src下新建component目錄,並創建index.js和async-component.vue文件,完整目錄結構如下

  

  

// async-component.vue
<template>
  <div class="async-component">
    <h1 class="name">{{name}}</h1>
    <div class="age">{{age}}</div>
  </div>
</template>

<script>
  export default {
    name: 'async-component',
    data () {
      return {

      }
    },
    props: {
      name: {
        type: String,
        default: '張三'
      },
      age: {
        type: Number,
        default: 18
      }
    }
  }
</script>

<style lang="scss" scoped>
  .async-component {
    .name {
      color: red;
    }
    .age {
      color: green;
    }
  }
</style>
// index.js
/**
 * Created by hs on 2019/7/15
 */
import AsyncComponent from './async-component'
if (typeof window !== 'undefined' && window.Vue) {
  // 跟滴滴一樣,將業務線異步組件存到window.modules下
  window.modules = {
    'async-component': AsyncComponent
  }
}
// webpack.config.js 修改入口和出口文件
entry: process.NODE_ENV === 'development' ? './src/main.js' : './src/component/index.js',
output: {
    path: path.resolve(__dirname, './dist'),
    publicPath: '/dist/',
    filename: 'async-component.js'
},

  在 async-component 項目根目錄運行 npm run build,然后dist生成了 async-component.js 文件,然后我們進入到dist文件夾下,運行 puer (一個web服務器,如果提示沒有這個命令),用npm或者yarn全局安裝下,puer啟動后默認地址為 http://localhost:8000 , 在瀏覽器測試下http://localhost:8000/async-component.js , 能成功訪問即可。然后啟動下我的Vue測試項目,地址為 http://localhost:8080 ,Vue測試項目代碼如下:

  

// App.vue
<template>
  <div id="app">
    <el-button type="primary" @click="changeComponent">加載異步組件</el-button>
    <component :is="componentName" name="小明" :age="50"></component>
  </div>
</template>

<script>
export default {
  name: 'App',
  data() {
    return {
    name: 'async-component' }; }, methods: { changeComponent () {
this.componentName = this.name }, loadAsyncComponent () { Vue.component(this.name, (resolve, reject) => { this.loadScript(`//localhost:8000/${this.name}.js`) .then(() => { resolve(window.modules[this.name]) }).catch((e) => { reject(e) }) }) }, loadScript (url){ return new Promise((resolve, reject) => { var script = document.createElement ("script") script.type = "text/javascript"; if (script.readyState){ //IE script.onreadystatechange = function(){ if (script.readyState == "loaded" || script.readyState == "complete"){ script.onreadystatechange = null; resolve() } }; } else { //Others script.onload = function(){ console.log('complete') resolve() }; script.onerror = function (e) { reject(e) } } script.src = url; document.getElementsByTagName("body")[0].appendChild(script); }) } }, mounted() { this.loadAsyncComponent() } } </script> <style lang="scss"> * { margin: 0; padding: 0; font-family: Microsoft YaHei; } #app { background: #f1f1f5; } </style>

  瀏覽訪問 http://localhost:8080,如下

 

點擊按鈕后如下

  

  個人感覺滴滴這個解決方法真的很精妙,但是細細想了一下,在公司的項目中好像用不到...這個方案是滴滴結合自身業務想出來的,技術還是要結合實際項目最好。最后引用下大佬對此相關的回復:滴滴這個場景是不適合用 webpack.ensure 的,因為是動態加載其它業務線的代碼,壓根代碼就不在一個倉庫下,只能通過 loadscript 方式加載,所以也有動態注冊路由的需求。技術重構往往伴隨着產品重構,單純的技術重構不太現實,除非特別閑。。所以慢慢來吧,新項目可以用 vue2 了~

 

  

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM