54

Trying to follow some Vue tutorials and I can't currently import Vue in a .js file and then import this file in my index.html. This is how I'm importing the script in my index.html:

<script src="./js/main.js" type="module"></script>

If I do this in my main.js file:

import Vue from 'vue';

I get the following error in the browser console:

Uncaught TypeError: Failed to resolve module specifier "vue". Relative references must start with either "/", "./", or "../".

If my import line to:

import Vue from '../../node_modules/vue';

Then I get a different error:

http://localhost:63342/vue-official-tutorial/node_modules/vue net::ERR_ABORTED 404 (Not Found)

What am I doing wrong?

zerohedge
  • 3,185
  • 4
  • 28
  • 63
  • are you working with webpack or vue cli 3 ...? – Boussadjra Brahim Oct 02 '18 at 16:23
  • @boussadjrabrahim - Thanks. To be honest I'm not very sure. I did do `npm install vue` to be able to do `import Vue from 'vue'` without ESLint complaining. But I don't recall having installed `vue cli`. I do have a `package.json` file in the project's root folder that includes `vue` as a dependency after I've installed `vue` with `npm` – zerohedge Oct 02 '18 at 16:25
  • You just show the import of Vue. How did you load the vue.js script in your HTML? – Aaron Digulla Sep 16 '19 at 08:22
  • I've had a similar issue and have asked a question about it here: https://stackoverflow.com/questions/72368150/how-to-do-module-resolution-when-an-npm-package-contains-multiple-namespaces-sub – timhc22 May 24 '22 at 19:01

3 Answers3

38

As of June 2020

The way you can use ES modules in your Browser directly is this:

  1. Use the ESM version of your dependencies (the one that has import instead of require).

    For example, Vue ESM version is available at: https://cdnjs.cloudflare.com/ajax/libs/vue/3.2.41/vue.esm-browser.prod.js

  2. Make your browser work with the experimental importmap feature.

    update 2022: major browsers now support Import maps

    For older versions of Chrome this is under chrome://flags#enable-experimental-productivity-features (latest Chrome versions moved this under chrome://flags#enable-experimental-web-platform-features)

  3. Create an importmap in your HTML file.

    It only works with inline <script> tags at the moment in Chrome. For example:

<script type="importmap">
  { "imports": {
      "vue":        "https://cdnjs.cloudflare.com/ajax/libs/vue/3.2.41/vue.esm-browser.prod.js",
      "vue-router": "https://cdnjs.cloudflare.com/ajax/libs/vue-router/4.1.5/vue-router.esm-browser.min.js"
  } }
</script>    

  1. Load your own code as an ESM module.
<script type="module" src="./main.js"></script>
  1. In your own scripts, and the scripts that you import - you can now successfully import from named modules.

Import Maps Documentation


Full example:

<html>
<body class="app">

<script type="importmap">
  { "imports": {
      "vue":               "https://cdnjs.cloudflare.com/ajax/libs/vue/3.2.41/vue.esm-browser.prod.js",
      "vue-router":        "https://cdnjs.cloudflare.com/ajax/libs/vue-router/4.1.5/vue-router.esm-browser.min.js",
      "@vue/devtools-api": "https://unpkg.com/@vue/devtools-api@6.4.5/lib/esm/index.js"
  } }
</script>

<script type="module">
  import { createRouter, createWebHistory } from 'vue-router'
  import { createApp } from 'vue'

  const app = createApp({ template: 'Hello world.' })
  const router = createRouter({
    routes: [{ path: '/:pathMatch(.*)*', component: app }],
    history: createWebHistory()
  })
  app.use(router)

  document.addEventListener('DOMContentLoaded', () => app.mount('.app'));
</script>

</body>
</html>
aljgom
  • 7,879
  • 3
  • 33
  • 28
