Created
February 20, 2025 21:08
-
-
Save superjose/9eaa87be5fe320f25325e22ee8e455de to your computer and use it in GitHub Desktop.
Remix V2 + Express + Vite + PostHog Proxy Rewrite
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { createRequestHandler } from '@remix-run/express'; | |
import express, { Request } from 'express'; | |
import { createCookieSessionStorage, type ServerBuild } from '@remix-run/node'; | |
import { dispatchWithContext } from './app/.server/shared/config.js'; | |
import { Dispatch } from './app/.server/services/mediator.types'; | |
import shrinkRay from 'shrink-ray-current'; | |
import 'dotenv/config'; | |
import { getGrowthbookClient } from '@alertdown/core'; | |
import { createProxyMiddleware } from 'http-proxy-middleware'; | |
const API_HOST = 'us.i.posthog.com'; | |
const ASSET_HOST = 'us-assets.i.posthog.com'; | |
const viteDevServer = | |
process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'staging' | |
? undefined | |
: await import('vite').then((vite) => { | |
return vite.createServer({ | |
server: { middlewareMode: true }, | |
appType: 'custom', | |
}); | |
}); | |
const remixHandler = createRequestHandler({ | |
build: viteDevServer | |
? () => | |
viteDevServer.ssrLoadModule( | |
'virtual:remix/server-build' | |
) as Promise<ServerBuild> | |
: await import('./build/server/index.js'), | |
async getLoadContext(req) { | |
const env = process.env as Record<string, string>; | |
const sessionFlashSecret = env.SESSION_FLASH_SECRET; | |
const flashStorage = createCookieSessionStorage({ | |
cookie: { | |
name: '__flash', | |
httpOnly: true, | |
maxAge: 60, | |
path: '/', | |
sameSite: 'lax', | |
secrets: [sessionFlashSecret], | |
secure: true, | |
}, | |
}); | |
return { | |
cloudflare: { | |
env, | |
}, | |
dispatch: (await dispatchWithContext({ | |
env, | |
request: req, | |
})) as Dispatch, | |
flashStorage, | |
growthbook: await getGrowthbookClient(env.GROWTHBOOK_API_KEY), | |
}; | |
}, | |
}); | |
const app = express(); | |
app.use(shrinkRay()); | |
// http://expressjs.com/en/advanced/best-practice-security.html#at-a-minimum-disable-x-powered-by-header | |
app.disable('x-powered-by'); | |
// PostHog proxy configuration | |
app.use( | |
'/ingest/static', | |
createProxyMiddleware({ | |
target: `https://${ASSET_HOST}`, | |
pathRewrite: (path) => { | |
// Remove /ingest/static and ensure /static is present | |
const newPath = path.replace(/^\/ingest\/static/, ''); | |
return `/static${newPath}`; | |
}, | |
changeOrigin: true, | |
on: { | |
proxyReq: (proxyReq, req, res) => { | |
console.log('Final target URL:', proxyReq.path); | |
}, | |
error: (err, req, res) => { | |
console.error('Proxy error:', err); | |
}, | |
}, | |
secure: true, | |
}) | |
); | |
app.use( | |
'/ingest', | |
createProxyMiddleware({ | |
target: `https://${API_HOST}`, | |
pathRewrite: { | |
'^/ingest': '', | |
}, | |
changeOrigin: true, | |
secure: true, | |
on: { | |
error: (err, req, res) => { | |
console.error('Proxy error:', err); | |
}, | |
}, | |
}) | |
); | |
// handle asset requests | |
if (viteDevServer) { | |
app.use(viteDevServer.middlewares); | |
} else { | |
// Vite fingerprints its assets so we can cache forever. | |
app.use( | |
'/assets', | |
express.static('build/client/assets', { immutable: true, maxAge: '1y' }) | |
); | |
} | |
// Everything else (like favicon.ico) is cached for an hour. You may want to be | |
// more aggressive with this caching. | |
app.use(express.static('build/client', { maxAge: '1h' })); | |
// app.use(morgan('tiny')); | |
// handle SSR requests | |
app.all('*', remixHandler); | |
const port = process.env.PORT || 3000; | |
app.listen(port, () => | |
console.log(`Express server listening at http://localhost:${port}`) | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment