Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Docs]: Middleware context initialization (Error: No value found for context) #13252

Open
vladinator1000 opened this issue Mar 18, 2025 · 1 comment
Labels

Comments

@vladinator1000
Copy link
Contributor

vladinator1000 commented Mar 18, 2025

Describe what's incorrect/missing in the documentation

Hey folks, I'm trying out the new middleware API, followed these docs for v7.3.0 and got an error when I tried check if a context value exists:

import {
  type unstable_MiddlewareFunction,
  unstable_createContext,
} from "react-router"
import { appContext } from "~/app-context"
import { createAuthServer } from "./auth-server"

type AuthServer = ReturnType<typeof createAuthServer>

export const authServerContext = unstable_createContext<AuthServer>()

export const authMiddleware: unstable_MiddlewareFunction = async (
  { request, context },
  next,
) => {
  let authServer = context.get(authServerContext) // <-- error here

  if (!authServer) {
    let app = context.get(appContext)
    authServer = createAuthServer(app)
    context.set(authServerContext, authServer)
  }

// ...
}
Error: No value found for context
    at unstable_RouterContextProvider.get (/home/vlady/code/gyarns/node_modules/.vite/deps_ssr/chunk-QZO7VHZY.js:1384:11)
    at authMiddleware (/home/vlady/code/gyarns/app/routes/auth/auth-middleware.ts:19:28)
    at callRouteMiddleware (/home/vlady/code/gyarns/node_modules/.vite/deps_ssr/chunk-QZO7VHZY.js:4660:24)
    at runMiddlewarePipeline (/home/vlady/code/gyarns/node_modules/.vite/deps_ssr/chunk-QZO7VHZY.js:4600:24)
    at Object.query (/home/vlady/code/gyarns/node_modules/.vite/deps_ssr/chunk-QZO7VHZY.js:3696:30)
    at handleDocumentRequest (/home/vlady/code/gyarns/node_modules/.vite/deps_ssr/chunk-QZO7VHZY.js:10745:40)
    at requestHandler (/home/vlady/code/gyarns/node_modules/.vite/deps_ssr/chunk-QZO7VHZY.js:10671:24)

Why is context.get erroring here? Are we expected to initialize all contexts that can ever be used before context.get calls?

My idea was to do a "self-initialization" pattern, where the middleware creates its own dependencies if needed. I am creating an initial context like this, but I was hoping that I don't have to add stuff to that any time I create a new context type.

// app/worker.ts
import { createRequestHandler } from "react-router"
import { createAppContext } from "./app-context"

const handler = createRequestHandler(
  // @ts-expect-error - virtual module provided by React Router at build time
  () => import("virtual:react-router/server-build"),
  import.meta.env.MODE,
)

export default {
  async fetch(request, env, ctx) {
    try {
      const appContext = await createAppContext(request, env, ctx)

      // @ts-expect-error unstable types,
      // import {AppContext} from './app-context' instead of AppLoadContext
      return handler(request, appContext)
    } catch (error) {
      console.error(error)
      return new Response("An unexpected error occurred", { status: 500 })
    }
  },
} satisfies ExportedHandler<Env>
// app-context.ts
import { unstable_createContext } from "react-router"
import { type DatabaseClient, createDbClient } from "./db/db-client.server"
import { currencyCookie } from "./internationalization/cookies"
import type { Currency } from "./internationalization/currency-context"
import { i18next } from "./internationalization/i18n.server"
import { type ServerConfig, getServerConfig } from "./lib/config.server"

export type AppContext = {
  env: Env
  executionContext: ExecutionContext
  db: DatabaseClient
  config: ServerConfig
  language: string
  currency: Currency
}

/**
 * Contains data and bindings needed by most requests.
 */
export const appContext = unstable_createContext<AppContext>()

// https://github.com/remix-run/react-router/issues/13181
// https://github.com/alexanderson1993/cloudflare-middleware/pull/1/files
export async function createAppContext(
  request: Request,
  env: Env,
  executionContext: ExecutionContext,
) {
  let map = new Map()

  let db = createDbClient(env.DB)
  let config = getServerConfig(env, request)
  let language = await i18next.getLocale(request)
  let cookie = request.headers.get("Cookie")
  let currency = (await currencyCookie.parse(cookie)) ?? "EUR"

  let contextValue: AppContext = {
    env,
    executionContext,
    db,
    config,
    language,
    currency,
  }

  map.set(appContext, contextValue)

  return map
}
@vladinator1000 vladinator1000 changed the title [Docs]: New middleware API - context initialization (Error: No value found for context) [Docs]: Middleware context initialization (Error: No value found for context) Mar 18, 2025
@sergiodxa
Copy link
Member

I think you need to define an initial value for the context when you create it.

export const authServerContext = unstable_createContext<AuthServer>(initialValue)

Then when you do the context.get(authServerContext) it will return that initial value that you could use to decide if it's the initial one or not.

Maybe a symbol can work here

const initialValue = Symbol()
export const authServerContext = unstable_createContext<AuthServer>(initialValue)

// later in the middleware
const value = context.get(authServerContext)
if (value === initialValue) context.set(authServerContext, newValue)
return await next()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants