Skip to content

Commit

Permalink
docs: add guide and examples for frameworks and ssr (#599)
Browse files Browse the repository at this point in the history
This adds documentation about SSR and frameworks like Next.js and Remix as well as example for both frameworks to demonstrate the technical setup
  • Loading branch information
mrMetalWood authored Nov 20, 2024
1 parent a2ca4fb commit a5c75f1
Show file tree
Hide file tree
Showing 44 changed files with 997 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ node_modules
dist
.npmignore
CHANGELOG.md
examples/nextjs/.next
examples/nextjs/next.lock
73 changes: 73 additions & 0 deletions docs/guides/ssr-and-frameworks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Frameworks and SSR

The main thing to consider when using the library with Server-side Rendering (SSR) or a fullstack framework like Next.js or Remix is to make sure that
the map is excluded from Server-side Rendering since that is not supported by the Google Maps API. We are currently evaluating a solution that would provide basic SSR capabilities via the Static Maps API.

## Next.js

This is how a component in a Next.js (app router) application looks like. Checkout the example [code](https://github.com/visgl/react-google-maps/tree/main/examples/nextjs) on Github or play around with the [demo](https://codesandbox.io/s/github/visgl/react-google-maps/tree/main/examples/nextjs) on Codesandbox.

:::note

The `use client;` statement at the top tells Next.js that
this component should only be rendered on the client.

:::

```tsx
'use client';

import {APIProvider, Map} from '@vis.gl/react-google-maps';

export default function MyMap() {
return (
<div className={styles.container}>
<APIProvider apiKey={'...'}>
<Map
mapId={'bf51a910020fa25a'}
defaultZoom={5}
defaultCenter={{lat: 53, lng: 10}}
gestureHandling={'greedy'}
disableDefaultUI={true}
/>
</APIProvider>
</div>
);
}
```

## Remix

Here is the best approach we found to use a map component in a Remix application. Checkout the example [code](https://github.com/visgl/react-google-maps/tree/main/examples/remix) on Github or play around with the [demo](https://codesandbox.io/s/github/visgl/react-google-maps/tree/main/examples/remix) on Codesandbox.

Wrap the map in a `<ClientOnly>` component from the [`remix-utils`](https://github.com/sergiodxa/remix-utils) package for it to be rendered only on the client.

:::note

If you use a fallback and you know the dimensions of your final map, make sure that
the fallback has the same size to prevent layout shifts when the map component loads.

:::

```tsx
import {APIProvider, Map} from '@vis.gl/react-google-maps';
import {ClientOnly} from 'remix-utils/client-only';

export default function MyMap() {
return (
<ClientOnly fallback={<MapFallback />}>
{() => (
<APIProvider apiKey={'...'}>
<Map
mapId={'bf51a910020fa25a'}
defaultZoom={5}
defaultCenter={{lat: 53, lng: 10}}
gestureHandling={'greedy'}
disableDefaultUI={true}
/>
</APIProvider>
)}
</ClientOnly>
);
}
```
1 change: 1 addition & 0 deletions docs/table-of-contents.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"items": [
"guides/interacting-with-google-maps-api",
"guides/deckgl-integration",
"guides/ssr-and-frameworks",
"guides/writing-examples"
]
},
Expand Down
3 changes: 3 additions & 0 deletions examples/nextjs/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": ["next/core-web-vitals", "next/typescript"]
}
2 changes: 2 additions & 0 deletions examples/nextjs/.example.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Duplicate this file and rename it to ".env" and enter your Google Maps API key here
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=<YOUR_GOOGLE_MAPS_API_KEY>
51 changes: 51 additions & 0 deletions examples/nextjs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# env files (can opt-in for committing if needed)
.env*

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts

# Ignoring tsconfig.json here since NextJS does not provide a way yet to specify a custom tsconfig.json path
# and rather hard codes the tsconfig.json path. We do want to use different tsconfig files
# for this example to be able to use the local files in dev mode and the installed package
# when called in Codesandbox.
tsconfig.json

# Ignoring the lock folder here since this is not intended
# for a production build This should not be done on a real project.
# https://nextjs.org/docs/app/api-reference/next-config-js/urlImports#lockfile
next.lock
41 changes: 41 additions & 0 deletions examples/nextjs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Next.js Example

This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). It shows a basic map setup with two routes.

## Demo

Checkout the [demo](https://codesandbox.io/s/github/visgl/react-google-maps/tree/main/examples/nextjs) on Codesandbox.

## Google Maps Platform API Key

This example does not come with an API key. Running the examples locally requires a valid API key for the Google Maps Platform.
See [the official documentation][get-api-key] on how to create and configure your own key.

The API key has to be provided via an environment variable `NEXT_PUBLIC_GOOGLE_MAPS_API_KEY`. This can be done by creating a
file named `.env` in the example directory with the following content:

```shell title=".env"
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY="<YOUR API KEY HERE>"
```

If you are on the CodeSandbox playground you can also choose to [provide the API key like this](https://codesandbox.io/docs/learn/environment/secrets)

## Development

First, run the development server:

For the local server that uses the local library files:

```bash
npm run start-local
```

For the regular dev server that uses the installe files for `@vis.gl/react-google-maps`:

```bash
npm run start
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

[get-api-key]: https://developers.google.com/maps/documentation/javascript/get-api-key
7 changes: 7 additions & 0 deletions examples/nextjs/next.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type {NextConfig} from 'next';

const nextConfig: NextConfig = {
/* config options here */
};

export default nextConfig;
23 changes: 23 additions & 0 deletions examples/nextjs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"scripts": {
"start": "cp tsconfig.sandbox.json tsconfig.json && next dev",
"start-local": "cp tsconfig.local.json tsconfig.json && next dev",
"build": "cp tsconfig.sandbox.json tsconfig.json && next build",
"serve": "next start",
"lint": "next lint"
},
"dependencies": {
"@vis.gl/react-google-maps": "latest",
"react": "19.0.0-rc-66855b96-20241106",
"react-dom": "19.0.0-rc-66855b96-20241106",
"next": "15.0.3"
},
"devDependencies": {
"typescript": "^5",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^8",
"eslint-config-next": "15.0.3"
}
}
8 changes: 8 additions & 0 deletions examples/nextjs/src/app/about/page.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.page {
width: 100%;
height: 100%;
background: aliceblue;
display: flex;
align-items: center;
justify-content: center;
}
5 changes: 5 additions & 0 deletions examples/nextjs/src/app/about/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import styles from './page.module.css';

export default function About() {
return <div className={styles.page}>About</div>;
}
18 changes: 18 additions & 0 deletions examples/nextjs/src/app/components/header.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.container {
width: 100%;
height: 100%;
}

.header {
display: flex;
align-items: center;
justify-content: center;
}

.nav ul {
display: flex;
align-items: center;
justify-content: center;
gap: 16px;
list-style: none;
}
20 changes: 20 additions & 0 deletions examples/nextjs/src/app/components/header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import Link from 'next/link';

import styles from './header.module.css';

export default function Header() {
return (
<header className={styles.header}>
<nav className={styles.nav}>
<ul>
<li>
<Link href="/">Home</Link>
</li>
<li>
<Link href="/about">About</Link>
</li>
</ul>
</nav>
</header>
);
}
11 changes: 11 additions & 0 deletions examples/nextjs/src/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
html,
body {
max-width: 100vw;
overflow-x: hidden;
}

* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
7 changes: 7 additions & 0 deletions examples/nextjs/src/app/layout.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.container {
width: 100vw;
height: 100vh;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 60px 1fr;
}
33 changes: 33 additions & 0 deletions examples/nextjs/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import type {Metadata} from 'next';
import Script from 'next/script';

import Header from './components/header';

import styles from './layout.module.css';
import './globals.css';

export const metadata: Metadata = {
title: 'React Google Maps - NextJS Example'
};

export default function RootLayout({
children
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body>
<div className={styles.container}>
<Header />
{children}
</div>

<Script
src="https://visgl.github.io/react-google-maps/scripts/examples.js"
strategy="beforeInteractive"
/>
</body>
</html>
);
}
4 changes: 4 additions & 0 deletions examples/nextjs/src/app/page.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.container {
width: 100%;
height: 100%;
}
25 changes: 25 additions & 0 deletions examples/nextjs/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use client';

import {APIProvider, Map} from '@vis.gl/react-google-maps';

import styles from './page.module.css';

export default function Home() {
const API_KEY =
(process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY as string) ??
globalThis.GOOGLE_MAPS_API_KEY;

return (
<div className={styles.container}>
<APIProvider apiKey={API_KEY}>
<Map
mapId={'bf51a910020fa25a'}
defaultZoom={5}
defaultCenter={{lat: 53, lng: 10}}
gestureHandling={'greedy'}
disableDefaultUI={true}
/>
</APIProvider>
</div>
);
}
4 changes: 4 additions & 0 deletions examples/nextjs/src/global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// global.d.ts
declare module globalThis {
var GOOGLE_MAPS_API_KEY: string;
}
Loading

0 comments on commit a5c75f1

Please sign in to comment.