DEV Community

Alessandro T.
Alessandro T.

Posted on • Edited on • Originally published at trinca.tornidor.com

1

Vitepress and leaflet.markercluster

Vitepress and leaflet.markercluster

VitePress pre-renders the app in Node.js during the production build, using Vue's Server-Side Rendering (SSR) capabilities: this fact prevents using 'leaflet.markercluster' (or its wrapper module 'vue-leaflet-markercluster') within a vitepress project. Let's say we create this simple Leaflet map within a vue component imported within a vitepress project:

<template>
  <div id="map">
    <l-map
      :zoom="9"
      :center="[45.1, 9.1]"
      :use-global-leaflet="true"
    >
      <l-tile-layer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" :attribution="attribution"/>
      <l-marker-cluster-group>
        <l-marker :lat-lng="[45.1, 9.1]"/>
        <l-marker :lat-lng="[45.2, 9.2]"/>
        <l-marker :lat-lng="[45.3, 9.3]"/>
      </l-marker-cluster-group>
    </l-map>
  </div>
</template>

<script setup lang="ts">
import {LMarker, LMap, LTileLayer} from "@vue-leaflet/vue-leaflet";
import L, {marker} from 'leaflet'

globalThis.L = L
import {LMarkerClusterGroup} from 'vue-leaflet-markercluster'
import {ref} from 'vue'

import 'leaflet/dist/leaflet.css'
import 'vue-leaflet-markercluster/dist/style.css'

const attribution = ref("openstreetmap contributors")
const prefix = ref("leaflet")
</script>

<style scoped>
#map {
  height: 50vh;
  width: 100%;
}
</style>
Enter fullscreen mode Exit fullscreen mode

While running this code with yarn docs:dev or pnpm docs:dev (aliases of vitepress dev docs, see the vitepress documentation) it's fine, of course the leaflet.markercluster SSR requirements break the build step. Luckily it's possible to build the project using the import() syntax, commonly called dynamic import. There are different possible implementations (e.g. async components) but in this case I prefer using the classic JS syntax within the onBeforeMount() hook, then we can fix the broken component this way:

<template>
  <div id="map-photos"/>
</template>

<script setup lang="ts">
import "leaflet/dist/leaflet.css";
import "leaflet.markercluster/dist/MarkerCluster.css"
import "leaflet.markercluster/dist/MarkerCluster.Default.css"
import {onBeforeMount} from "vue";

onBeforeMount(async () => {
  const L = await import("leaflet")
  const {MarkerClusterGroup} = await import('leaflet.markercluster/dist/leaflet.markercluster')

  const map = L.map("map-photos") // div id
  map.setView([45.1, 9.1], 8)
  L.tileLayer("http://{s}.tile.osm.org/{z}/{x}/{y}.png").addTo(map);
  let mcluster = new MarkerClusterGroup()
  let marker1 = new L.Marker([45.1, 9.1])
  let marker2 = new L.Marker([45.2, 9.2])
  let marker3 = new L.Marker([45.3, 9.3])
  marker1.addTo(mcluster)
  marker2.addTo(mcluster)
  marker3.addTo(mcluster)
  mcluster.addTo(map)
})
</script>

<style scoped>
#map-photos {
  width: 100%;
  height: 60vh;
}
</style>
Enter fullscreen mode Exit fullscreen mode

Note that onBeforeMount() must be async to make it work.
Last but not least the package.json of this vitepress project contains these dependencies:

{
  "name": "vitepress-ssr-build",
  "version": "1.0.0",
  "scripts": {
    "docs:dev": "vitepress dev docs",
    "docs:build": "pnpm i --frozen-lockfile && vitepress build docs",
    "docs:serve": "vitepress serve docs",
    "docs:preview": "vitepress preview docs --port 3000"
  },
  "license": "MIT",
  "type": "module",
  "dependencies": {
    "@vue-leaflet/vue-leaflet": "^0.10.1",
    "leaflet": "^1.9.4",
    "leaflet.markercluster": "^1.5.3",
    "vitepress": "^1.0.0-rc.10",
    "vue": "^3.3.4"
  },
  "devDependencies": {
    "@tsconfig/recommended": "^1.0.2",
    "@types/geojson": "^7946.0.10",
    "@types/leaflet": "^1.9.4",
    "@types/leaflet.markercluster": "^1.5.2"
  }
}
Enter fullscreen mode Exit fullscreen mode

SurveyJS custom survey software

JavaScript UI Libraries for Surveys and Forms

SurveyJS lets you build a JSON-based form management system that integrates with any backend, giving you full control over your data and no user limits. Includes support for custom question types, skip logic, integrated CCS editor, PDF export, real-time analytics & more.

Learn more

Top comments (0)

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more