Evgeny
  • 6,533
  • 5
  • 58
  • 64
  • 1
    Note to readers: [**Firefox** currently seems to have a bug](https://discourse.threejs.org/t/solved-importmaps-broken-on-firefox-which-now-supports-importmaps/48413/6) where the `type="importmap"` script must come first to work. Check how you've ordered things if import mapping works fine for you on Chrome, etc. and yet Firefox gives you the error, "The specifier 'vue' was a bare specifier, but was not remapped to anything." – MarredCheese Jun 15 '23 at 05:37
11

UPDATE (2020-05-10)

Using ES6 modules without Webpack


If you are working with ES6 then you should NOT manually inserting your main.js into index.html - this will be handled by Webpack. Actually, the simplest tutorial for Vue goes like this:

  1. npm install -g vue-cli
  2. vue init webpack my_project
  3. npm run dev (and start developing - result is available on http://localhost:8080)
  4. npm run build (result is available inside the ./dist folder of your project

Also, you should import Vue like this

import Vue from 'vue';

and not like this

import Vue from '../../node_modules/vue';

EDIT

Okay, if you insist on going through the beginners' path and not using Webpack and single-file Vue components - then you should start like this:

<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
    <title>My beginners project</title>
    <link rel="stylesheet" type="text/css" href="/assets/css/styles.css" />
  </head>

  <body>
    <div id="app">
      <router-view></router-view>
    </div>
    <!-- templates for your components -->
    <template id="login">
      <div>test</div>
    </template>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>
    <script src="https://unpkg.com/vue-router@3.0.1/dist/vue-router.js"></script>
    <!-- code for your components -->
    <script type="text/javascript" src="/app/login.js"></script>
    <!-- Vue Root component should be last -->
    <script type="text/javascript" src="/app/app.js"></script>
  </body>

</html>

And your /app/app.js will look like this:

var badRoute = Vue.component('bad-route', {
    template: '<div id="bad_route"><h1>Page Not Found</h1><p>Sorry, but the page you were trying to view does not exist.</p></div>'
});
var vue_router = new VueRouter({
    base: '/app'
    , mode: 'hash'
    , routes: [{
        path: '/'
        , redirect: '/login'
    }, {
        path: '/login'
        , component: loginForm
        , name: 'LOGIN'
    }, {
        path: '*', // should be last, otherwise matches everything
        component: badRoute
        , name: 'NOT FOUND'
    }]
});
// Main application
var vue_app = new Vue({
        router: vue_router
    , })
    .$mount('#app');

And your /app/login.js component will look like this:

var loginForm = Vue.component('login-form', {
    template: '#login', // should match the ID of template tag
    data: function() {
        var a = {
            username: ''
            , password: ''
        , };
        return a;
    }
    , methods: {}
});
IVO GELOV
  • 13,496
  • 1
  • 17
  • 26
  • 8
    I'm sorry. I'm sure there's something I'm missing but I don't get how this answers my question. If I simply remove the manual import of the `main.js` script tag, then...nothing happens. – zerohedge Oct 02 '18 at 17:13
  • 1
    Also: I am doing `import Vue from 'vue'` but getting a syntax error on the JS file "Uncaught SyntaxError: Unexpected identifier" in the line where I import it like this. – zerohedge Oct 02 '18 at 17:15
  • 1
    I will try to clarify the steps. On step 1 you install Vue-CLI tool globally on your computer. On step 2 you use the tool to scaffold an empty Vue project using the official Webpack template. On step 3 you start a development web server so that you can immediately see how your new web applications looks like (by opening the specified URL in your browser). Here you write your code in `main.js`, then in `App.vue` and then in your other single-file Vue components (if you create such ones). On step 4 you build your project and deploy `./dist` folder onto your hosting. – IVO GELOV Oct 02 '18 at 17:23
  • 8
    Sorry. I still don't understand why what I'm doing as per the above isn't working. I don't have vue-cli installed because the official tutorial explicitly states that beginners shouldn't go that route. Why can't I use `import Vue from 'vue'` in my `main.js` file and simply have that render correctly? (I'm not "complaining" to you, this was my actual question) – zerohedge Oct 02 '18 at 17:25
  • This answer is correct and complete. My answer (below?) may help clarify the issue. – Glen Little Sep 30 '19 at 23:20
  • Webpack is no longer necessary with ES modules. – 8f7ca04d817b1696 Nov 27 '19 at 19:53
  • I would also think that webpack is not necessary with ES modules. But for vue i also get this error. Maybe it's loading the wrong type of vue module from node-modules? – Catweazle May 08 '20 at 19:45
  • @Catweazle Without Vue-CLI you need to load `vue.js` rather than `vue.runtime.js` – IVO GELOV May 09 '20 at 16:39
  • 1
    @zerohedge If you work with modules but without Vue-CLI then you should read this article - https://vuejsdevelopers.com/2019/02/04/vue-es-module-browser-build/ – IVO GELOV May 09 '20 at 16:41
  • Thanks @zerhedge! Following the input from the artile, I was able to get it working by 1/ cp node_modules/vue/dist/vue.esm.browser.js vue.js 2/ in my module: import Vue from './vue.js' – Catweazle May 09 '20 at 21:22
  • 1
    I don't think this answers the question. The answer from @evgeny actually does. – Andy Reagan Dec 16 '20 at 21:12
  • Has anyone other answer? , iinstalled all of this and still have that error – fsalazar_sch Mar 24 '23 at 04:26
3

You can only use "import vue..." if you are using the CLI and webpack, etc.

If you are using Vue directly in a web page, you can follow the instructions at https://v2.vuejs.org/v2/guide/installation.html#Direct-lt-script-gt-Include and include a line like this in your HTML file:

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

Do this before you import your own script, and then Vue will be defined and you don't need to import it again. Import your script without the "module" attribute. In the script, you can run:

var x = new Vue({ 
  el: '#myApp',
  ... all the other stuff ...
})

This assumes that somewhere on your HTML page you have:

<div id=myApp></div>
tony19
  • 125,647
  • 18
  • 229
  • 307
Glen Little
  • 6,951
  • 4
  • 46
  • 68