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

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

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

  咱們注意到,官方提供的demo是異步引入本工程下的組件,對於滴滴(每一個業務線是一個工程,在不一樣的git倉庫存儲)。滴滴的作法是將不一樣的業務線單獨構建,構建的每一個業務線是一個Vue實例(不知道這塊是否理解有錯,歡迎指正),而後將其傳遞給resolve函數(我感受滴滴在這塊的處理特別秒:好比全局的Vue,Vuex,公共業務組件的共享,異步業務組件的全局掛載,動態路由註冊非常妙哉,但願你們去原地址查看,我這裏就不贅述了)。下面是我本身的一個嘗試:前端

  首先,在一個目錄下運行 vue init webpack-simple async-component , 新建一個工程,用來開發須要異步註冊的組件,在src下新建component目錄,並建立index.js和async-component.vue文件,完整目錄結構以下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測試項目代碼以下:java

  

// 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 {
    };
  },
  methods: {
    changeComponent () {
      this.componentName = this.name
    },
    loadAsyncComponent () {
      Vue.component(this.name, (resolve, reject) => {
        this.loadScript('http://localhost:8000/async-component.js')
          .then(() => {
            resolve(window.modules['async-component'])
          }).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

 

點擊按鈕後以下git

  

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

相關文章
相關標籤/搜索