Nuxt 3 Quickstart
Install
bash
npm install maplibre-glComponent (client-only)
MapLibre is browser-only. Use <ClientOnly> or import in onMounted.
vue
<!-- components/MapView.client.vue -->
<!-- The .client.vue suffix makes Nuxt skip SSR for this file. -->
<script setup lang="ts">
import { onMounted, onBeforeUnmount, ref } from 'vue';
import maplibregl, { type Map } from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
const config = useRuntimeConfig();
const el = ref<HTMLDivElement>();
let map: Map | null = null;
onMounted(() => {
if (!el.value) return;
map = new maplibregl.Map({
container: el.value,
style: `https://api.mapsfordevs.com/styles/standard.json?key=${config.public.mfdPubKey}`,
center: [28.04, -26.20],
zoom: 11
});
});
onBeforeUnmount(() => { map?.remove(); map = null; });
</script>
<template><div ref="el" class="w-full h-screen" /></template>nuxt.config.ts
ts
export default defineNuxtConfig({
runtimeConfig: {
mfdSrvKey: process.env.MFD_SRV_KEY, // server only
mfdSrvSecret: process.env.MFD_SRV_SECRET,
public: {
mfdPubKey: process.env.NUXT_PUBLIC_MFD_PUB_KEY // browser-safe
}
}
});Server route — tile proxy
ts
// server/api/tiles/[z]/[x]/[y].pbf.get.ts
import { createHmac } from 'node:crypto';
export default defineEventHandler(async (event) => {
const { z, x, y } = getRouterParams(event);
const config = useRuntimeConfig();
const path = `/tiles/${z}/${x}/${y}.pbf`;
const ts = String(Math.floor(Date.now() / 1000));
const sig = createHmac('sha256', config.mfdSrvSecret)
.update(`GET\n${path}\n${ts}`).digest('hex');
const upstream = await $fetch.raw<ArrayBuffer>(`https://tiles.mapsfordevs.com${path}`, {
headers: {
Authorization: `Bearer ${config.mfdSrvKey}`,
'X-MFD-Timestamp': ts,
'X-MFD-Signature': sig
},
responseType: 'arrayBuffer'
});
setHeader(event, 'Content-Type', 'application/x-protobuf');
setHeader(event, 'Cache-Control', 'public, max-age=86400');
return Buffer.from(upstream._data!);
});Geocoding composable
ts
// composables/useGeocode.ts
export function useGeocode() {
const config = useRuntimeConfig();
const results = ref<any[]>([]);
const loading = ref(false);
async function search(q: string) {
loading.value = true;
try {
const body = await $fetch<{ ok: boolean; items: any[]; error?: string }>(
'https://api.mapsfordevs.com/geocode/forward',
{
headers: { Authorization: `Bearer ${config.public.mfdPubKey}` },
query: { q, limit: 5 }
}
);
if (body.ok) results.value = body.items;
} finally {
loading.value = false;
}
}
return { results, loading, search };
}