Search code examples
jqueryvue.jsvuejs3vue-routerfont-awesome

JavaScript packages not found/loaded when navigating using vue-router


I am building a Vue3 app which uses vue-router. I initialized the <router-view /> component and the necessary router-links. When I click on a <router-link> element, I am taken to the corresponding page, but the JavaScript modules I used (apexcharts, fontawesome, ...) are not loading.

An example of this is the <i> element, which the fontawesome package should render as an icon. Here is a snippet from my source code where I use this:

<i class="ti-trash"></i> Cancel

The <i> element can be found in the HTML by using the Chrome DevTools, but it is not rendered into an icon, which is what I would have wanted to happen.

Here are relevant snippets of my source code:

main.js:

import { createApp } from 'vue'
import Dashboard from '@/components/Dashboard.vue'
import InstanceCreationForm from '@/components/InstanceCreationForm.vue'
import { createRouter, createWebHistory } from 'vue-router'
import App from "@/App.vue";

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/',
      component: Dashboard
    },
    {
      path: '/create-instance',
      component: InstanceCreationForm
    }
  ]
})


const app = createApp(App)

app.use(router)
app.mount('#app')

Dashboard.vue:

<template>
    <main-template>
        <template v-slot:content>
            <router-link to="/create-instance">
                Add New
            </router-link>
        </template>
    </main-template>
</template>



<script>
import "../js/vendors.min.js" //  <--  Contains jQuery, fontawesome
import "../assets/icons/feather-icons/feather.min.js"
import "../assets/vendor_components/apexcharts-bundle/dist/apexcharts.js"
import "../js/demo.js"
import "../js/jquery.smartmenus.js"
import "../js/menus.js"
import "../js/template.js"
import "../js/pages/dashboard.js"

import MainTemplate from "@/components/MainTemplate.vue";

export default {
    name: "Dashboard",
    extends: MainTemplate,
    components: {MainTemplate}
    metaInfo: {
        script: [
            {src: "https://cdn.amcharts.com/lib/4/core.js", async: true, defer: true},
            {src: "https://cdn.amcharts.com/lib/4/charts.js", async: true, defer: true},
            {src: "https://cdn.amcharts.com/lib/4/themes/animated.js", async: true, defer: true},
        ]
    }
}
</script>

InstanceCreationForm.vue:

<template>
    <main-template>
        <template v-slot:content>
            <router-link to="/" id="cancel-button" type="button">
              <i class="ti-trash"></i> Cancel
            </router-link>
        </template>
    </main-template>
</template>

<script>
import MainTemplate from "@/components/MainTemplate.vue";

export default {
    name: "InstanceCreationForm",
    components: {MainTemplate},
    extends: MainTemplate,
}
</script>

I could solve the problem by using anchor tags (<a>) to redirect between routes, but it feels inefficient to reload the entire page every time the user moves pages. The only other solution I could find was either force reloading my component on page load which effectively does the same thing.

Why aren't my JavaScript packages loading on vue-router redirect?


Solution

  • I found the answer!

    The solution was to add the library as a <src> tag after the component has mounted:

    MainTemplate.vue

    import "../js/vendors.min.js"
    import "../assets/icons/feather-icons/feather.min.js"
    import "../assets/vendor_components/apexcharts-bundle/dist/apexcharts.js"
    import "../js/demo.js"
    import "../js/jquery.smartmenus.js"
    import "../js/menus.js"
    import "../js/template.js"
    
    export default {
    name: "MainTemplate",
    methods: {
        loadLibrary(libraryPath) {
            let newScript = document.createElement('script')
            newScript.setAttribute('src', libraryPath)
            document.head.appendChild(newScript)
        }
    },
    mounted() {
        if (this.$options.name === 'MainTemplate') {
            this.loadLibrary("/src/js/vendors.min.js")
            this.loadLibrary("/src/assets/icons/feather-icons/feather.min.js")
            this.loadLibrary("/src/assets/vendor_components/apexcharts-bundle/dist/apexcharts.js")
            this.loadLibrary("/src/js/demo.js")
            this.loadLibrary("/src/js/jquery.smartmenus.js")
            this.loadLibrary("/src/js/menus.js")
            this.loadLibrary("/src/js/template.js")
        }
    }
    }
    

    I chose to put this code in my MainTemplate (because my other components extend from it) rather than use it in each one.

    I also kept my original import statements so that they run the first time the site is loaded.