Laravel-mix: Way to split VueJS components / instances to many *.js files to make performance better

Created on 28 Apr 2018  路  9Comments  路  Source: JeffreyWay/laravel-mix

Hi.

Is there a way ? Or is there any improvement planned to split the compiled code into many small .js files or Vue instances and to be able to use them later only for needy subpages to improve performance?

I mean we have many components and we mix them with normal blade files. For now when we want to use any we need to inject app.js file to this page. So if our app.js file is few MB or even more we need to get thie every time we change poge or smth. If we could only include part of components we need for actual page it could improve the performance of the application and make it work faster even when we are using it on lower cpu devices or something.

Most helpful comment

@Bowens20832 In webpack.mix.js:

// Config to make chunks
mix.webpackConfig({
    plugins: [
        // Clearing public/js file -> bug on laravel-mix when we using version and files are not removed
        new Clean(['public/js/'], {verbose: false})
    ],
    output: {
        // Chunks in webpack
        publicPath: '/',
        chunkFilename: 'js/[name].[chunkhash].js',
    },
});

And in components you should use async import for components:

  1. Globaly:
Vue.component('my-component', () => import(/* webpackChunkName: "my-component" */ './MyComponent'));
  1. Localy:
const MyComponent= () => import(/* webpackChunkName: "my-component" */ './MyComponent')
  1. From package (export default):
const Vuetable = () => import(/* webpackChunkName: "vuetable" */ 'vuetable-2');
  1. From package (export named component) (?) Don't know if it's best way yet.
const Vuetable = (resolve) => import(/* webpackChunkName: "vuetable" */ 'vuetable-2').then( item => {
         resolve(item.Vuetable)
});

And finaly you need to create .babelrc file with:

{
    "plugins": ["syntax-dynamic-import"]
}

And install this as package with:
npm install babel-plugin-syntax-dynamic-import

Then recompile files with:
npm run dev

All 9 comments

You're using Vue.js under a not-SPA page, which is totally valid, but you want the lazy-loading advantages of a SPA app.

I think you have one simple option, and is the Vue Lazy Loading guide. The other thing you could do is to extract the libraries to cache your libraries.

Finally, you could rewrite your app to have a single entry point entry-point.js with a Vue instance, an inside it, register the variable components declared on a const for each page:

app.net/js/components/login.js

const PageComponent = ({
  components: {
    'validator': Validator
  },
  data: {
    user: '',
    password: '',
  },
  // ...
})

app.net/js/entry-point.js

new Vue({
  el: '#app'
  components: {
    'page-component': PageComponent
  },
  // ...
})

views/login.blade.php

<head>
  <script src="{{ mix('js/components/login.js') }}" defer></script>
  <script src="{{ mix('js/entry-point.js') }}" defer></script>
 <!-- ... -->
</head>

Using the latter, you would need to tell laravel-mix to compile every component by its own.

Other solutions would need a custom webpack configuration, or even a new build.

Do like below, it should work.

<template>
    <div> 
        <sample-component></sample-component>
    </div>
</template>
<script>
    const SampleComponent = resolve => require(['./components/SampleComponent.vue'], resolve);

    export default {
        components:{
            SampleComponent 
        }
    }
</script>

Thanks for your replay :)

@lrembacz Did that work for you?

@Bowens20832 In webpack.mix.js:

// Config to make chunks
mix.webpackConfig({
    plugins: [
        // Clearing public/js file -> bug on laravel-mix when we using version and files are not removed
        new Clean(['public/js/'], {verbose: false})
    ],
    output: {
        // Chunks in webpack
        publicPath: '/',
        chunkFilename: 'js/[name].[chunkhash].js',
    },
});

And in components you should use async import for components:

  1. Globaly:
Vue.component('my-component', () => import(/* webpackChunkName: "my-component" */ './MyComponent'));
  1. Localy:
const MyComponent= () => import(/* webpackChunkName: "my-component" */ './MyComponent')
  1. From package (export default):
const Vuetable = () => import(/* webpackChunkName: "vuetable" */ 'vuetable-2');
  1. From package (export named component) (?) Don't know if it's best way yet.
const Vuetable = (resolve) => import(/* webpackChunkName: "vuetable" */ 'vuetable-2').then( item => {
         resolve(item.Vuetable)
});

And finaly you need to create .babelrc file with:

{
    "plugins": ["syntax-dynamic-import"]
}

And install this as package with:
npm install babel-plugin-syntax-dynamic-import

Then recompile files with:
npm run dev

@lrembacz Thanks, Works perfect!
Is there some way to automatically create a legacy build so browsers like IE11 use that build?
I know Vue-cli 3.0.0 provides that option 'https://cli.vuejs.org/guide/browser-compatibility.html#modern-mode'. Here some more info: 'https://philipwalton.com/articles/deploying-es2015-code-in-production-today/'

@lrembacz Thanks.
Only one problem I see is that I have versioning enabled (mix.version()). Lazy loaded files does not get their version.

@muffeen Already a pull request for this. Waiting for merge. https://github.com/JeffreyWay/laravel-mix/pull/1557

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mstralka picture mstralka  路  3Comments

pixieaka picture pixieaka  路  3Comments

RomainGoncalves picture RomainGoncalves  路  3Comments

jpmurray picture jpmurray  路  3Comments

mementoneli picture mementoneli  路  3Comments