Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

zachleigh's avatar

Speed up Vue rendering?

Vue components in my current project are taking about 3 seconds to render on mobile. Its starting to feel pretty slow... What can I do about this? How can I at least figure out what the hold up is?

App is not a SPA and has a single Vue instance with about 20 components registered. The server caches all resources so loading the js etc. is not the issue. Ive dived into the browser tools timeline to see what was going on, but I wasnt able to find anything useful...

0 likes
15 replies
willvincent's avatar

Are you using all of those components on every page it's loaded on? If not you might consider splitting it up so only the necessary code is loaded on each page. JS is always slower on mobile devices, so minimizing the amount that you're shoving at them is probably a good idea.

~3sec seems awfully slow for Vue though. Is vue making separate requests to fetch data after the components load, or are you serving that all up with the initial request? Lots of computation and filtering going on, or everything fairly basic?

1 like
willvincent's avatar

@ejdelmonico brings to mind another consideration.. are you serving all of your css/js directly, or using CDNs? I've actually encountered situations where the CDN was considerably slower than serving the code directly.

zachleigh's avatar

@ejdelmonico Yeah, Ive run it through Google page speed and a few others. Nothing is blocking.

@willvincent No, Im not using all the components on every page. Ive been considering splitting it up, but I generally dont like to do that unless I have to. If I have a huge js file, it of course slows down the download, but does that also slow down the javascript execution? Im not really sure how javascript execution works, especially when using webpack...

There is really no computation at all. On one page, I simply have a wrapper component that has a div, header etc. and then a loop that goes through a list of no more than 5 things rendering a component for each one.

willvincent's avatar
Level 54

I'm pretty sure the browser will interpret all of the JS, whether it's used on the page or not. This is why especially in IE a small syntax error that doesn't affect other browsers can cause an entire page to not work properly/etc..

I think you'd be best off packaging your vue components together for each specific page, so only those needed are added to the page. Since it's not a SPA, there's no reason to shove all of that code at the browser on every page.

1 like
willvincent's avatar

I'm doing something like that on a project myself...

For each page that needs specific components, I have a JS file something like this:

import ProjectInfo from "./components/project-detail.vue";
import ProjectForecasts from "./components/project-detail-forecasts.vue";
import ProjectHistory from "./components/project-detail-history.vue";
import Modal from "./components/modal.vue";

// Filters
Vue.use(require('./filters/number-filter'));
Vue.use(require('./filters/moment-filter'));

// Directives


new Vue({
  el: '#wf-app',
  components: {
    ProjectInfo,
    ProjectForecasts,
    ProjectHistory,
// --- snip ---

That, as you see pulls in the components relevant to that page. Then in the blade template for that page, I inject it accordingly:

@extends('layouts.default')

@section('content')
    <div id="wf-app" v-cloak>
        <project-info :project.sync="project"></project-info>
        <project-forecasts :project.sync="project"></project-forecasts>
        <project-history :project.sync="project"></project-history>
        <modal></modal>
    </div>
@stop

@section('scripts')
    <script>var project = {id: '{{ $project['id'] }}'};</script>
    <script src="/js/pg-project.js"></script>
@stop
2 likes
zachleigh's avatar

@willvincent I think you're right. Ive been experimenting and by limiting my js to only what is needed, I can cut the load time for most pages down by over a second. Thanks!

1 like
zachleigh's avatar

@willvincent If you have multiple Vue instance bundles, how are you doing things in your gulp file? Webpack?

zachleigh's avatar

@willvincent Thanks. I switched to using webpack + vueify and and am having some issues with compiling multiple bundles. How do you accomplish this browserify?

willvincent's avatar

With browserify I just call it multiple times, like this:

elixir(function (mix) {
  mix.sass('app.scss')
    .sass('vendor.scss')
    .scripts(['tables.js'], 'public/js/tables.js')
    .browserify('app.js')
    .browserify('vue/pg-summary.js')
    .browserify('vue/pg-forecasts.js')
    .browserify('vue/pg-billing.js')
    .browserify('vue/pg-change-log.js')
    .browserify('vue/pg-project.js');
});

But as I understand it you can't do that (at least at the moment) with webpack or it'll blow up on you -- at least through elixir anyway you can't call webpack multiple times.

However, I don't know if anyone has tried doing it like this, or if it would even work:

elixir(function (mix) {
  mix.sass('app.scss')
    .sass('vendor.scss')
    .webpack('app.js');
});

elixir(function (mix) {
  mix.webpack('something.js');
});

elixir(function (mix) {
  mix.webpack('something_else.js');
});

Might be worth a try.

I've never used webpack, so not really going to be much of a resource for you in that regard.

prasinoulhs's avatar

Here is how i generate multiple bundles with webpack.

const elixir = require('laravel-elixir');
require('laravel-elixir-vue-2');

const jsDir = __dirname + '/resources/assets/js/';

elixir(mix => {

    Elixir.webpack.mergeConfig({
        entry: {
            'app': jsDir + 'app.js',
            'app2': jsDir + 'app2.js',
            'app3' : jsDir + 'app3.js'
        },
        output: {
            path: __dirname + '/public/js/',
            filename: '[name].js'
        }
    });

    mix.webpack('app.js');
});

This will create app.js, app2.js and app3.js. These are standalone bundles, that contain the runtime.

You can extract the runtime to a different file with this config

const webpack = require('webpack');
....
Elixir.webpack.mergeConfig({
    entry: {
        'app': jsDir + 'app.js',
        'app2': jsDir + 'app2.js',
        'app3' : jsDir + 'app3.js'
    },
    output: {
        path: __dirname + '/public/js/',
        filename: '[name].js'
    },
    plugins: [ new webpack.optimize.CommonsChunkPlugin('init') ]
});

this will produce an extra file init.js that contains the runtime.

Finally, if you want to bundle common modules together you can use this config.

const webpack = require('webpack');
....
Elixir.webpack.mergeConfig({
    entry: {
        'app': jsDir + 'app.js',
        'app2': jsDir + 'app2.js',
        'app3' : jsDir + 'app3.js',
        'vendor': ['vue', 'undescore']
    },
    output: {
        path: __dirname + '/public/js/',
        filename: '[name].js'
    },
    plugins: [ new webpack.optimize.CommonsChunkPlugin({name: 'vendor'}) ]
});

which will bundle the runtime and any modules specified in the vendor entry together.

More info about code splitting and the options for the CommonsChunkPlugin.

I just switched to this config so there may be problems with it that i didn't encounter.

4 likes
zachleigh's avatar

@willvincent I've been doing the same with webpack, but its kind of a nightmare. It looks like every webpack call gets a different watcher so when I run gulp watch I get massive notification spam and a lot of elixir errors related to webpack.

@prasinoulhs Thank you! Your first webpack config setup does exactly what I want.

1 like
jekinney's avatar

@willvincent is 100% correct about browser running your js. Having one large file can/does slow performance as it's checking the dom while rendering etc.

As was stated, where applicable try to link (for example) jquery, vue etc into one main file set on your master. Then utilize page specific on each page. I set a yield for CSS and js on the master layout just in case. Habit.

Also many times people forget on each page reload everything it checked for changes and re-executed etc.. setting the headers to not request, unless possible updates more frequently, I suggest an hour otherwise load from cache.

1 like

Please or to participate in this conversation.