Next.js a été tristement célèbre pour sa gestion des variables d'environnement. Bien qu'il ait été amélioré au fil des années, il présente encore quelques bizarreries qui peuvent prêter à confusion, notamment lorsqu'il s'agit de variables publiques exposées via l'objet process.env.
Toutes les variables préfixées NEXT_PUBLIC_ sont accessibles côté client, mais comme mentionné dans la documentation officielle, elles ne sont disponibles qu'au moment de la construction, ne pouvant donc pas changer au moment de l'exécution lorsqu'elles sont utilisées avec Docker.
Bien que j'aie abordé ce problème dans le passé, j'ai trouvé une autre approche qui pourrait être intéressante à explorer, en utilisant des variables partagées globalement qui peuvent être modifiées au moment de l'exécution.
Les variables globales sont partiellement prises en charge par Next.js, mais nous pouvons utiliser un polyfill pour les rendre disponibles à l'aide d'un petit script injecté.
// app/layout.tsx <script dangerouslySetInnerHTML={{ __html: `!function(t){function e(){var e=this||self;e.globalThis=e,delete t.prototype._T_}"object"!=typeof globalThis&&(this?e():(t.defineProperty(t.prototype,"_T_",{configurable:!0,get:e}),_T_))}(Object);`, }} />
Le code original a été tiré de ce commentaire sur GitHub, et il crée essentiellement un objet globalThis global qui peut être utilisé pour partager des variables entre le client et le serveur. Le polyfill arrive avec Next.js 14.x, mais il semble casser l'objet globalThis dans certains navigateurs, c'est pourquoi nous utilisons la propriété __html pour injecter le code directement dans la page.
Ensuite, nous pouvons utiliser Zod pour valider les variables au moment de l'exécution et générer une erreur si les variables ne sont pas valides. Cette étape est cruciale pour garantir que les variables sont toujours disponibles et valides, évitant ainsi les erreurs d'exécution et exposant l'application à des problèmes de sécurité.
npm install zod
Nous créons ensuite un fichier variables.ts qui contiendra certaines fonctions utilitaires pour récupérer les variables de process.env et les convertir en toute sécurité dans le type attendu.
// lib/env.ts import { z } from 'zod'; // Load the variables export const load = () => { return process.env; }; // Parse or throw the variables export function parseOrThrow(schema: z.Schema, data: unknown, error: Error) { const parsed = schema.safeParse(data); // Log the errror if (parsed.success) return parsed.data; console.error(parsed.error); throw error; } // Some zod helpers to use export const port = z .string() .refine( (port) => parseInt(port) > 0 && parseInt(port) < 65536, 'Invalid port number' ); export const str = z.string(); export const url = z.string().url(); export const num = z.coerce.number(); export const bool = z.coerce.boolean();
load est une fonction simple qui renvoie l'objet process.env, tandis que parseOrThrow est une fonction utilitaire qui analyse les variables à l'aide d'un schéma Zod et renvoie une erreur si les variables ne sont pas valides.
Enfin, nous pouvons créer un fichier variables.ts qui contiendra le schéma des variables et les fonctions utilitaires pour charger et analyser les variables.
// lib/vars.ts import { z } from 'zod'; import { load, parseOrThrow } from './env'; import { parseOrThrow, load, str, num, bool, port } from './env'; // Define the variables schema const schema = z.object({ PUBLIC_VARIABLE: str.optional(), PUBLIC_MY_NUM: num, PUBLIC_BOOL: bool, PUBLIC_PORT: port, }); export const loadEnv = () => { const env = load(); const parsed = parseOrThrow(schema, env, new Error('Invalid variables')); for (const key of Object.keys(parsed)) { if (!globalThis[key]) { globalThis[key] = parsed[key]; } } };
Pour utiliser les variables, nous devons d'abord les charger. Nous pouvons le faire dans le fichier app/layout.tsx ou dans tout autre fichier de mise en page pour les exposer progressivement au reste de l'application, à la fois sur le client et sur le serveur.
// app/layout.tsx import { loadEnv } from '@/lib/vars'; loadEnv(); export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html lang="en"> <body>{children}</body> </html> ); }
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!