vue-mapbox icon indicating copy to clipboard operation
vue-mapbox copied to clipboard

Nuxt compatibility

Open TheNoim opened this issue 5 years ago • 28 comments

This module doesn't seem to be compatible with Nuxt, because of map-promisified.

screen shot 2019-02-22 at 18 18 14

This is where the error happens: screen shot 2019-02-22 at 18 21 00 (https://raw.githubusercontent.com/soal/map-promisified/master/dist/mapPromisify.js)

If I try to patch temporarily it and refactor the dist version to a normal module without window, then the error moves to this line: screen shot 2019-02-22 at 18 23 30

Which is this line: https://github.com/soal/map-promisified/blob/master/src/promisifyMethod.ts#L27

I am not sure if this is a incorrect use of map-promisified by vue-mapbox or a bug in map-promisified.

nuxt: v2.4.3

TheNoim avatar Feb 22 '19 17:02 TheNoim

Nuxt have a special option for JS to be run only on client-side with ssr: false option: https://nuxtjs.org/guide/plugins#client-side-only

hoanglamyeah avatar Mar 01 '19 10:03 hoanglamyeah

I have same issue, can't add this module to nuxt. May somebody show example how to add as plugin with ssr: false? Or another way. I have done a few tries, but not solve this.

ProjectINT avatar Mar 26 '19 00:03 ProjectINT

Just create a mapbox.js file in the plugins folder and initialize the components:

plugins/mapbox.js

/* eslint-disable import/no-extraneous-dependencies */
import Vue from 'vue';
import { MglMap, MglGeolocateControl } from 'vue-mapbox';
import Mapbox from 'mapbox-gl';

Vue.component('MglMap', MglMap);
Vue.component('MglGeolocateControl', MglGeolocateControl);

Vue.prototype.$mapbox = Mapbox;

nuxt.config.js

plugins: [
    { src: '~/plugins/mapbox', mode: 'client' },
],

./compnents/Map.vue

<template>
  <div
    class="map"
  >
    <no-ssr>
      <MglMap
        :access-token="accessToken"
        :map-style="mapStyle"
        :center="center"
        :zoom="zoom"
        @load="onMapLoaded"
      >
        <MglGeolocateControl ref="geolocateControl" />
      </MglMap>
    </no-ssr>
  </div>
</template>

michisp avatar Mar 26 '19 09:03 michisp

Thank you very much for your solution, it works.

ProjectINT avatar Mar 26 '19 18:03 ProjectINT

@michisp unfortunately this doent work for me. I am getting the error message:

the page keeeps on loading forever (even tho I deactivate all privacy related browser plugins that could interfer. Screenshot from 2019-04-02 14-07-38

transfluxus avatar Apr 02 '19 12:04 transfluxus

@michisp unfortunately this doent work for me. I am getting the error message:

the page keeeps on loading forever (even tho I deactivate all privacy related browser plugins that could interfer. Screenshot from 2019-04-02 14-07-38

@transfluxus It seems like you do something mapbox specific on the server-side. Which nuxt version are you using? To use mode: 'client' in the nuxt.config.js you need nuxt >= 2.4. Else you have to use ssr: false which is deprecated in the next major release.

michisp avatar Apr 02 '19 12:04 michisp

I think it is 2.4.5. The mode for the plugin is client. In general (in the top of the nuxt.config.js it is universal . Thanks for the fast response. appreciate it a lot.

transfluxus avatar Apr 02 '19 12:04 transfluxus

I have 2 other plugins, they are just defined as string:

  plugins: [
    '@/plugins/vuetify',
    '~plugins/element-ui',
    { src: '~/plugins/mapbox', mode: 'client' },
],

transfluxus avatar Apr 02 '19 12:04 transfluxus

@transfluxus Okay, i can't really tell you what's the problem. It could be something in your component. Don't forget that everything before the mounted lifecycle (created() for example) will also be executed on the server-side.

michisp avatar Apr 02 '19 13:04 michisp

mmh, I created a new page just to test the map:

<template>
  <div
    class="map"
  >
    <no-ssr>
      <MglMap
        :access-token="accessToken"
        :map-style="mapStyle"
        :center="center"
        :zoom="zoom"
        @load="onMapLoaded"
      >
        <MglGeolocateControl ref="geolocateControl"/>
      </MglMap>
    </no-ssr>
  </div>
</template>

<script>
  import Mapbox from "mapbox-gl";
  import {MglMap} from "vue-mapbox";

  export default {
    name: "Map",
    components: {
      MglMap
    },
    data() {
      return {
        accessToken: "sk.eyJ1IjoicmFtaW4taWN0YSIsImEiOiJjanR6czVzYnUwazcyNDRtZ3htdmRla2x2In0.Gbsf8uPdWVWfTudW_vzhGA", // your access token. Needed if you using Mapbox maps
        mapStyle: 'mapbox://styles/mapbox/streets-v11', // your map style,
        location: null
      };
    },

    created() {
      // We need to set mapbox-gl library here in order to use it in template
      this.mapbox = Mapbox;
    }
  };
</script>

transfluxus avatar Apr 02 '19 13:04 transfluxus

haha, I can trash that token :D

transfluxus avatar Apr 02 '19 13:04 transfluxus

@transfluxus: Should be look like this:

<template>
  <div
    class="map"
  >
    <no-ssr>
      <MglMap
        :access-token="accessToken"
        :map-style="mapStyle"
        :center="center"
        :zoom="zoom"
        @load="onMapLoaded"
      >
        <MglGeolocateControl ref="geolocateControl"/>
      </MglMap>
    </no-ssr>
  </div>
</template>

<script>
  export default {
    name: "Map",
    data() {
      return {
        accessToken: "test", // your access token. Needed if you using Mapbox maps
        mapStyle: 'mapbox://styles/mapbox/streets-v11', // your map style,
        location: null
      };
    },
  };
</script>

You don't have to import mapbox and mapbox-vue because it's also done inside the nuxt.config.js. Just define your components like I did it in the ~/plugins/mapbox.js

michisp avatar Apr 02 '19 13:04 michisp

I see the world! climate change research thanks you 1000 times!

transfluxus avatar Apr 02 '19 13:04 transfluxus

Hi, after getting it to work I wanted to start displaying data on the map. But however, besides the loaded style I cannot add anything to the map.

I see the Controls in the dom, but not in the Vue component tree (in the dev-addon). e.g.

        <MglNavigationControl ref="navigationControl" position="bottom-right" />
        <MglGeolocateControl/>

        <MglPopup :coordinates="popupCoordinates">
          <span>Hello world!</span>
        </MglPopup>

no iead what ref means...

also I have to add all components in the plugin file:

import { MglMap, MglGeolocateControl, MglNavigationControl, MglPopup } from 'vue-mapbox';
import Mapbox from 'mapbox-gl';

Vue.component('MglMap', MglMap);
Vue.component('MglGeolocateControl', MglGeolocateControl);
...

If I import and add them to my map component/page the page wont load with window not defined error message.

transfluxus avatar Apr 12 '19 09:04 transfluxus

ok, so the css import was missing, which can also be included in the page:

    head() {
        return {
            link: [{
                href: "https://api.tiles.mapbox.com/mapbox-gl-js/v0.53.0/mapbox-gl.css",
                rel: "stylesheet"
            }]
        }
    },

transfluxus avatar May 04 '19 22:05 transfluxus

@transfluxus You dont have to import it like that.

Just add a style-tag with the src. If you do it like this nuxt takes the css from your node-modules

<style src="mapbox-gl/dist/mapbox-gl.css"></style>

<style lang="scss" scoped>
   .spot__map {
    margin: 0 20px;
    width: auto;
    
    .mgl-map-wrapper {
      position: absolute;
    }
  }
</style>

michisp avatar May 06 '19 08:05 michisp

This is more of a heads up comment, but I think this is related-- I have a similar setup as this comment: https://github.com/soal/vue-mapbox/issues/94#issuecomment-476551707 and that works fine, but when I add in a Navigation Control it works until I navigate away, and then it throws "TypeError: Cannot read property 'off' of undefined" in the beforeDestroy hook. Afaik it's just the Navigation Control specifically in that stage of the lifecycle. I tried it in a project that doesn't use Nuxt and it works fine, but I also tried Geolocate Control in my Nuxt project and that works fine too. Debugger shows this._map is coming back as undefined in the onRemove function:

ko.prototype.onRemove=function(){i.remove(this._container),this.options.showCompass&&(this._map.off("rotate",this._rotateCompassArrow)

laurpaik-zz avatar May 08 '19 19:05 laurpaik-zz

thanks @michisp after these test, I need to start bringing the map into my main app and my previous method didn't work but yours does...

except for the

@laurpaik aaarggh,, yes I get the "TypeError: Cannot read property 'off' of undefined"
error too when I navigate away. Somebody knows a fix?!

[edit] oh in my super minimal test app, navigation actually still works...

Also I use some vuetify icons in my layout, and they are not available anymore but are replaced by overly large text. I guess cuz I am in client mode? also not so great :/

transfluxus avatar Jun 07 '19 19:06 transfluxus

oh well,,, blindly copy pasting my test map page-component into my main app brought the icons back and ripping out the Navigation Control (thanks @laurpaik ), which is not crucial makes it work.

aside from messed up layer style color... I think a npm install just did that...

transfluxus avatar Jun 07 '19 20:06 transfluxus

FYI, from nuxt 3 onwards, no-ssr is going to be deprecated.

- <no-ssr> </no-ssr>
+ <client-only> </client-only>

vinayakkulkarni avatar Aug 22 '19 06:08 vinayakkulkarni

I've got vue-mapbox working with the plugin method but I'm having trouble accessing the map directly in a component. I have a watcher watching route changes and I need to fire this.map.resize(), but I can't figure out how to actually access this.map. Any ideas? I've tried using this.$mapbox that the plugin is apparently exporting, but I can seem to wrap my head around how to access it.

gorbypark avatar Jan 26 '20 18:01 gorbypark

I've got vue-mapbox working with the plugin method but I'm having trouble accessing the map directly in a component. I have a watcher watching route changes and I need to fire this.map.resize(), but I can't figure out how to actually access this.map. Any ideas? I've tried using this.$mapbox that the plugin is apparently exporting, but I can seem to wrap my head around how to access it.

@gorbypark Use the ref attribute to access the map.

<MglMap :access-token="accessToken" :map-style="mapStyle" ref="map" ></MglMap>

Then you can access it: this.$refs.map.resize()

michisp avatar Feb 01 '20 20:02 michisp

I've followed https://github.com/soal/vue-mapbox/issues/94#issuecomment-476551707 but I'm seeing MapBox not defined?

nuxt.config.js

plugins: [
    "~plugins/vue-scrollto.js",
    "~plugins/global.js",
    { src: '~/plugins/mapbox', mode: 'client' },
  ],

/plugins/mapbox.js

/* eslint-disable import/no-extraneous-dependencies */
import Vue from 'vue';
import { MglMap, MglGeolocateControl } from 'vue-mapbox';
import Mapbox from 'mapbox-gl';

Vue.component('MglMap', MglMap);
Vue.component('MglGeolocateControl', MglGeolocateControl);

Vue.prototype.$mapbox = Mapbox;
<template>
  <div class="map">
    <client-only>
      <MglMap
        :access-token="accessToken"
        :map-style="mapStyle"
        :center="location"
        :zoom="zoom"
        @load="onMapLoaded"
      >
        <MglGeolocateControl ref="geolocateControl" />
      </MglMap>
    </client-only>
  </div>
</template>
<script>
export default {
  data() {
    return {
      accessToken: "MYTOKEN", // your access token. Needed if you using Mapbox maps
      mapStyle: "mapbox://styles/mapbox/light-v9", // your map style
      location: [-111.549668, 39.014],
      zoom: 13,
    };
  },

  created() {
    // We need to set mapbox-gl library here in order to use it in template
    this.mapbox = Mapbox;
  }
};
</script>

Appreciate any help offered

GrantSmithDoddle avatar Feb 13 '20 17:02 GrantSmithDoddle

@granttransition this.mapbox = Mapbox is the problem and it will not work like this. Mapbox is not defined. You can already access it globally with this.$mapbox, you don't have to set it.

And take care of the created hook. Code in there will run on server-side also and this.$mapbox is not defined there. With if (process.client) {} you can run code on client-side only in beforeCreate and created hooks

michisp avatar Feb 13 '20 21:02 michisp

For anyone else reading, I completely removed the created statement along with @load="onMapLoaded as this was causing errors, and I can't see what it's purpose is?

GrantSmithDoddle avatar Feb 14 '20 10:02 GrantSmithDoddle

always self is not defined,,,,

ubay1 avatar Jun 06 '20 12:06 ubay1

Has anyone managed to get it working with Nuxt 3? I have this error:

[nuxt] [request error] HTMLElement is not defined
  at $id_2d7d4933 (./.nuxt/dist/server/server.mjs:23691:20)  
  at __instantiateModule__ (./.nuxt/dist/server/server.mjs:31884:9)  
  at __ssrLoadModule__ (./.nuxt/dist/server/server.mjs:31822:25)  
  at ssrImport (./.nuxt/dist/server/server.mjs:31847:13)  
  at $id_3e3bc7b9 (./.nuxt/dist/server/server.mjs:23435:37)  
  at async __instantiateModule__ (./.nuxt/dist/server/server.mjs:31884:3)

.vue

<template lang="pug">
section(class="bg-grey h-[200px]")
  GMapAutocomplete(placeholder="This is a placeholder" @place_changed="setPlace")
  client-only
    MglMap(:accessToken="ACCESS_TOKEN" :mapStyle="MAP_STYLE" :center="center_default" :zoom="zoom_deafult" :animate="true")
</template>

<script setup>
import { MglMap, MglMarker } from "vue-mapbox"
import 'mapbox-gl/dist/mapbox-gl.css'
import { ACCESS_TOKEN, MAP_STYLE } from '@/utils/mapbox-config'

defineNuxtComponent({
  MglMap,
  MglMarker
})

const center_default = [15.859986, 42.314909]
const zoom_deafult = 4.5

function setPlace(place) {
  const lat = place.geometry.location.lat()
  const long = place.geometry.location.lng()
}
</script>

mrc-bsllt avatar Jul 21 '22 12:07 mrc-bsllt

I am using the vue-mapbox in nuxt, but it gives me a compatibility issue with nuxt & working fine for the vue app. I found out the correct way to use vue-map in nuxt. I hope it will be helpful for someone. .nuxt.config.js

{ src: '~/plugins/vueMapBox', mode: 'client' },

Use the registration of components here

.vueMap.js

import Vue from 'vue';
import { MglMap, MglGeolocateControl, MglMarker, MglNavigationControl, MglFullscreenControl } from 'vue-mapbox';
import Mapbox from 'mapbox-gl';

Vue.component('MglMap', MglMap);
Vue.component('MglGeolocateControl', MglGeolocateControl);
Vue.component('MglMarker', MglMarker);
Vue.component('MglNavigationControl', MglNavigationControl);
Vue.component('MglFullscreenControl', MglFullscreenControl);

Vue.prototype.$mapbox = Mapbox;

.vueFile

<template>
  <div id="map" class="card map-card-h">
    <div class="card-body">
      <div v-if="showMap" class="h-100">
        <MglMap :zoom="4" :minZoom="5" :accessToken="accessToken" :mapStyle.sync="mapStyle" :center="coordinates">
          <MglMarker :coordinates="coordinates" color="blue" />
          <MglNavigationControl position="top-left" />
          <MglFullscreenControl />
        </MglMap>
      </div>
    </div>
  </div>
</template>

<script>
import 'mapbox-gl/dist/mapbox-gl.css'

export default {
  props: {
    coordinates: Array,
  },

  data() {
    return {
      showMap: true,
      mapbox: null,
      mapStyle: 'mapbox://styles/mapbox/streets-v11',
      accessToken: <token>,
    }
  },
}
</script>

abdullah-336 avatar Aug 18 '22 11:08 abdullah-336