# 路由懶加載
當打包構建應用時,Javascript 包會變得非常大,影響頁面加載速度。如果我們能把不同路由對應的組件分割成不同的代碼塊,然后當路由被訪問的時候才加載對應組件,這樣就更加高效了。
結合 Vue 的[異步組件](https://cn.vuejs.org/v2/guide/components.html#%E5%BC%82%E6%AD%A5%E7%BB%84%E4%BB%B6)和 Webpack 的[代碼分割功能](https://doc.webpack-china.org/guides/code-splitting),輕松實現路由組件的懶加載。如:
~~~
const Foo = () => import('./Foo.vue')
~~~
**當你覺得你的頁面熱更新速度慢的時候,才需要往下看 ↓**
## [#](https://panjiachen.github.io/vue-element-admin-site/zh/guide/advanced/lazy-loading.html#%E5%8C%BA%E5%88%86%E5%BC%80%E5%8F%91%E4%B8%8E%E7%94%9F%E4%BA%A7%E7%8E%AF%E5%A2%83-%E8%AF%A5%E6%96%B9%E6%A1%88%E5%B7%B2%E6%B7%98%E6%B1%B0)區分開發與生產環境 \[該方案已淘汰\]
當你的項目頁面越來越多之后,在開發環境之中使用`lazy-loading`會變得不太合適,每次更改代碼觸發熱更新都會變得非常的慢。所以建議只在生產環境之中使用路由懶加載功能。
**開發環境:**
~~~
module.exports = file => require('@/views/' + file + '.vue').default // vue-loader at least v13.0.0+
~~~
**這里注意一下該寫法只支持`vue-loader at least v13.0.0+`理由[vue-element-admin/issues/231](https://github.com/PanJiaChen/vue-element-admin/issues/231)**
**生產環境:**
~~~
module.exports = file => () => import('@/views/' + file + '.vue')
~~~
## [#](https://panjiachen.github.io/vue-element-admin-site/zh/guide/advanced/lazy-loading.html#%E6%B7%98%E6%B1%B0%E5%8E%9F%E5%9B%A0)淘汰原因
當然這樣寫會有一些副作用。由于
> Every module that could potentially be requested on an import() call is included. For example, import(./locale/${language}.json) will cause every .json file in the ./locale directory to be bundled into the new chunk. At run time, when the variable language has been computed, any file like english.json or german.json will be available for consumption.
`@/views/下的 .vue`文件都會被打包。不管你是否被依賴。所以這樣就產生了一個副作用,就是會多打包一些可能永遠都用不到 js 代碼。當然這只會增加 dist 文件的大小,但不會對線上代碼產生任何的副作用。[相關 issue](https://github.com/PanJiaChen/vue-element-admin/issues/292)
> TIP
>
> 用戶自己可以根據業務情況來衡量一下是否采用本方案,如果你的項目頁面不超過幾十個,本地開發熱更新速度你還能接受的話,可以直接所有環境下都是用懶加載避免此副作用。
## [#](https://panjiachen.github.io/vue-element-admin-site/zh/guide/advanced/lazy-loading.html#%E6%96%B0%E6%96%B9%E6%A1%88)新方案
使用`babel`的`plugins`[babel-plugin-dynamic-import-node](https://github.com/airbnb/babel-plugin-dynamic-import-node)。它只做一件事就是將所有的`import()`轉化為`require()`,這樣就可以用這個插件將所有異步組件都用同步的方式引入,并結合[BABEL\_ENV](https://babeljs.io/docs/usage/babelrc/#env-option)這個`babel`環境變量,讓它只作用于開發環境下,在開發環境中將所有`import()`轉化為`require()`,這種方案解決了之前重復打包的問題,同時對代碼的侵入性也很小,你平時寫路由的時候只需要按照官方[文檔](https://router.vuejs.org/zh/guide/advanced/lazy-loading.html)路由懶加載的方式就可以了,其它的都交給`babel`來處理,當你不想用這個方案的時候,也只要將它從`babel`的`plugins`中移除就可以了。
**具體代碼:**
首先在`package.json`中增加`BABEL_ENV`
~~~
"dev": "cross-env BABEL_ENV=development webpack-dev-server --inline --progress --config build/webpack.dev.conf.js"
~~~
接著在`.babelrc`只能加入`babel-plugin-dynamic-import-node`這個`plugins`,并讓它只有在`development`模式中才生效。
~~~
{
"env": {
"development": {
"plugins": ["dynamic-import-node"]
}
}
}
~~~
之后就大功告成了,路由只要像平時一樣寫就可以了。
~~~
{ path: '/login', component: () => import('@/views/login/index')}
~~~
[相關代碼改動](https://github.com/PanJiaChen/vue-element-admin/pull/727)
## [#](https://panjiachen.github.io/vue-element-admin-site/zh/guide/advanced/lazy-loading.html#vue-cli-3)vue-cli@3
`vue-element-admin@4`在新版本中已修改為基于`vue-cli`來進行構建。所以在新版本中你只要在`.env.development`環境變量配置文件中設置`VUE_CLI_BABEL_TRANSPILE_MODULES:true`就可以了,具體[代碼](https://github.com/PanJiaChen/vue-element-admin/blob/master/.env.development)。
它的實現邏輯和原理與之前還是一樣的,還是基于`babel-plugin-dynamic-import-node`來實現的。之所以在`vue-cli`中只需要設置一個變量就可以了,是借用了`vue-cli`它的默認配置,它幫你代碼都寫好了。通過閱讀[源碼](https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/babel-preset-app/index.js)可知,`vue-cli`會通過`VUE_CLI_BABEL_TRANSPILE_MODULES`這個環境變量來區分是否使用`babel-plugin-dynamic-import-node`,所以我們只要開其它就可以。雖然它的初衷是為了單元測試的,但正好滿足了我們的需求。
## [#](https://panjiachen.github.io/vue-element-admin-site/zh/guide/advanced/lazy-loading.html#%E6%94%B9%E8%BF%9B)改進
`webpack5`即將發布,大大幅提高了打包和編譯速度,之后可能完全不需要搞這么復雜了,再多的頁面熱更新,都能很快,完全就不需要前面提到的解決方案了。