前言:最近在掘金逛的時候,無心中看到前滴滴前端架構黃軼大佬,看到了大佬分享的一篇博客 滴滴 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