---
tags: PHP, Laravel, Backend
disqus: HackMD
---
# Laravel Vue组件分割,動態加載组件
## 環境
使用 `webpack` 非 `Vite`
## 發現問題
在 `laravel` 上開發 `Vue` 時,往往會將所有組件都註冊在 `app.js` 上,這樣在加載時會一次載入所有組件,導致 `client side` 網頁加載時間變長,影響使用者體驗。
## 動態引入
從 `laravel-mix(4.0.16)` 開始,開始支援動態引入 `(Dynamic Import)`。動態引入是一種 `code splitting`,可以將單一的 `bundle` 切分成多個塊 `chunk`,可搭配平行載入或在需要時才載入,或是對一些不常變動的 `chunk` 個別做快取,以達到載入效能的優化。這是 `Lazy Loading`(等用到的時候再載入)的一種實現。
## 解法
### Vue2解法
#### 配置
可以選擇設定`webpack.mix.js`或`.babelrc`檔案擇一即可
#### webpack.mix.js配置
在`webpack.mix.js`加上以下這行程式碼,`laravel-mix`必須是`4.0.16`版本以上
```javascript=
mix.babelConfig({ plugins: ['@babel/plugin-syntax-dynamic-import'], });
```
#### .babelrc檔案設置
根目錄新增`.babelrc` 檔案或是修改,將 `@babel/plugin-syntax-dynamic-import` 加到 `「plugins」` 這個`array`裏面,在啟用`laravel-mix`時就會自動引入
```javascript=
{ "plugins": [ "@babel/plugin-syntax-dynamic-import" ] }
```
#### 使用動態引入
原先引入Vue組件是使用`static import`方法引入
```javascript=
import ExampleComponent from "./components/ExampleComponent.vue";
Vue.component("example-component", ExampleComponent);
```
將其更改為`Dynamic Import`
#### 寫法一
通過使用特殊註釋語法提供塊名稱來使用命名塊(需要 `webpack > 2.4`),加入`/* webpackChunkName: "example" */`,為塊命名,不然在`run dev` 跟 `run prod`檔案名稱會不相同。
```javascript=
const ExampleComponent = () => import(/* webpackChunkName: "example" */ "./components/ExampleComponent.vue");
Vue.component("example-component", ExampleComponent);
```
#### 寫法二
```javascript=
Vue.component("example-component", () => import(/* webpackChunkName: "example" */ "./components/ExampleComponent.vue"));
```
#### 在`vue router`中
```javascript=
const routes = [
{
path:"/home",
component: ()=>import(/* webpackChunkName: "example" */ './components/ExampleComponent'),
},
];
```
#### 更改塊存放位置
可以設置`webpack.mix.js`更改塊`(chunks)`存放的位置
```javascript=
mix.webpackConfig({
output:{
chunkFilename: 'js/chunks/[name].js',
publicPath: '/',
}
});
```
#### 編譯
`npm run dev` 或是 `npm run watch`
#### 後記
可以看到在還未分割檔案前`app.js`的容量較大,分割後多了其他組件的`js`而`app.js`也縮水了
切割前:

切割後:

也只需要加載`app.js`,`laravel-mix`會去解決按需要才載入問題
### Vue3 and inertia解法
#### 動態引入`Page vue`
修改`app.js`
```javascript=
import { createApp, h } from 'vue';
import { createInertiaApp } from '@inertiajs/inertia-vue3';
const app = createInertiaApp({
title: (title) => `${title} - ${appName}`,
// 原先寫法
// resolve: (name) => require(`./Pages/${name}.vue`),
// 更改後
resolve: (name) => import(/* webpackChunkName: "[request]" */`./Pages/${name}.vue`),
setup({ el, app, props, plugin }) {
return createApp({ render: () => h(app, props) })
.use(plugin)
.mixin({ methods: { route } })
.mount(el);
},
});
```
#### 結果
前

後
