--- 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)