1

I have main.js and app.vue file

main js file inner look like this

var a = 1;
import App from './App.vue'
new Vue({
  el: '#app',
  render: h => h(App)
})

in App.vue file i want to console.log(a) return error a is not defined why ? What is wrong ?

Murad Sofiyev
  • 790
  • 1
  • 8
  • 25
  • The `a` variable is not in the scope of that component – thanksd Jun 15 '17 at 20:42
  • 1
    The idea of modules is that they encapsulate values defined in them - so that those values are not available elsewhere unless you export them. So you are basically doing things backwards. Imports do not work like includes in languages like PHP, and that's a good thing. Here's a nice resource you can use to learn how ES6 modules work: hacks.mozilla.org/2015/08/es6-in-depth-modules – sbking Jun 15 '17 at 20:45
  • @sbking I think my code compile look like that var a = 1; after App.vue file inner So i think a is global variable and after import module must be use a variable – Murad Sofiyev Jun 15 '17 at 20:51
  • @MuradSofiyev That is not how ES6 modules work, like I said. Any variables you define within an ES6 module are *locally scoped to that file*. If you want them to be accessible from other files, you have to [export](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) them, and then [import](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) them in the other file. Or you can attach them as properties on the global object (`window` in browsers, `global` in node.js), but that pretty much negates the benefits of using modules. – sbking Jun 15 '17 at 20:54
  • Thabk you so much. I read the link you sent me – Murad Sofiyev Jun 15 '17 at 20:57
  • @sbking So sory Do you can show me after compile my code what it looks like? – Murad Sofiyev Jun 15 '17 at 21:02
  • @MuradSofiyev That depends on what compiler you are using.... But you don't have to worry about what your code looks like after it is compiled. The ES6 module and `import`/`export` syntax is well defined and should work the way it was designed to work. See my answer. – sbking Jun 15 '17 at 21:05
  • Another small question console.log(1) after import App from './App.vue' in my App.vue file console.log(2) and when i run code my console show 2 1 – Murad Sofiyev Jun 15 '17 at 21:15
  • @MuradSofiyev when you import a file, it runs the file's code, but in its own scope (without access to the variables in main.js). So if the console.log(1) is placed *after* the import statement, then it won't run until App.vue's script has run. You could export a function from App.vue, and then call that function from main.js whenever you want to control the timing of execution. I have updated my answer to show you an example. – sbking Jun 15 '17 at 21:19
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/146798/discussion-between-sbking-and-murad-sofiyev). – sbking Jun 15 '17 at 21:19

3 Answers3

4

You need to export the variable, and then import it into another file where you want it. The best way to do that would be to put the variable a in its own module file. This allows you to avoid using global variables, which pretty much negate the purpose of modules!

a.js:

export const a = 'foo'

App.vue:

<script>
  import { a } from './a.js'
  console.log(a) // foo

  console.log(1)
  export function log3() {
    console.log(3)
  }
</script>

main.js:

import { log3, default as App } from './App.vue'
console.log(2)
log3()

new Vue({
  el: '#app',
  render: h => h(App)
})

import { a } from './a.js'
console.log(a) // foo

Here is what will be logged to the console:

  • 'foo' (from App.vue)
  • 1 (from App.vue)
  • 2 (from main.js)
  • 3 (from main.js calling the function log3 from App.vue)
  • 'foo' (from main.js)

Now both App.vue and main.js have access to a, because they have explicitly imported it. The fact that App.vue has access to a has nothing to do with the fact that main.js also has access to a.

sbking
  • 7,630
  • 24
  • 33
1

The simplest thing you can do I guess is define data properties insode root instance, and access them as this.$root.myProperty from components:

new Vue({
  el: '#app',
  data: {
    myGlobal: 'Hi there'
  },
  components: {
    'child' : {
      template: `<p>{{ text }}</p>`,
      data: function() {
       return {
          text: this.$root.myGlobal
        }
      }
    }
  }
});
<script src="https://unpkg.com/vue/dist/vue.js"></script>

<div id="app">
  <child></child>
</div>

Another option - a simple plugin as a central storage: https://stackoverflow.com/a/44517332/7636961

Egor Stambakio
  • 17,836
  • 5
  • 33
  • 35
  • Why not just put the "global" variable in its own module and then import it where needed? Why use modules at all if you're just going to use global variables? – sbking Jun 15 '17 at 21:03
  • @sbking why use a module for a variable which you can just put into root data object? – Egor Stambakio Jun 15 '17 at 21:04
  • What if another component wants to put a property with the same name onto the root data object? – sbking Jun 15 '17 at 21:09
  • 1
    @sbking he didn't suggest a global. I don't even know what you mean with that last comment. Components in Vue don't set properties of other components or the root. Passing it as a prop would be more idiomatic than using $root. – Bert Jun 15 '17 at 21:18
  • @BertEvans He uses the name `myGlobal` in his code snippet... Yes, I realize that passing as a prop is more idiomatic, and my wording was incorrect. What I meant was what if another component wanted to use a different $root property with the same name? The properties that exist higher in the hierarchy should not affect the correctness of lower level components. – sbking Jun 15 '17 at 21:30
  • @sbking Could you describe a situation for me where the $root could have two properties with the same name? $root is always the Vue instance. https://vuejs.org/v2/api/#vm-root – Bert Jun 15 '17 at 21:34
  • @BertEvans It can't, that's the problem. If developer Bob Smith writes a component that accesses a root property called `foo`, and developer Joe Schmoe writes a component that also accesses a root property called `foo`, they better hope that root property is definitely intended to be used for the exact same purpose in both cases, and isn't just a case of two developers coming up with the same name for two different variables. – sbking Jun 15 '17 at 21:37
  • What I'm trying to say is that `$root` is analogous to a global namespace for the Vue component hierarchy, and that comes with similar problems you would encounter with any global namespace. Why should a variable that is needed for one or two components be automatically exposed to every single component in the entire hierarchy? – sbking Jun 15 '17 at 21:43
  • @sbking I understand your line of thought, thank you for clarifying. I think the practice of reaching out of a component to get a value is generally a bad idea. Defining a value on the Vue instance and passing it down to components that need it, however, is standard practice. – Bert Jun 15 '17 at 21:49
0

a is not defined in your App component but directly in main.js.

You may want to use a global variable. (see also this thread for global variable in vuejs)

Ulysse BN
  • 10,116
  • 7
  • 54
  • 82