Search code examples
javascriptvue.jsvuejs2vue-routerpreloader

How to run preloader before page starts loading VUE.JS


So I'm trying to set up a preloader but before it starts running the preloader it starts downloading a lot of CSS/js etc files which should not happen since the preloader should run before it starts downloading vue stuff and only stops when the page is ready. This problem is not noticed in fast connections but it's very clear under FAST 3G or SLOW 3G.

I saw some examples using vue routing but I'm routing Vue with flask which means that I shouldn't be able to use the routing way at least that I know.

Is there a way to set it up so it loads the preloader and then starts loading the other stuff in the background?

I'm using vue plugin Vue-loading-overlay for the preloader.

Part of my code in case it's necessary:

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<template>
  <div id="app">
    <vue-topprogress ref="topProgress" :color="'#1d1d25'"
                     :height="5" :errorColor="'#f81732'"/>
    <loading :active.sync="isLoading"
        :is-full-page="true" :opacity="1">
      <img src="../assets/images/testGif.gif" alt="this slowpoke moves"  width=250/>
    </loading>
  </div>
</template>
<script>
  import Loading from 'vue-loading-overlay';
  import 'vue-loading-overlay/dist/vue-loading.css';

  export default {
    name: 'index',
    components: {
      Loading,
    },
    data() {
      return {
        isLoading: true,
      };
    },
    mounted() {
      document.onreadystatechange = () => {
        if (document.readyState === 'complete') {
          this.isLoading = false;
        }
      };
    },
  }
</script>


Solution

  • I can think of 2 solutions: async route, and async component.

    Async route

    Here in the routes.js file we define main route / with a simple LoginPage component which will be included in the main JS bundle file. We also define /app route with an async component - this one would be loaded only if user open /app route. A comment with webpackChunkName tells Webpack to compile that component to another file with that specific name.

    routes.js

    import LoginPage from '../pages/login-page'
    
    const routes = [
     {
      path: '/',
      component: LoginPage
     },
     {
      path: '/app',
      component: () => import('../pages/app-wrapper.vue' /* webpackChunkName: "page--app-wrapper" */),
      children: [
       // child routes
      ]
     }
    ]
    

    Now in Your login-page component You can do some stuff, like loading config by AJAX, and then go to /app route.

    Async component

    Another solution could be using a dynamic component. Initially it could be a simple loaderComponent and after loading finishes it would become appWrapperComponent and only then its definition would be loaded from another bigger chunk file.

    <template>
      <div :is="componentName"></div>
    </template>
    
    export {
      data() {
        componentName: 'loaderComponent'
      },
      components: { loaderComponent },
      mounted() {
        this.$axios('/api/config.json') // its' just an example of loading something
        .then(config => {
          this.$root.config = config; 
          this.componentName = 'appWrapperComponent'; // this changes component name
        });
      }
    }
    

    Now to make it work we need to makeappWrapperComponent async.

    Vue.component('appWrapperComponent', () => ({
        component: import('../pages/app-wrapper.vue' /* webpackChunkName: "pages--app-wrapper" */),
        delay: 200,
        timeout: 5000
    }));