1

My next js app is working well in development and build but when I try to deploy it in Vercel I'm getting this error when I try to call the page calling my mapView component :

Application error: a client-side exception has occurred (see the browser console for more information).

This is the complete log in the vercel app : log

And this is the of my map component :

import { GoogleMap, Marker, MarkerClusterer, useJsApiLoader } from '@react-google-maps/api'
import { useCallback, useState } from 'react'
import SpotCard from './spots/SpotCard'

export const MapView = ({ data }) => {
  const [postCardData, setPostCardData] = useState(null)
  const defaultProps = {
    center: {
      lat: -21.115141,
      lng: 55.536384,
    },
    containerStyle: {
      maxWidth: '800px',
      height: '600px',
      margin: '0 auto',
      borderRadius: '10px',
      opacity: 1,
    },
    zoom: 10,
  }

  const getImage = (category) => {
    let source
    if (category == 'Bivouac') source = `/static/icons/Bivouac.png`
    if (category == 'Camping') source = `/static/icons/Camping.png`
    if (category == 'Gîtes') source = `/static/icons/Gîtes.png`
    if (category == 'Insolite') source = `/static/icons/Insolite.png`

    return source
  }

  const { isLoaded } = useJsApiLoader({
    id: 'google-map-script',
    googleMapsApiKey: 'XXXXXXXXX',
  })

  const [map, setMap] = useState(null)

  const onLoad = useCallback(function callback(map) {
    const bounds = new window.google.maps.LatLngBounds(defaultProps.center)
    map.fitBounds(bounds)
    setMap(map)
  }, [])

  const onUnmount = useCallback(function callback(map) {
    setMap(null)
  }, [])
  return (
    isLoaded ? (
      <div>
        <div className=" my-16">
          <GoogleMap
            mapContainerStyle={defaultProps.containerStyle}
            center={defaultProps.center}
            zoom={10}
            onLoad={onLoad}
            onUnmount={onUnmount}
          >
            <MarkerClusterer minimumClusterSize={4}>
              {(clusterer) =>
                data.length > 1 ? (
                  data?.map((marker, i) => (
                    <Marker
                      key={i}
                      position={{
                        lat: Number(marker.attributes.lat),
                        lng: Number(marker.attributes.lon),
                      }}
                      icon={getImage(marker.attributes.category.data.attributes.name)}
                      onClick={() => setPostCardData(marker)}
                      clusterer={clusterer}
                    />
                  ))
                ) : (
                  <Marker
                    position={{
                      lat: Number(data.attributes.lat),
                      lng: Number(data.attributes.lon),
                    }}
                    icon={getImage(data.attributes.category.data.attributes.name)}
                    onClick={() => setPostCardData(data)}
                  />
                )
              }
            </MarkerClusterer>
            {postCardData !== null && (
              <div className=" z-10 flex h-full items-center justify-center">
                <div className=" max-w-xs">
                  <div className="flex justify-end">
                    <button
                      className="absolute top-16 z-20 inline-flex items-center justify-center rounded-full bg-white p-2 text-green-600 opacity-95 hover:bg-gray-100 hover:text-green-800 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-green-500"
                      onClick={() => setPostCardData(null)}
                    >
                      <span className="sr-only">Close menu</span>

                      <svg
                        className="h-6 w-6"
                        xmlns="http://www.w3.org/2000/svg"
                        fill="none"
                        viewBox="0 0 24 24"
                        stroke="currentColor"
                        aria-hidden="true"
                      >
                        <path
                          strokeLinecap="round"
                          strokeLinejoin="round"
                          strokeWidth="2"
                          d="M6 18L18 6M6 6l12 12"
                        />
                      </svg>
                    </button>
                  </div>
                  <SpotCard post={postCardData} />
                </div>
              </div>
            )}
          </GoogleMap>
        </div>
      </div>
    ) : (
      <></>
    )
  )
}

I tried to find a solution, but did not find yet since yesterday, so I'm wondering if someone had already the same issue and could help me ..

Thanks

EDIT : It coul be also a problem with ContentSecurityPolicy I let here my configuration :

const ContentSecurityPolicy = `
  default-src 'self';
  script-src 'self' 'unsafe-eval' 'unsafe-inline' giscus.app maps.googleapis.com;
  style-src 'self' 'unsafe-inline' fonts.googleapis.com;
  img-src * blob: data: maps.gstatic.com googleapis.com ggpht.com;
  media-src 'none';
  connect-src * googleapis.com google.com gstatic.com data: blob:;
  font-src 'self' fonts.gstatic.com;
  frame-src giscus.app google.com

or come from eslint config :

module.exports = {
  root: true,
  env: {
    browser: true,
    amd: true,
    node: true,
    es6: true,
    window: true,
  },
  globals: {
    window: true,
    document: true,
    google: true,
  },
  extends: [
    'eslint:recommended',
    'plugin:prettier/recommended',
    'next',
    'next/core-web-vitals',
    'google',
  ],
  rules: {
    'prettier/prettier': ['error', { endOfLine: 'auto' }],
    'react/react-in-jsx-scope': 'off',
    'react/prop-types': 0,
    'no-unused-vars': 0,
    'react/no-unescaped-entities': 0,
  },
}

1 Answers1

0

I found an article that helped me solved the production error in console. Here is the article: https://medium.com/web-dev-survey-from-kyoto/3-gotchas-of-google-maps-api-when-used-with-next-js-and-eslint-dba627c9657d

I loaded the map in useEffect, I think this was the main issue. Hope it helps!