Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions app/entry.server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,16 @@ import { createInstance } from "i18next"
import { isbot } from "isbot"
import { renderToPipeableStream } from "react-dom/server"
import { I18nextProvider, initReactI18next } from "react-i18next"
import { type AppLoadContext, type EntryContext, type HandleDataRequestFunction, ServerRouter } from "react-router"
import {
type EntryContext,
type HandleDataRequestFunction,
type RouterContextProvider,
ServerRouter,
} from "react-router"
import i18n from "./localization/i18n" // your i18n configuration file
import i18nextOpts from "./localization/i18n.server"
import { resources } from "./localization/resource"
import { globalAppContext } from "./server/context"

// Reject all pending promises from handler functions after 10 seconds
export const streamTimeout = 10000
Expand All @@ -17,11 +23,12 @@ export default async function handleRequest(
responseStatusCode: number,
responseHeaders: Headers,
context: EntryContext,
appContext: AppLoadContext
appContext: RouterContextProvider
) {
const callbackName = isbot(request.headers.get("user-agent")) ? "onAllReady" : "onShellReady"
const instance = createInstance()
const lng = appContext.lang
const ctx = appContext.get(globalAppContext)
const lng = ctx.lang
const ns = i18nextOpts.getRouteNamespaces(context)

await instance
Expand All @@ -48,7 +55,7 @@ export default async function handleRequest(

resolve(
// @ts-expect-error - We purposely do not define the body as existent so it's not used inside loaders as it's injected there as well
appContext.body(stream, {
ctx.body(stream, {
headers: responseHeaders,
status: didError ? 500 : responseStatusCode,
})
Expand Down
3 changes: 2 additions & 1 deletion app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import { isRouteErrorResponse, Links, Meta, Outlet, Scripts, ScrollRestoration,
import { useChangeLanguage } from "remix-i18next/react"
import type { Route } from "./+types/root"
import { LanguageSwitcher } from "./library/language-switcher"
import { globalAppContext } from "./server/context"
import { ClientHintCheck, getHints } from "./services/client-hints"
import tailwindcss from "./tailwind.css?url"

export async function loader({ context, request }: Route.LoaderArgs) {
const { lang, clientEnv } = context
const { lang, clientEnv } = context.get(globalAppContext)
const hints = getHints(request)
return { lang, clientEnv, hints }
}
Expand Down
3 changes: 2 additions & 1 deletion app/routes/resource.locales.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { cacheHeader } from "pretty-cache-header"
import { z } from "zod/v4"
import { type Language, type Namespace, resources } from "~/localization/resource"
import { globalAppContext } from "~/server/context"
import type { Route } from "./+types/resource.locales"

export async function loader({ request, context }: Route.LoaderArgs) {
const { isProductionDeployment } = context
const { isProductionDeployment } = context.get(globalAppContext)
const url = new URL(request.url)

const lng = z.enum(Object.keys(resources) as Language[]).parse(url.searchParams.get("lng"))
Expand Down
4 changes: 2 additions & 2 deletions app/routes/robots[.]txt.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { generateRobotsTxt } from "@forge42/seo-tools/robots"

import { globalAppContext } from "~/server/context"
import { createDomain } from "~/utils/http"
import type { Route } from "./+types/robots[.]txt"

export async function loader({ request, context }: Route.LoaderArgs) {
const { isProductionDeployment } = context
const { isProductionDeployment } = context.get(globalAppContext)
const domain = createDomain(request)
const robotsTxt = generateRobotsTxt([
{
Expand Down
14 changes: 12 additions & 2 deletions app/server/context.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import type { Context } from "hono"
import { createContext, RouterContextProvider } from "react-router"
import { i18next } from "remix-hono/i18next"
import { getClientEnv, getServerEnv } from "~/env.server"

export const getLoadContext = async (c: Context) => {
export const globalAppContext = createContext<LoadContext>()

export const getAppContext = async (c: Context) => {
// get the locale from the context
const locale = i18next.getLocale(c)
// get t function for the default namespace
Expand All @@ -21,7 +24,14 @@ export const getLoadContext = async (c: Context) => {
}
}

interface LoadContext extends Awaited<ReturnType<typeof getLoadContext>> {}
export const getLoadContext = async (c: Context) => {
const ctx = new RouterContextProvider()
const globalCtx = await getAppContext(c)
ctx.set(globalAppContext, globalCtx)
return ctx
}

interface LoadContext extends Awaited<ReturnType<typeof getAppContext>> {}

/**
* Declare our loaders and actions context type
Expand Down
1 change: 1 addition & 0 deletions react-router.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ export default {
unstable_viteEnvironmentApi: true,
unstable_splitRouteModules: true,
unstable_optimizeDeps: true,
v8_middleware: true,
},
} satisfies Config