Next.js Supabase V3 (#463)
Version 3 of the kit: - Radix UI replaced with Base UI (using the Shadcn UI patterns) - next-intl replaces react-i18next - enhanceAction deprecated; usage moved to next-safe-action - main layout now wrapped with [locale] path segment - Teams only mode - Layout updates - Zod v4 - Next.js 16.2 - Typescript 6 - All other dependencies updated - Removed deprecated Edge CSRF - Dynamic Github Action runner
This commit is contained in:
committed by
GitHub
parent
4912e402a3
commit
7ebff31475
210
docs/development/external-marketing-website.mdoc
Normal file
210
docs/development/external-marketing-website.mdoc
Normal file
@@ -0,0 +1,210 @@
|
||||
---
|
||||
status: "published"
|
||||
label: "External Marketing Website"
|
||||
title: "External Marketing Website in the Next.js Supabase Turbo Starter Kit"
|
||||
description: "Configure Makerkit to redirect marketing pages to an external website built with Framer, Webflow, or WordPress."
|
||||
order: 9
|
||||
---
|
||||
|
||||
Redirect Makerkit's marketing pages to an external website by configuring the `proxy.ts` middleware. This lets you use Framer, Webflow, or WordPress for your marketing site while keeping Makerkit for your SaaS application.
|
||||
|
||||
{% sequence title="External Marketing Website Setup" description="Configure redirects to your external marketing site" %}
|
||||
|
||||
[Understand the architecture](#when-to-use-an-external-marketing-website)
|
||||
|
||||
[Configure the middleware](#configuring-the-middleware)
|
||||
|
||||
[Handle subpaths and assets](#handling-subpaths-and-assets)
|
||||
|
||||
[Verify the redirects](#verify-the-redirects)
|
||||
|
||||
{% /sequence %}
|
||||
|
||||
## When to Use an External Marketing Website
|
||||
|
||||
Use an external marketing website when:
|
||||
|
||||
- **Marketing team independence**: Your marketing team needs to update content without developer involvement
|
||||
- **Design flexibility**: You want visual builders like Framer or Webflow for landing pages
|
||||
- **Content management**: WordPress or a headless CMS better fits your content workflow
|
||||
- **A/B testing**: Your marketing tools integrate better with external platforms
|
||||
|
||||
Keep marketing pages in Makerkit when:
|
||||
|
||||
- You want a unified codebase and deployment
|
||||
- Your team is comfortable with React and Tailwind
|
||||
- You need tight integration between marketing and app features
|
||||
|
||||
## Configuring the Middleware
|
||||
|
||||
{% alert type="default" title="Next.js 16+" %}
|
||||
In Next.js 16+, Makerkit uses `proxy.ts` for middleware. Prior versions used `middleware.ts`.
|
||||
{% /alert %}
|
||||
|
||||
Edit `apps/web/proxy.ts` to redirect marketing pages:
|
||||
|
||||
```typescript {% title="apps/web/proxy.ts" %}
|
||||
import type { NextRequest } from 'next/server';
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
const EXTERNAL_MARKETING_URL = 'https://your-marketing-site.com';
|
||||
|
||||
const MARKETING_PAGES = [
|
||||
'/',
|
||||
'/pricing',
|
||||
'/faq',
|
||||
'/contact',
|
||||
'/about',
|
||||
'/blog',
|
||||
'/privacy-policy',
|
||||
'/terms-of-service',
|
||||
'/cookie-policy',
|
||||
];
|
||||
|
||||
export function proxy(req: NextRequest) {
|
||||
if (isMarketingPage(req)) {
|
||||
const redirectUrl = new URL(
|
||||
req.nextUrl.pathname,
|
||||
EXTERNAL_MARKETING_URL
|
||||
);
|
||||
|
||||
// Preserve query parameters
|
||||
redirectUrl.search = req.nextUrl.search;
|
||||
|
||||
return NextResponse.redirect(redirectUrl, { status: 301 });
|
||||
}
|
||||
|
||||
// Continue with existing middleware logic
|
||||
return NextResponse.next();
|
||||
}
|
||||
|
||||
function isMarketingPage(req: NextRequest): boolean {
|
||||
const pathname = req.nextUrl.pathname;
|
||||
|
||||
return MARKETING_PAGES.some((page) => {
|
||||
if (page === '/') {
|
||||
return pathname === '/';
|
||||
}
|
||||
return pathname === page || pathname.startsWith(`${page}/`);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration Options
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| `EXTERNAL_MARKETING_URL` | Your external marketing site's base URL |
|
||||
| `MARKETING_PAGES` | Array of paths to redirect |
|
||||
| Status code `301` | Permanent redirect (SEO-friendly) |
|
||||
| Status code `302` | Temporary redirect (for testing) |
|
||||
|
||||
## Handling Subpaths and Assets
|
||||
|
||||
### Blog Posts with Dynamic Paths
|
||||
|
||||
If your blog uses dynamic paths like `/blog/post-slug`, handle them separately:
|
||||
|
||||
```typescript
|
||||
const MARKETING_PAGES = [
|
||||
// ... other pages
|
||||
];
|
||||
|
||||
const MARKETING_PREFIXES = [
|
||||
'/blog',
|
||||
'/resources',
|
||||
'/case-studies',
|
||||
];
|
||||
|
||||
function isMarketingPage(req: NextRequest): boolean {
|
||||
const pathname = req.nextUrl.pathname;
|
||||
|
||||
// Check exact matches
|
||||
if (MARKETING_PAGES.includes(pathname)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check prefix matches
|
||||
return MARKETING_PREFIXES.some((prefix) =>
|
||||
pathname.startsWith(prefix)
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Excluding Application Routes
|
||||
|
||||
Keep certain routes in Makerkit even if they share a marketing prefix:
|
||||
|
||||
```typescript
|
||||
const APP_ROUTES = [
|
||||
'/blog/admin', // Blog admin panel stays in Makerkit
|
||||
'/pricing/checkout', // Checkout flow stays in Makerkit
|
||||
];
|
||||
|
||||
function isMarketingPage(req: NextRequest): boolean {
|
||||
const pathname = req.nextUrl.pathname;
|
||||
|
||||
// Never redirect app routes
|
||||
if (APP_ROUTES.some((route) => pathname.startsWith(route))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ... rest of the logic
|
||||
}
|
||||
```
|
||||
|
||||
## Verify the Redirects
|
||||
|
||||
After configuring, verify redirects work correctly:
|
||||
|
||||
```bash
|
||||
# Start the development server
|
||||
pnpm run dev
|
||||
|
||||
# Test a redirect (should return 301)
|
||||
curl -I http://localhost:3000/pricing
|
||||
```
|
||||
|
||||
Expected output:
|
||||
|
||||
```
|
||||
HTTP/1.1 301 Moved Permanently
|
||||
Location: https://your-marketing-site.com/pricing
|
||||
```
|
||||
|
||||
### Common Issues
|
||||
|
||||
**Redirect loops**: Ensure your external site doesn't redirect back to Makerkit.
|
||||
|
||||
**Missing query parameters**: The example code preserves query params. Verify UTM parameters pass through correctly.
|
||||
|
||||
**Asset requests**: Don't redirect asset paths like `/images/` or `/_next/`. The middleware should only match page routes.
|
||||
|
||||
## Environment-Based Configuration
|
||||
|
||||
Use environment variables for different environments:
|
||||
|
||||
```typescript {% title="apps/web/proxy.ts" %}
|
||||
const EXTERNAL_MARKETING_URL = process.env.EXTERNAL_MARKETING_URL;
|
||||
|
||||
export function proxy(req: NextRequest) {
|
||||
// Only redirect if external URL is configured
|
||||
if (!EXTERNAL_MARKETING_URL) {
|
||||
return NextResponse.next();
|
||||
}
|
||||
|
||||
// ... redirect logic
|
||||
}
|
||||
```
|
||||
|
||||
```bash {% title=".env.production" %}
|
||||
EXTERNAL_MARKETING_URL=https://your-marketing-site.com
|
||||
```
|
||||
|
||||
This lets you keep marketing pages in Makerkit during development while redirecting in production.
|
||||
|
||||
## Related Resources
|
||||
|
||||
- [Marketing Pages](/docs/next-supabase-turbo/development/marketing-pages) for customizing built-in marketing pages
|
||||
- [SEO Configuration](/docs/next-supabase-turbo/development/seo) for sitemap and meta tag setup
|
||||
- [Legal Pages](/docs/next-supabase-turbo/development/legal-pages) for privacy policy and terms pages
|
||||
Reference in New Issue
Block a user