Search code examples
javascriptvue.jsmomentjsvuexvuejs3

Using momentJS globally in VueJS 3


In VueJS 2, I could use momentJS globally like this:

in main.js:

import moment from 'moment';
moment.locale('fr');
Object.defineProperty(Vue.prototype, '$moment', { value: moment });

in any component:

{{ item.date_creation?$moment(item.date_creation).format('l'):'No date'}}

In VueJS 3 I tried to do the following in main.js:

import { createApp } from 'vue';
import moment from 'moment';
import App from './App.vue';
import './registerServiceWorker';
import router from './router';
import store from './store';

moment.locale('fr');

createApp(App).use(moment).use(store).use(router)
  .mount('#app');

But actually I can't use "moment" in any of my component, I have to import "moment" in each of them. Isn't there a better solution? I read a lot of documentation and tutorials, I didn't see anything good... Thanks in advance.

Edit: here is how I use $moment in my component:

<template>
  <div class="xx" :key="'title-'+myReactiveVariable.title">
    <h1>{{ myReactiveVariable.title }}</h1>
    <div class="yy">
      {{ myReactiveVariable.content }}
    </div>
    <footer>
      Sent on
      {{ myReactiveVariable.date }}
      by {{ myReactiveVariable.author }}
      <who-is-it :idSent="id" :key="'ID-'+id">
      </who-is-it>
    </footer>
  </div>
</template>

<script>
// @ is an alias to /src
import WhoIsIt from '@/components/WhoIsIt.vue';

import {
  defineComponent, reactive, onMounted, watch, ref,
} from 'vue';

import axios from 'axios';

import { useRoute } from 'vue-router';

export default defineComponent({
  name: 'XXX',
  components: {
    WhoIsIt,
  },
  setup() {
    const route = useRoute();

    const myReactiveVariable = reactive({
      title: '',
      content: '',
      date: '',
    });

    const id = ref('');

    async function fetchArticle(id) {
      console.log(`A: ${process.env.VUE_APP_API_URL} - ${id}`);
      const res = await axios.get(`${process.env.VUE_APP_API_URL}/whoarewe/${id}`);
      id.value = res.data.author;
      myReactiveVariable.titre = res.data.title;
      myReactiveVariable.content = res.data.content;
      myReactiveVariable.date = this.$moment(res.data.date).format('l');
    }

    watch(() => route.params.id, () => {
      fetchArticle(route.params.id);
    });

    onMounted(async () => {
      fetchArticle(route.params.id);
    });

    return {
      myReactiveVariable,
      id,
    };
  },
});
</script>

Solution

  • Add the moment to the global config properties app.config.globalProperties.$moment=moment:

    import { createApp } from 'vue';
    import moment from 'moment';
    import App from './App.vue';
    import './registerServiceWorker';
    import router from './router';
    import store from './store';
    
    moment.locale('fr');
    
    let app=createApp(App);
    
    app.config.globalProperties.$moment=moment;
    
    app.use(store).use(router)
      .mount('#app');
    

    then use this.$moment in any child component with option api, with composition you should use getCurrentInstance :

    import { getCurrentInstance } from 'vue'
    
    setup(){
      const internalInstance = getCurrentInstance()
      ...
      myReactiveVariable.date = internalInstance.appContext.config.globalProperties.$moment(res.data.date).format('l');
    
    }
    

    You couldn't do app.use(moment) since moment is not a Vue plugin.