Change Docker handling of custom rewrites

This commit is contained in:
Maxime-J 2025-04-19 19:44:27 +02:00
parent 3b5e1da39e
commit b88432fcf4
4 changed files with 78 additions and 62 deletions

View file

@ -13,7 +13,6 @@ FROM node:22-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
COPY docker/middleware.js ./src
ARG DATABASE_TYPE
ARG BASE_PATH
@ -51,6 +50,8 @@ COPY --from=builder /app/scripts ./scripts
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
RUN mv ./.next/routes-manifest.json ./.next/routes-manifest-orig.json
USER nextjs
EXPOSE 3000

View file

@ -1,60 +0,0 @@
import { NextResponse } from 'next/server';
export const config = {
matcher: '/:path*',
};
const apiHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': '*',
'Access-Control-Allow-Methods': 'GET, DELETE, POST, PUT',
'Access-Control-Max-Age': process.env.CORS_MAX_AGE || '86400',
'Cache-Control': 'no-cache',
};
const trackerHeaders = {
'Access-Control-Allow-Origin': '*',
'Cache-Control': 'public, max-age=86400, must-revalidate',
};
function customCollectEndpoint(req) {
const collectEndpoint = process.env.COLLECT_API_ENDPOINT;
if (collectEndpoint) {
const url = req.nextUrl.clone();
const { pathname } = url;
if (pathname.endsWith(collectEndpoint)) {
url.pathname = '/api/send';
return NextResponse.rewrite(url, { headers: apiHeaders });
}
}
}
function customScriptName(req) {
const scriptName = process.env.TRACKER_SCRIPT_NAME;
if (scriptName) {
const url = req.nextUrl.clone();
const { pathname } = url;
const names = scriptName.split(',').map(name => name.trim().replace(/^\/+/, ''));
if (names.find(name => pathname.endsWith(name))) {
url.pathname = '/script.js';
return NextResponse.rewrite(url, { headers: trackerHeaders });
}
}
}
export default function middleware(req) {
const fns = [customCollectEndpoint, customScriptName];
for (const fn of fns) {
const res = fn(req);
if (res) {
return res;
}
}
return NextResponse.next();
}

View file

@ -14,7 +14,7 @@
"build": "npm-run-all check-env build-db check-db build-tracker build-geo build-app",
"start": "next start",
"build-docker": "npm-run-all build-db build-tracker build-geo build-app",
"start-docker": "npm-run-all check-db update-tracker start-server",
"start-docker": "npm-run-all check-db update-tracker set-routes-manifest start-server",
"start-env": "node scripts/start-env.js",
"start-server": "node server.js",
"build-app": "next build",
@ -25,6 +25,7 @@
"build-geo": "node scripts/build-geo.js",
"build-db-schema": "prisma db pull",
"build-db-client": "prisma generate",
"set-routes-manifest": "node scripts/set-routes-manifest.js",
"update-tracker": "node scripts/update-tracker.js",
"update-db": "prisma migrate deploy",
"check-db": "node scripts/check-db.js",

View file

@ -0,0 +1,74 @@
/* eslint-disable no-console */
require('dotenv').config();
const fs = require('fs');
const path = require('path');
const routesManifestPath = path.resolve(__dirname, '../.next/routes-manifest.json');
const originalPath = path.resolve(__dirname, '../.next/routes-manifest-orig.json');
const originalManifest = require(originalPath);
const API_PATH = '/api/:path*';
const TRACKER_SCRIPT = '/script.js';
const collectApiEndpoint = process.env.COLLECT_API_ENDPOINT;
const trackerScriptName = process.env.TRACKER_SCRIPT_NAME;
const headers = [];
const rewrites = [];
if (collectApiEndpoint) {
const apiRoute = originalManifest.headers.find((route) => route.source === API_PATH);
const routeRegex = new RegExp(apiRoute.regex);
rewrites.push({
source: collectApiEndpoint,
destination: '/api/send',
});
if (!routeRegex.test(collectApiEndpoint)) {
headers.push({
source: collectApiEndpoint,
headers: apiRoute.headers,
});
}
}
if (trackerScriptName) {
const trackerRoute = originalManifest.headers.find((route) => route.source === TRACKER_SCRIPT);
const names = trackerScriptName?.split(',').map(name => name.trim());
if (names) {
names.forEach(name => {
const normalizedSource = `/${name.replace(/^\/+/, '')}`;
rewrites.push({
source: normalizedSource,
destination: TRACKER_SCRIPT,
});
headers.push({
source: normalizedSource,
headers: trackerRoute.headers,
});
});
}
}
const routesManifest = { ...originalManifest };
if (rewrites.length != 0) {
const { buildCustomRoute } = require('next/dist/lib/build-custom-route');
const builtHeaders = headers.map((header) => buildCustomRoute('header', header));
const builtRewrites = rewrites.map((rewrite) => buildCustomRoute('rewrite', rewrite));
routesManifest.headers = [...originalManifest.headers, ...builtHeaders];
routesManifest.rewrites = [...builtRewrites, ...originalManifest.rewrites];
console.log('Using updated Next.js routes manifest');
} else {
console.log('Using original Next.js routes manifest');
}
fs.writeFileSync(routesManifestPath, JSON.stringify(routesManifest, null, 2));