Pass global JSON to Vue app from flask webserver

1.2k views Asked by At

I have a vue-router enabled app using single-file .vue components, bundled using browserify. This app is served by a flask webserver, which passes it global config settings (page title, layout order, etc) as JSON. I've been struggling to pass the globals into the app in a clean way.

main.js (used as entry point for browserify):

var Content = require('./vue/Content.vue');
var App = Vue.extend();
var router = new VueRouter({ history: true });
router.map({
  '/': { component: Content, name: 'home' }
});
router.start(App, '#app');

index.html, served by flask webserver

<body>
{% with ga_id = ''|get_env('GA_ID') %}
  <div id="app" ><router-view ga-id={{ga_id}} global-settings={{globalsettings|tojson|safe}}></router-view></div>
{% endwith %}
  <script type="text/javascript">
    window.global_settings = {{globalsettings|tojson|safe}};
  </script>
  <script src="/js/build.js" defer></script>
</body>

App.vue, main component of the app:

<template>
</template>
<script type="text/javascript">
  var app = {
    props: ['gaId', 'globalSettings'],
   ready: function ready() {
      console.log(this.gaId); //returns expected string
      console.log(this.globalSettings); //truncated at first space in the string
      console.log(window.global_settings); // returns expected json
    },
  module.exports = app;
</script>

and for completeness' sake, routes.py:

@APP.route('/', methods=['GET'])
def index():
    settings = APP.app_config['settings']
    return render_template('index.html', rawsettings=settings)

It feels wrong to pass Vue a global variable by setting it on the window, but I haven't been able to pass it in otherwise.

I tried using the data function in Vue.extend in main.js:

Vue.extend({ 
  data: function() {
    return { 
      global: 'test' 
    }
  }
})

but this.global is undefined in App.vue. Is there a better pattern I should be using?

1

There are 1 answers

2
Rashad Saleh On

This feature from Vue.js official API documentation means that inside any component, this.$root will reference the root Vue instance, or, in your case, the App variable.

So, ideally, you want to change this line:

window.global_settings = {{globalsettings|tojson|safe}};

to

App.global_settings = {{globalsettings|tojson|safe}};

and then you can access global_settings from any component using this.$root.global_settings.

However, depending on how your code is bundled, App might return undefined in the global scope. Which leads me to a better point altogether...

consider using vuex

vuex is the official state manager for vuejs. Basically it serves as a center for shared state (or data) accross all components, which fits the concept of "global settings" well! Vuex also comes with its very powerful features especially for large scale applications. However, if you don't plan on using vuex extensively, then something like my earlier approach might be more desirable or lightweight.