vuejs3cdnvuetifyjs3import-maps

"Cannot read properties of undefined (reading 'defineComponent')" when loading Vuetify3 from CDN in importmap


According to CDN section of the document Get started with Vuetify3, I've prepared CDN links of vuetify on index.html and calling createVuetify() on main.js as follows:

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <link rel="icon" href="/favicon.ico">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vite App</title>
    <!-- https://stackoverflow.com/a/62282239/11073131 -->
    <script type="importmap">
      {
        "imports": {
          "vue": "https://cdn.jsdelivr.net/npm/vue@3/dist/vue.esm-browser.prod.js",
          "vue-router": "https://cdn.jsdelivr.net/npm/vue-router@4/dist/vue-router.esm-browser.js",
          "@vue/devtools-api": "https://cdn.jsdelivr.net/npm/@vue/devtools-api@6/lib/esm/index.js"
        }
      }
    </script>

    <!--vuetify-->
    <link href="https://cdn.jsdelivr.net/npm/vuetify@3.1.14/dist/vuetify.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/vuetify@3.1.14/dist/vuetify.min.js">

</script>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.js"></script>
  </body>
</html>

main.js

import { createApp } from 'vue'
import App from './App.vue'
import Home from '/src/views/Home.vue'
import About from '/src/views/About.vue'
import { createRouter, createWebHistory } from 'vue-router'

import './assets/main.css'

// router
const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
]

const router = createRouter({
  history: createWebHistory(),
  routes, // short for `routes: routes`
})

// vuetify
const { createVuetify } = Vuetify
const vuetify = createVuetify()

createApp(App).use(router).use(vuetify).mount('#app')

Run yarn dev and read this site from the browser, this main.js get the error of

Cannot read properties of undefined (reading 'defineComponent')

enter image description here

I have no idea what was wrong or lacked steps.


Solution

  • The .js version of Vuetify expects Vue to be available in the global scope, but you are importing it as a named ESM import.

    Try importing Vuetify as ESM module as well, check https://cdn.jsdelivr.net/npm/vuetify@3.1.14/dist/ for the correct sources:

    <script type="importmap">
      {
        "imports": {
          "vue": "https://cdn.jsdelivr.net/npm/vue@3/dist/vue.esm-browser.prod.js",
          "vue-router": "https://cdn.jsdelivr.net/npm/vue-router@4/dist/vue-router.esm-browser.js",
          "@vue/devtools-api": "https://cdn.jsdelivr.net/npm/@vue/devtools-api@6/lib/esm/index.js",
          "vuetify": "https://cdn.jsdelivr.net/npm/vuetify@3.1.14/dist/vuetify.esm.js"
        }
      }
    </script>
    

    Then you can import it like other modules:

    import { createVuetify } from 'vuetify'
    const vuetify = createVuetify()
    

    Where the name has to be the key from the importmap.


    Note that importmap is a pretty new feature and there seem to be bugs around the issue in Firefox version 112.0.1, but not in 113.0b5. Same in Chrome version 110.0.5481.177, but not in 112.0.5615.49.


    This works when I load it from a local webserver:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8">
        <link rel="icon" href="/favicon.ico">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Vite App</title>
        <script type="importmap">
          {
            "imports": {
              "vue": "https://cdn.jsdelivr.net/npm/vue@3/dist/vue.esm-browser.prod.js",
              "@vue/devtools-api": "https://cdn.jsdelivr.net/npm/@vue/devtools-api@6/lib/esm/index.js",
              "vuetify": "https://cdn.jsdelivr.net/npm/vuetify@3.1.14/dist/vuetify.esm.js"
            }
          }
        </script>
        <script type="module" src="/main.js"></script>
        <link href="https://cdn.jsdelivr.net/npm/vuetify@3.1.14/dist/vuetify.min.css" rel="stylesheet">
      </head>
      <body>
        <div id="app"></div>
      </body>
    </html>
    
    import { createApp, ref } from 'vue'
    import { createVuetify } from 'vuetify'
    
    const vuetify = createVuetify()
    
    const App = {
      template: `
          <v-app>
            <v-main>
              <v-switch v-model="switcher"/> {{ switcher }}
            </v-main>
          </v-app>
      `,
      data(){
        return {
          switcher: ref(true)
        }    
      }
    }
    
    createApp(App).use(vuetify).mount('#app')