---
# System prepended metadata

title: Laravel Vue组件分割，動態加載组件
tags: [PHP, ' Backend', ' Laravel']

---

---
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`也縮水了

切割前:
![](https://i.imgur.com/nbLJViR.jpg)


切割後:
![](https://i.imgur.com/JgDFDb1.jpg)

也只需要加載`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);
    },
});
```

#### 結果

前

![](https://i.imgur.com/YLrstPm.jpg)


後

![](https://i.imgur.com/q5mpike.jpg)

