From 276fb7bd2ceb64ecf373b95e576a8b9720744269 Mon Sep 17 00:00:00 2001 From: Bogdan Chadkin Date: Sun, 24 Nov 2024 11:49:39 +0700 Subject: [PATCH 1/4] refactor: enable all remix future flags https://reactrouter.com/upgrading/remix https://remix.run/docs/en/2.13.1/start/future-flags#v3_fetcherpersist https://remix.run/docs/en/2.13.1/guides/single-fetch --- apps/builder/app/root.tsx | 6 +++--- apps/builder/app/routes/_ui.(builder).tsx | 4 ++-- apps/builder/app/routes/_ui.dashboard.tsx | 6 +++--- apps/builder/app/routes/_ui.login._index.tsx | 11 ++++------- apps/builder/app/routes/_ui.logout.tsx | 6 +++--- apps/builder/app/routes/_ui.tsx | 6 +++--- apps/builder/app/routes/builder-logout.ts | 4 ++-- apps/builder/app/routes/dashboard-logout.ts | 4 ++-- apps/builder/app/routes/n8n.$.tsx | 4 ++-- apps/builder/app/routes/oauth.ws.authorize.tsx | 10 +++++----- apps/builder/app/routes/oauth.ws.token.ts | 16 ++++++++-------- .../builder/app/routes/rest.build.$buildId.tsx | 6 +++--- .../app/routes/rest.buildId.$projectId.tsx | 6 +++--- .../app/routes/rest.resources-loader.ts | 8 ++++---- .../app/services/no-cross-origin-cookie.ts | 4 ++-- .../shared/$resources/sitemap.xml.server.ts | 6 +++--- apps/builder/vite.config.ts | 14 ++++++++++++++ .../app/routes/[another-page]._index.tsx | 9 +++++---- .../app/routes/_index.tsx | 9 +++++---- .../vite.config.ts | 10 +++++++++- .../app/routes/[script-test]._index.tsx | 9 +++++---- .../app/routes/[world]._index.tsx | 9 +++++---- .../app/routes/_index.tsx | 9 +++++---- .../webstudio-custom-template/vite.config.ts | 18 +++++++++++++++++- .../app/routes/[another-page]._index.tsx | 9 +++++---- .../app/routes/_index.tsx | 9 +++++---- .../vite.config.ts | 13 ++++++++++++- .../app/routes/[another-page]._index.tsx | 9 +++++---- .../app/routes/_index.tsx | 9 +++++---- .../vite.config.ts | 13 ++++++++++++- .../routes/[_route_with_symbols_]._index.tsx | 9 +++++---- .../app/routes/[class-names]._index.tsx | 9 +++++---- .../app/routes/[expressions]._index.tsx | 9 +++++---- .../app/routes/[form]._index.tsx | 9 +++++---- .../app/routes/[heading-with-id]._index.tsx | 9 +++++---- .../routes/[nested].[nested-page]._index.tsx | 9 +++++---- .../app/routes/[radix]._index.tsx | 9 +++++---- .../app/routes/[resources]._index.tsx | 9 +++++---- .../app/routes/_index.tsx | 9 +++++---- fixtures/webstudio-remix-vercel/vite.config.ts | 18 +++++++++++++++++- .../cli/templates/cloudflare/vite.config.ts | 10 +++++++++- .../defaults/app/route-templates/html.tsx | 9 +++++---- packages/cli/templates/defaults/vite.config.ts | 18 +++++++++++++++++- .../netlify-edge-functions/vite.config.ts | 13 ++++++++++++- .../templates/netlify-functions/vite.config.ts | 13 ++++++++++++- 45 files changed, 278 insertions(+), 140 deletions(-) diff --git a/apps/builder/app/root.tsx b/apps/builder/app/root.tsx index be290602a4d1..4afa5486cb30 100644 --- a/apps/builder/app/root.tsx +++ b/apps/builder/app/root.tsx @@ -1,13 +1,13 @@ // Our root outlet doesn't contain a layout because we have 2 types of documents: canvas and builder and we need to decide down the line which one to render, thre is no single root document. -import { Outlet, json, useLoaderData } from "@remix-run/react"; +import { Outlet, useLoaderData } from "@remix-run/react"; import { setEnv } from "@webstudio-is/feature-flags"; import env from "./env/env.server"; import { useSetFeatures } from "./shared/use-set-features"; export const loader = () => { - return json({ + return { features: env.FEATURES, - }); + }; }; export default function App() { diff --git a/apps/builder/app/routes/_ui.(builder).tsx b/apps/builder/app/routes/_ui.(builder).tsx index 454fe64cde9f..1e1ec55f8746 100644 --- a/apps/builder/app/routes/_ui.(builder).tsx +++ b/apps/builder/app/routes/_ui.(builder).tsx @@ -7,7 +7,7 @@ import { lazy } from "react"; import { useLoaderData } from "@remix-run/react"; import type { MetaFunction, ShouldRevalidateFunction } from "@remix-run/react"; import { - json, + data, type HeadersArgs, type LoaderFunctionArgs, } from "@remix-run/server-runtime"; @@ -207,7 +207,7 @@ export const loader = async (loaderArgs: LoaderFunctionArgs) => { `frame-src ${url.origin}/canvas https://app.goentri.com/; worker-src 'none'` ); - return json( + return data( { project, publisherHost, diff --git a/apps/builder/app/routes/_ui.dashboard.tsx b/apps/builder/app/routes/_ui.dashboard.tsx index 07b45474f521..df3fcc5707d6 100644 --- a/apps/builder/app/routes/_ui.dashboard.tsx +++ b/apps/builder/app/routes/_ui.dashboard.tsx @@ -1,6 +1,6 @@ import { lazy } from "react"; import { useLoaderData, type MetaFunction } from "@remix-run/react"; -import { json, type LoaderFunctionArgs } from "@remix-run/server-runtime"; +import type { LoaderFunctionArgs } from "@remix-run/server-runtime"; import { dashboardProjectRouter } from "@webstudio-is/dashboard/index.server"; import { findAuthenticatedUser } from "~/services/auth.server"; import { builderUrl, isDashboard, loginPath } from "~/shared/router-utils"; @@ -112,7 +112,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { const { sourceOrigin } = parseBuilderUrl(request.url); - return json({ + return { user, projects, projectTemplates, @@ -121,7 +121,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { imageBaseUrl: env.IMAGE_BASE_URL, origin: sourceOrigin, projectToClone, - }); + }; }; /** diff --git a/apps/builder/app/routes/_ui.login._index.tsx b/apps/builder/app/routes/_ui.login._index.tsx index 246df700f718..1c32cbf83394 100644 --- a/apps/builder/app/routes/_ui.login._index.tsx +++ b/apps/builder/app/routes/_ui.login._index.tsx @@ -1,8 +1,7 @@ import { type LinksFunction, type LoaderFunctionArgs, - type TypedResponse, - json, + data, } from "@remix-run/server-runtime"; import { useLoaderData, type MetaFunction } from "@remix-run/react"; import { findAuthenticatedUser } from "~/services/auth.server"; @@ -49,9 +48,7 @@ export const meta: MetaFunction = () => { return metas; }; -export const loader = async ({ - request, -}: LoaderFunctionArgs): Promise> => { +export const loader = async ({ request }: LoaderFunctionArgs) => { if (false === isDashboard(request)) { throw new Response("Not Found", { status: 404, @@ -83,14 +80,14 @@ export const loader = async ({ headers.append("Set-Cookie", await returnToCookie.serialize(returnTo)); - return json( + return data( { isSecretLoginEnabled: env.DEV_LOGIN === "true", isGithubEnabled: Boolean(env.GH_CLIENT_ID && env.GH_CLIENT_SECRET), isGoogleEnabled: Boolean( env.GOOGLE_CLIENT_ID && env.GOOGLE_CLIENT_SECRET ), - }, + } satisfies LoginProps, { headers } ); }; diff --git a/apps/builder/app/routes/_ui.logout.tsx b/apps/builder/app/routes/_ui.logout.tsx index 74fd57e1450b..d81e8fe0e5af 100644 --- a/apps/builder/app/routes/_ui.logout.tsx +++ b/apps/builder/app/routes/_ui.logout.tsx @@ -1,4 +1,4 @@ -import { json, type LoaderFunctionArgs } from "@remix-run/server-runtime"; +import type { LoaderFunctionArgs } from "@remix-run/server-runtime"; import { createDebug } from "~/shared/debug"; import { builderUrl, isDashboard, loginPath } from "~/shared/router-utils"; import { preventCrossOriginCookie } from "~/services/no-cross-origin-cookie"; @@ -58,10 +58,10 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { `${builderUrl({ projectId, origin: url.origin })}builder-logout` ); - return json({ + return { redirectTo, logoutUrls, - }); + }; } catch (error) { if (error instanceof Response) { throw error; diff --git a/apps/builder/app/routes/_ui.tsx b/apps/builder/app/routes/_ui.tsx index 26dbc5987888..e6eaad8bec83 100644 --- a/apps/builder/app/routes/_ui.tsx +++ b/apps/builder/app/routes/_ui.tsx @@ -11,7 +11,7 @@ import manropeVariableFont from "@fontsource-variable/manrope/index.css?url"; import robotoMonoFont from "@fontsource/roboto-mono/index.css?url"; import appCss from "../shared/app.css?url"; import { - json, + data, type LinksFunction, type LoaderFunctionArgs, } from "@remix-run/server-runtime"; @@ -56,7 +56,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { const [csrfToken, setCookieValue] = await getCsrfTokenAndCookie(request); if (request.headers.get("sec-fetch-mode") !== "navigate") { - return json({ csrfToken: "" }); + return { csrfToken: "" }; } const headers = new Headers(); @@ -65,7 +65,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { headers.set("Set-Cookie", setCookieValue); } - return json( + return data( { csrfToken }, { headers, diff --git a/apps/builder/app/routes/builder-logout.ts b/apps/builder/app/routes/builder-logout.ts index 2037af64688f..4e67bc49838e 100644 --- a/apps/builder/app/routes/builder-logout.ts +++ b/apps/builder/app/routes/builder-logout.ts @@ -1,4 +1,4 @@ -import { json, type ActionFunctionArgs } from "@remix-run/server-runtime"; +import { data, type ActionFunctionArgs } from "@remix-run/server-runtime"; import { createDebug } from "~/shared/debug"; import { builderAuthenticator } from "~/services/builder-auth.server"; import { getAuthorizationServerOrigin } from "~/shared/router-utils/origins"; @@ -19,7 +19,7 @@ export const action = async ({ request }: ActionFunctionArgs) => { } if (request.method !== "POST") { - return json( + return data( { message: "Method not allowed" }, { status: 405, diff --git a/apps/builder/app/routes/dashboard-logout.ts b/apps/builder/app/routes/dashboard-logout.ts index 7d949d854cbe..ca2cffd68e8d 100644 --- a/apps/builder/app/routes/dashboard-logout.ts +++ b/apps/builder/app/routes/dashboard-logout.ts @@ -1,4 +1,4 @@ -import { json } from "@remix-run/server-runtime"; +import { data } from "@remix-run/server-runtime"; import { authenticator } from "~/services/auth.server"; import { isDashboard, loginPath } from "~/shared/router-utils"; import { preventCrossOriginCookie } from "~/services/no-cross-origin-cookie"; @@ -32,7 +32,7 @@ export const action = async ({ request }: ActionFunctionArgs) => { headers.set("Content-Type", "application/json"); - return json( + return data( { redirectTo: error.headers.get("Location"), }, diff --git a/apps/builder/app/routes/n8n.$.tsx b/apps/builder/app/routes/n8n.$.tsx index f6d81c803a63..e2fc6e7e4738 100644 --- a/apps/builder/app/routes/n8n.$.tsx +++ b/apps/builder/app/routes/n8n.$.tsx @@ -1,4 +1,4 @@ -import { type LoaderFunctionArgs, json } from "@remix-run/server-runtime"; +import type { LoaderFunctionArgs } from "@remix-run/server-runtime"; import { isRouteErrorResponse, useRouteError } from "@remix-run/react"; import { z } from "zod"; import { findAuthenticatedUser } from "~/services/auth.server"; @@ -119,7 +119,7 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => { n8nResponse satisfies never; - return json({}); + return {}; }; export const ErrorBoundary = () => { diff --git a/apps/builder/app/routes/oauth.ws.authorize.tsx b/apps/builder/app/routes/oauth.ws.authorize.tsx index 2d425648169a..68f800110dff 100644 --- a/apps/builder/app/routes/oauth.ws.authorize.tsx +++ b/apps/builder/app/routes/oauth.ws.authorize.tsx @@ -1,4 +1,4 @@ -import { json, type LoaderFunction } from "@remix-run/server-runtime"; +import { data, type LoaderFunction } from "@remix-run/server-runtime"; import { z } from "zod"; import { createDebug } from "~/shared/debug"; import { fromError } from "zod-validation-error"; @@ -103,7 +103,7 @@ export const loader: LoaderFunction = async ({ request }) => { if (false === parsedRedirect.success) { debug("redirect_uri not provided in query params"); - return json( + return data( { error: "invalid_request", error_description: "No redirect_uri provided", @@ -126,7 +126,7 @@ export const loader: LoaderFunction = async ({ request }) => { ) { debug("redirect_uri does not match the registered redirect URIs"); - return json( + return data( { error: "invalid_request", error_description: @@ -196,7 +196,7 @@ export const loader: LoaderFunction = async ({ request }) => { ) { debug("redirect_uri does not match the registered redirect URIs"); - return json( + return data( { error: "invalid_request", error_description: @@ -260,7 +260,7 @@ export const loader: LoaderFunction = async ({ request }) => { console.error("error", error); debug("error", error); - throw json( + throw data( { error: "server_error", error_description: diff --git a/apps/builder/app/routes/oauth.ws.token.ts b/apps/builder/app/routes/oauth.ws.token.ts index 866e77ea058a..18ce51e81a14 100644 --- a/apps/builder/app/routes/oauth.ws.token.ts +++ b/apps/builder/app/routes/oauth.ws.token.ts @@ -1,4 +1,4 @@ -import { type ActionFunctionArgs, json } from "@remix-run/server-runtime"; +import { type ActionFunctionArgs, data } from "@remix-run/server-runtime"; import { z } from "zod"; import { createDebug } from "~/shared/debug"; @@ -54,7 +54,7 @@ export const action = async ({ request }: ActionFunctionArgs) => { const authorizationHeader = request.headers.get("Authorization"); if (authorizationHeader === null) { - return json( + return data( { error: "invalid_request", error_description: "missing client credentials", @@ -79,7 +79,7 @@ export const action = async ({ request }: ActionFunctionArgs) => { clientSecret !== env.AUTH_WS_CLIENT_SECRET ) { debug("client_id and client_secret do not match", clientId, clientSecret); - return json( + return data( { error: "invalid_client", error_description: "invalid client credentials", @@ -97,7 +97,7 @@ export const action = async ({ request }: ActionFunctionArgs) => { if (false === parsedBody.success) { debug(fromError(parsedBody.error).toString()); - return json( + return data( { error: "invalid_request", error_description: fromError(parsedBody.error).toString(), @@ -114,7 +114,7 @@ export const action = async ({ request }: ActionFunctionArgs) => { if (codeToken === undefined) { debug("Code can not be read", body.code); - return json( + return data( { error: "invalid_grant", error_description: "invalid code", @@ -135,7 +135,7 @@ export const action = async ({ request }: ActionFunctionArgs) => { body.code_verifier, codeToken.codeChallenge ); - return json( + return data( { error: "invalid_grant", error_description: "invalid code_verifier", @@ -151,7 +151,7 @@ export const action = async ({ request }: ActionFunctionArgs) => { if (false === isAuthorized) { debug("User does not have access to the project", userId, projectId); - return json( + return data( { error: "invalid_grant", error_description: "user does not have access to the project", @@ -179,7 +179,7 @@ export const action = async ({ request }: ActionFunctionArgs) => { await readAccessToken(accessToken, env.AUTH_WS_CLIENT_SECRET) ); - return json( + return data( { access_token: accessToken, token_type: "Bearer", diff --git a/apps/builder/app/routes/rest.build.$buildId.tsx b/apps/builder/app/routes/rest.build.$buildId.tsx index afbb76a4281c..71324ebed14d 100644 --- a/apps/builder/app/routes/rest.build.$buildId.tsx +++ b/apps/builder/app/routes/rest.build.$buildId.tsx @@ -1,5 +1,5 @@ import { - json, + data, type LoaderFunctionArgs, type TypedResponse, } from "@remix-run/server-runtime"; @@ -39,7 +39,7 @@ export const loader = async ({ const buildId = params.buildId; if (buildId === undefined) { - throw json("Required build id", { status: 400 }); + throw data("Required build id", { status: 400 }); } const context = await createContext(request); @@ -72,7 +72,7 @@ export const loader = async ({ console.error(error); // We have no idea what happened, so we'll return a 500 error. - throw json(parseError(error), { + throw data(parseError(error), { status: 500, }); } diff --git a/apps/builder/app/routes/rest.buildId.$projectId.tsx b/apps/builder/app/routes/rest.buildId.$projectId.tsx index a6d43b6efe83..6f9da9679f00 100644 --- a/apps/builder/app/routes/rest.buildId.$projectId.tsx +++ b/apps/builder/app/routes/rest.buildId.$projectId.tsx @@ -1,5 +1,5 @@ import { - json, + data, type LoaderFunctionArgs, type TypedResponse, } from "@remix-run/server-runtime"; @@ -34,7 +34,7 @@ export const loader = async ({ const projectId = params.projectId; if (projectId === undefined) { - throw json("Required project id", { status: 400 }); + throw data("Required project id", { status: 400 }); } // @todo Create a context without user authentication information. @@ -55,7 +55,7 @@ export const loader = async ({ console.error(error); - throw json(parseError(error), { + throw data(parseError(error), { status: 500, }); } diff --git a/apps/builder/app/routes/rest.resources-loader.ts b/apps/builder/app/routes/rest.resources-loader.ts index 07529a9b7412..1bf4afbbacef 100644 --- a/apps/builder/app/routes/rest.resources-loader.ts +++ b/apps/builder/app/routes/rest.resources-loader.ts @@ -1,5 +1,5 @@ import { z } from "zod"; -import { json, type ActionFunctionArgs } from "@remix-run/server-runtime"; +import { data, type ActionFunctionArgs } from "@remix-run/server-runtime"; import { ResourceRequest } from "@webstudio-is/sdk"; import { isLocalResource, loadResource } from "@webstudio-is/sdk/runtime"; import { loader as siteMapLoader } from "../shared/$resources/sitemap.xml.server"; @@ -11,13 +11,13 @@ export const action = async ({ request }: ActionFunctionArgs) => { await checkCsrf(request); // Hope Remix will have customFetch by default, see https://kit.svelte.dev/docs/load#making-fetch-requests - const customFetch: typeof fetch = (input, init) => { + const customFetch: typeof fetch = async (input, init) => { if (typeof input !== "string") { return fetch(input, init); } if (isLocalResource(input, "sitemap.xml")) { - return siteMapLoader({ request }); + return Response.json(siteMapLoader({ request })); } return fetch(input, init); @@ -36,7 +36,7 @@ export const action = async ({ request }: ActionFunctionArgs) => { ); console.error("data:", requestJson); - throw json(computedResourcesParsed.error, { + throw data(computedResourcesParsed.error, { status: 400, }); } diff --git a/apps/builder/app/services/no-cross-origin-cookie.ts b/apps/builder/app/services/no-cross-origin-cookie.ts index 36fa78c84df8..930477cf44d7 100644 --- a/apps/builder/app/services/no-cross-origin-cookie.ts +++ b/apps/builder/app/services/no-cross-origin-cookie.ts @@ -1,4 +1,4 @@ -import { json } from "@remix-run/server-runtime"; +import { data } from "@remix-run/server-runtime"; /** * https://kevincox.ca/2024/08/24/cors/ @@ -46,7 +46,7 @@ export const preventCrossOriginCookie = ( ]); // allow service calls - throw json( + throw data( { message: `Cross-origin request to ${request.url}`, }, diff --git a/apps/builder/app/shared/$resources/sitemap.xml.server.ts b/apps/builder/app/shared/$resources/sitemap.xml.server.ts index 2ca651dabd35..55ad351439da 100644 --- a/apps/builder/app/shared/$resources/sitemap.xml.server.ts +++ b/apps/builder/app/shared/$resources/sitemap.xml.server.ts @@ -1,4 +1,4 @@ -import { json } from "@remix-run/server-runtime"; +import { data } from "@remix-run/server-runtime"; import { parsePages } from "@webstudio-is/project-build/index.server"; import { getStaticSiteMapXml } from "@webstudio-is/sdk"; import { parseBuilderUrl } from "@webstudio-is/http-client"; @@ -32,7 +32,7 @@ export const loader = async ({ request }: { request: Request }) => { .single(); if (buildResult.error) { - throw json({ message: buildResult.error.message }, { status: 404 }); + throw data({ message: buildResult.error.message }, { status: 404 }); } const build = buildResult.data; @@ -41,5 +41,5 @@ export const loader = async ({ request }: { request: Request }) => { const siteMap = getStaticSiteMapXml(pages, build.updatedAt); - return json(siteMap); + return siteMap; }; diff --git a/apps/builder/vite.config.ts b/apps/builder/vite.config.ts index 546710fb483a..cac241e6ad66 100644 --- a/apps/builder/vite.config.ts +++ b/apps/builder/vite.config.ts @@ -11,6 +11,13 @@ import { } from "./app/shared/router-utils/origins"; import { readFileSync } from "node:fs"; +declare module "@remix-run/node" { + // or cloudflare, deno, etc. + interface Future { + v3_singleFetch: true; + } +} + export default defineConfig(({ mode }) => { if (mode === "test") { return { @@ -36,6 +43,13 @@ export default defineConfig(({ mode }) => { plugins: [ remix({ presets: [vercelPreset()], + future: { + v3_singleFetch: true, + v3_fetcherPersist: true, + v3_relativeSplatPath: true, + v3_throwAbortReason: true, + v3_lazyRouteDiscovery: true, + }, }), { name: "request-timing-logger", diff --git a/fixtures/webstudio-cloudflare-template/app/routes/[another-page]._index.tsx b/fixtures/webstudio-cloudflare-template/app/routes/[another-page]._index.tsx index 96b66e25b8d3..ea5764804c76 100644 --- a/fixtures/webstudio-cloudflare-template/app/routes/[another-page]._index.tsx +++ b/fixtures/webstudio-cloudflare-template/app/routes/[another-page]._index.tsx @@ -5,7 +5,7 @@ import { type ActionFunctionArgs, type LoaderFunctionArgs, type HeadersFunction, - json, + data, redirect, } from "@remix-run/server-runtime"; import { useLoaderData } from "@remix-run/react"; @@ -50,7 +50,8 @@ const customFetch: typeof fetch = (input, init) => { return fetch(input, init); }; -export const loader = async (arg: LoaderFunctionArgs) => { +// have not idea how to win this error The inferred type of 'loader' cannot be named without a reference to '.pnpm/@remix-run+router@1.21.0/node_modules/@remix-run/router'. This is likely not portable. A type annotation is necessary. +export const loader = async (arg: LoaderFunctionArgs): Promise => { const url = new URL(arg.request.url); const host = arg.request.headers.get("x-forwarded-host") || @@ -77,7 +78,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.status === 301 || pageMeta.status === 302 ? pageMeta.status : 302; - return redirect(pageMeta.redirect, status); + throw redirect(pageMeta.redirect, status); } // typecheck @@ -87,7 +88,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.excludePageFromSearch = arg.context.EXCLUDE_FROM_SEARCH; } - return json( + return data( { host, url: url.href, diff --git a/fixtures/webstudio-cloudflare-template/app/routes/_index.tsx b/fixtures/webstudio-cloudflare-template/app/routes/_index.tsx index 83e8ee2cfd3a..13669db847a3 100644 --- a/fixtures/webstudio-cloudflare-template/app/routes/_index.tsx +++ b/fixtures/webstudio-cloudflare-template/app/routes/_index.tsx @@ -5,7 +5,7 @@ import { type ActionFunctionArgs, type LoaderFunctionArgs, type HeadersFunction, - json, + data, redirect, } from "@remix-run/server-runtime"; import { useLoaderData } from "@remix-run/react"; @@ -50,7 +50,8 @@ const customFetch: typeof fetch = (input, init) => { return fetch(input, init); }; -export const loader = async (arg: LoaderFunctionArgs) => { +// have not idea how to win this error The inferred type of 'loader' cannot be named without a reference to '.pnpm/@remix-run+router@1.21.0/node_modules/@remix-run/router'. This is likely not portable. A type annotation is necessary. +export const loader = async (arg: LoaderFunctionArgs): Promise => { const url = new URL(arg.request.url); const host = arg.request.headers.get("x-forwarded-host") || @@ -77,7 +78,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.status === 301 || pageMeta.status === 302 ? pageMeta.status : 302; - return redirect(pageMeta.redirect, status); + throw redirect(pageMeta.redirect, status); } // typecheck @@ -87,7 +88,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.excludePageFromSearch = arg.context.EXCLUDE_FROM_SEARCH; } - return json( + return data( { host, url: url.href, diff --git a/fixtures/webstudio-cloudflare-template/vite.config.ts b/fixtures/webstudio-cloudflare-template/vite.config.ts index 26a4f23dbca3..d5e4613a2d76 100644 --- a/fixtures/webstudio-cloudflare-template/vite.config.ts +++ b/fixtures/webstudio-cloudflare-template/vite.config.ts @@ -8,6 +8,14 @@ export default defineConfig(({ mode }) => ({ plugins: [ // without this, remixCloudflareDevProxy trying to load workerd even for production (it's not needed for production) mode === "production" ? undefined : remixCloudflareDevProxy(), - remix(), + remix({ + future: { + v3_singleFetch: true, + v3_fetcherPersist: true, + v3_relativeSplatPath: true, + v3_throwAbortReason: true, + v3_lazyRouteDiscovery: true, + }, + }), ].filter(Boolean), })); diff --git a/fixtures/webstudio-custom-template/app/routes/[script-test]._index.tsx b/fixtures/webstudio-custom-template/app/routes/[script-test]._index.tsx index bace806e6e14..89f50d6d5181 100644 --- a/fixtures/webstudio-custom-template/app/routes/[script-test]._index.tsx +++ b/fixtures/webstudio-custom-template/app/routes/[script-test]._index.tsx @@ -5,7 +5,7 @@ import { type ActionFunctionArgs, type LoaderFunctionArgs, type HeadersFunction, - json, + data, redirect, } from "@remix-run/server-runtime"; import { useLoaderData } from "@remix-run/react"; @@ -50,7 +50,8 @@ const customFetch: typeof fetch = (input, init) => { return fetch(input, init); }; -export const loader = async (arg: LoaderFunctionArgs) => { +// have not idea how to win this error The inferred type of 'loader' cannot be named without a reference to '.pnpm/@remix-run+router@1.21.0/node_modules/@remix-run/router'. This is likely not portable. A type annotation is necessary. +export const loader = async (arg: LoaderFunctionArgs): Promise => { const url = new URL(arg.request.url); const host = arg.request.headers.get("x-forwarded-host") || @@ -77,7 +78,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.status === 301 || pageMeta.status === 302 ? pageMeta.status : 302; - return redirect(pageMeta.redirect, status); + throw redirect(pageMeta.redirect, status); } // typecheck @@ -87,7 +88,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.excludePageFromSearch = arg.context.EXCLUDE_FROM_SEARCH; } - return json( + return data( { host, url: url.href, diff --git a/fixtures/webstudio-custom-template/app/routes/[world]._index.tsx b/fixtures/webstudio-custom-template/app/routes/[world]._index.tsx index cabe7ad15641..28212ccfb03d 100644 --- a/fixtures/webstudio-custom-template/app/routes/[world]._index.tsx +++ b/fixtures/webstudio-custom-template/app/routes/[world]._index.tsx @@ -5,7 +5,7 @@ import { type ActionFunctionArgs, type LoaderFunctionArgs, type HeadersFunction, - json, + data, redirect, } from "@remix-run/server-runtime"; import { useLoaderData } from "@remix-run/react"; @@ -50,7 +50,8 @@ const customFetch: typeof fetch = (input, init) => { return fetch(input, init); }; -export const loader = async (arg: LoaderFunctionArgs) => { +// have not idea how to win this error The inferred type of 'loader' cannot be named without a reference to '.pnpm/@remix-run+router@1.21.0/node_modules/@remix-run/router'. This is likely not portable. A type annotation is necessary. +export const loader = async (arg: LoaderFunctionArgs): Promise => { const url = new URL(arg.request.url); const host = arg.request.headers.get("x-forwarded-host") || @@ -77,7 +78,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.status === 301 || pageMeta.status === 302 ? pageMeta.status : 302; - return redirect(pageMeta.redirect, status); + throw redirect(pageMeta.redirect, status); } // typecheck @@ -87,7 +88,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.excludePageFromSearch = arg.context.EXCLUDE_FROM_SEARCH; } - return json( + return data( { host, url: url.href, diff --git a/fixtures/webstudio-custom-template/app/routes/_index.tsx b/fixtures/webstudio-custom-template/app/routes/_index.tsx index 83e8ee2cfd3a..13669db847a3 100644 --- a/fixtures/webstudio-custom-template/app/routes/_index.tsx +++ b/fixtures/webstudio-custom-template/app/routes/_index.tsx @@ -5,7 +5,7 @@ import { type ActionFunctionArgs, type LoaderFunctionArgs, type HeadersFunction, - json, + data, redirect, } from "@remix-run/server-runtime"; import { useLoaderData } from "@remix-run/react"; @@ -50,7 +50,8 @@ const customFetch: typeof fetch = (input, init) => { return fetch(input, init); }; -export const loader = async (arg: LoaderFunctionArgs) => { +// have not idea how to win this error The inferred type of 'loader' cannot be named without a reference to '.pnpm/@remix-run+router@1.21.0/node_modules/@remix-run/router'. This is likely not portable. A type annotation is necessary. +export const loader = async (arg: LoaderFunctionArgs): Promise => { const url = new URL(arg.request.url); const host = arg.request.headers.get("x-forwarded-host") || @@ -77,7 +78,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.status === 301 || pageMeta.status === 302 ? pageMeta.status : 302; - return redirect(pageMeta.redirect, status); + throw redirect(pageMeta.redirect, status); } // typecheck @@ -87,7 +88,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.excludePageFromSearch = arg.context.EXCLUDE_FROM_SEARCH; } - return json( + return data( { host, url: url.href, diff --git a/fixtures/webstudio-custom-template/vite.config.ts b/fixtures/webstudio-custom-template/vite.config.ts index 137c08462414..1a68023ffd34 100644 --- a/fixtures/webstudio-custom-template/vite.config.ts +++ b/fixtures/webstudio-custom-template/vite.config.ts @@ -1,6 +1,22 @@ import { defineConfig } from "vite"; import { vitePlugin as remix } from "@remix-run/dev"; +declare module "@remix-run/server-runtime" { + interface Future { + v3_singleFetch: true; + } +} + export default defineConfig({ - plugins: [remix()], + plugins: [ + remix({ + future: { + v3_singleFetch: true, + v3_fetcherPersist: true, + v3_relativeSplatPath: true, + v3_throwAbortReason: true, + v3_lazyRouteDiscovery: true, + }, + }), + ], }); diff --git a/fixtures/webstudio-remix-netlify-edge-functions/app/routes/[another-page]._index.tsx b/fixtures/webstudio-remix-netlify-edge-functions/app/routes/[another-page]._index.tsx index 96b66e25b8d3..ea5764804c76 100644 --- a/fixtures/webstudio-remix-netlify-edge-functions/app/routes/[another-page]._index.tsx +++ b/fixtures/webstudio-remix-netlify-edge-functions/app/routes/[another-page]._index.tsx @@ -5,7 +5,7 @@ import { type ActionFunctionArgs, type LoaderFunctionArgs, type HeadersFunction, - json, + data, redirect, } from "@remix-run/server-runtime"; import { useLoaderData } from "@remix-run/react"; @@ -50,7 +50,8 @@ const customFetch: typeof fetch = (input, init) => { return fetch(input, init); }; -export const loader = async (arg: LoaderFunctionArgs) => { +// have not idea how to win this error The inferred type of 'loader' cannot be named without a reference to '.pnpm/@remix-run+router@1.21.0/node_modules/@remix-run/router'. This is likely not portable. A type annotation is necessary. +export const loader = async (arg: LoaderFunctionArgs): Promise => { const url = new URL(arg.request.url); const host = arg.request.headers.get("x-forwarded-host") || @@ -77,7 +78,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.status === 301 || pageMeta.status === 302 ? pageMeta.status : 302; - return redirect(pageMeta.redirect, status); + throw redirect(pageMeta.redirect, status); } // typecheck @@ -87,7 +88,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.excludePageFromSearch = arg.context.EXCLUDE_FROM_SEARCH; } - return json( + return data( { host, url: url.href, diff --git a/fixtures/webstudio-remix-netlify-edge-functions/app/routes/_index.tsx b/fixtures/webstudio-remix-netlify-edge-functions/app/routes/_index.tsx index 83e8ee2cfd3a..13669db847a3 100644 --- a/fixtures/webstudio-remix-netlify-edge-functions/app/routes/_index.tsx +++ b/fixtures/webstudio-remix-netlify-edge-functions/app/routes/_index.tsx @@ -5,7 +5,7 @@ import { type ActionFunctionArgs, type LoaderFunctionArgs, type HeadersFunction, - json, + data, redirect, } from "@remix-run/server-runtime"; import { useLoaderData } from "@remix-run/react"; @@ -50,7 +50,8 @@ const customFetch: typeof fetch = (input, init) => { return fetch(input, init); }; -export const loader = async (arg: LoaderFunctionArgs) => { +// have not idea how to win this error The inferred type of 'loader' cannot be named without a reference to '.pnpm/@remix-run+router@1.21.0/node_modules/@remix-run/router'. This is likely not portable. A type annotation is necessary. +export const loader = async (arg: LoaderFunctionArgs): Promise => { const url = new URL(arg.request.url); const host = arg.request.headers.get("x-forwarded-host") || @@ -77,7 +78,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.status === 301 || pageMeta.status === 302 ? pageMeta.status : 302; - return redirect(pageMeta.redirect, status); + throw redirect(pageMeta.redirect, status); } // typecheck @@ -87,7 +88,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.excludePageFromSearch = arg.context.EXCLUDE_FROM_SEARCH; } - return json( + return data( { host, url: url.href, diff --git a/fixtures/webstudio-remix-netlify-edge-functions/vite.config.ts b/fixtures/webstudio-remix-netlify-edge-functions/vite.config.ts index a03b31397a26..05188ff819ca 100644 --- a/fixtures/webstudio-remix-netlify-edge-functions/vite.config.ts +++ b/fixtures/webstudio-remix-netlify-edge-functions/vite.config.ts @@ -3,5 +3,16 @@ import { defineConfig } from "vite"; import { netlifyPlugin } from "@netlify/remix-edge-adapter/plugin"; export default defineConfig({ - plugins: [remix(), netlifyPlugin()], + plugins: [ + remix({ + future: { + v3_singleFetch: true, + v3_fetcherPersist: true, + v3_relativeSplatPath: true, + v3_throwAbortReason: true, + v3_lazyRouteDiscovery: true, + }, + }), + netlifyPlugin(), + ], }); diff --git a/fixtures/webstudio-remix-netlify-functions/app/routes/[another-page]._index.tsx b/fixtures/webstudio-remix-netlify-functions/app/routes/[another-page]._index.tsx index 96b66e25b8d3..ea5764804c76 100644 --- a/fixtures/webstudio-remix-netlify-functions/app/routes/[another-page]._index.tsx +++ b/fixtures/webstudio-remix-netlify-functions/app/routes/[another-page]._index.tsx @@ -5,7 +5,7 @@ import { type ActionFunctionArgs, type LoaderFunctionArgs, type HeadersFunction, - json, + data, redirect, } from "@remix-run/server-runtime"; import { useLoaderData } from "@remix-run/react"; @@ -50,7 +50,8 @@ const customFetch: typeof fetch = (input, init) => { return fetch(input, init); }; -export const loader = async (arg: LoaderFunctionArgs) => { +// have not idea how to win this error The inferred type of 'loader' cannot be named without a reference to '.pnpm/@remix-run+router@1.21.0/node_modules/@remix-run/router'. This is likely not portable. A type annotation is necessary. +export const loader = async (arg: LoaderFunctionArgs): Promise => { const url = new URL(arg.request.url); const host = arg.request.headers.get("x-forwarded-host") || @@ -77,7 +78,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.status === 301 || pageMeta.status === 302 ? pageMeta.status : 302; - return redirect(pageMeta.redirect, status); + throw redirect(pageMeta.redirect, status); } // typecheck @@ -87,7 +88,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.excludePageFromSearch = arg.context.EXCLUDE_FROM_SEARCH; } - return json( + return data( { host, url: url.href, diff --git a/fixtures/webstudio-remix-netlify-functions/app/routes/_index.tsx b/fixtures/webstudio-remix-netlify-functions/app/routes/_index.tsx index 83e8ee2cfd3a..13669db847a3 100644 --- a/fixtures/webstudio-remix-netlify-functions/app/routes/_index.tsx +++ b/fixtures/webstudio-remix-netlify-functions/app/routes/_index.tsx @@ -5,7 +5,7 @@ import { type ActionFunctionArgs, type LoaderFunctionArgs, type HeadersFunction, - json, + data, redirect, } from "@remix-run/server-runtime"; import { useLoaderData } from "@remix-run/react"; @@ -50,7 +50,8 @@ const customFetch: typeof fetch = (input, init) => { return fetch(input, init); }; -export const loader = async (arg: LoaderFunctionArgs) => { +// have not idea how to win this error The inferred type of 'loader' cannot be named without a reference to '.pnpm/@remix-run+router@1.21.0/node_modules/@remix-run/router'. This is likely not portable. A type annotation is necessary. +export const loader = async (arg: LoaderFunctionArgs): Promise => { const url = new URL(arg.request.url); const host = arg.request.headers.get("x-forwarded-host") || @@ -77,7 +78,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.status === 301 || pageMeta.status === 302 ? pageMeta.status : 302; - return redirect(pageMeta.redirect, status); + throw redirect(pageMeta.redirect, status); } // typecheck @@ -87,7 +88,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.excludePageFromSearch = arg.context.EXCLUDE_FROM_SEARCH; } - return json( + return data( { host, url: url.href, diff --git a/fixtures/webstudio-remix-netlify-functions/vite.config.ts b/fixtures/webstudio-remix-netlify-functions/vite.config.ts index 7bd01662c22c..0fd811806049 100644 --- a/fixtures/webstudio-remix-netlify-functions/vite.config.ts +++ b/fixtures/webstudio-remix-netlify-functions/vite.config.ts @@ -3,5 +3,16 @@ import { defineConfig } from "vite"; import { netlifyPlugin } from "@netlify/remix-adapter/plugin"; export default defineConfig({ - plugins: [remix(), netlifyPlugin()], + plugins: [ + remix({ + future: { + v3_singleFetch: true, + v3_fetcherPersist: true, + v3_relativeSplatPath: true, + v3_throwAbortReason: true, + v3_lazyRouteDiscovery: true, + }, + }), + netlifyPlugin(), + ], }); diff --git a/fixtures/webstudio-remix-vercel/app/routes/[_route_with_symbols_]._index.tsx b/fixtures/webstudio-remix-vercel/app/routes/[_route_with_symbols_]._index.tsx index 21e182ee53a3..cd4348c0e6f7 100644 --- a/fixtures/webstudio-remix-vercel/app/routes/[_route_with_symbols_]._index.tsx +++ b/fixtures/webstudio-remix-vercel/app/routes/[_route_with_symbols_]._index.tsx @@ -5,7 +5,7 @@ import { type ActionFunctionArgs, type LoaderFunctionArgs, type HeadersFunction, - json, + data, redirect, } from "@remix-run/server-runtime"; import { useLoaderData } from "@remix-run/react"; @@ -50,7 +50,8 @@ const customFetch: typeof fetch = (input, init) => { return fetch(input, init); }; -export const loader = async (arg: LoaderFunctionArgs) => { +// have not idea how to win this error The inferred type of 'loader' cannot be named without a reference to '.pnpm/@remix-run+router@1.21.0/node_modules/@remix-run/router'. This is likely not portable. A type annotation is necessary. +export const loader = async (arg: LoaderFunctionArgs): Promise => { const url = new URL(arg.request.url); const host = arg.request.headers.get("x-forwarded-host") || @@ -77,7 +78,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.status === 301 || pageMeta.status === 302 ? pageMeta.status : 302; - return redirect(pageMeta.redirect, status); + throw redirect(pageMeta.redirect, status); } // typecheck @@ -87,7 +88,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.excludePageFromSearch = arg.context.EXCLUDE_FROM_SEARCH; } - return json( + return data( { host, url: url.href, diff --git a/fixtures/webstudio-remix-vercel/app/routes/[class-names]._index.tsx b/fixtures/webstudio-remix-vercel/app/routes/[class-names]._index.tsx index 45f7ed05a6e0..61c5e5e708f0 100644 --- a/fixtures/webstudio-remix-vercel/app/routes/[class-names]._index.tsx +++ b/fixtures/webstudio-remix-vercel/app/routes/[class-names]._index.tsx @@ -5,7 +5,7 @@ import { type ActionFunctionArgs, type LoaderFunctionArgs, type HeadersFunction, - json, + data, redirect, } from "@remix-run/server-runtime"; import { useLoaderData } from "@remix-run/react"; @@ -50,7 +50,8 @@ const customFetch: typeof fetch = (input, init) => { return fetch(input, init); }; -export const loader = async (arg: LoaderFunctionArgs) => { +// have not idea how to win this error The inferred type of 'loader' cannot be named without a reference to '.pnpm/@remix-run+router@1.21.0/node_modules/@remix-run/router'. This is likely not portable. A type annotation is necessary. +export const loader = async (arg: LoaderFunctionArgs): Promise => { const url = new URL(arg.request.url); const host = arg.request.headers.get("x-forwarded-host") || @@ -77,7 +78,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.status === 301 || pageMeta.status === 302 ? pageMeta.status : 302; - return redirect(pageMeta.redirect, status); + throw redirect(pageMeta.redirect, status); } // typecheck @@ -87,7 +88,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.excludePageFromSearch = arg.context.EXCLUDE_FROM_SEARCH; } - return json( + return data( { host, url: url.href, diff --git a/fixtures/webstudio-remix-vercel/app/routes/[expressions]._index.tsx b/fixtures/webstudio-remix-vercel/app/routes/[expressions]._index.tsx index 02e33f4e63b9..ccbb521ad626 100644 --- a/fixtures/webstudio-remix-vercel/app/routes/[expressions]._index.tsx +++ b/fixtures/webstudio-remix-vercel/app/routes/[expressions]._index.tsx @@ -5,7 +5,7 @@ import { type ActionFunctionArgs, type LoaderFunctionArgs, type HeadersFunction, - json, + data, redirect, } from "@remix-run/server-runtime"; import { useLoaderData } from "@remix-run/react"; @@ -50,7 +50,8 @@ const customFetch: typeof fetch = (input, init) => { return fetch(input, init); }; -export const loader = async (arg: LoaderFunctionArgs) => { +// have not idea how to win this error The inferred type of 'loader' cannot be named without a reference to '.pnpm/@remix-run+router@1.21.0/node_modules/@remix-run/router'. This is likely not portable. A type annotation is necessary. +export const loader = async (arg: LoaderFunctionArgs): Promise => { const url = new URL(arg.request.url); const host = arg.request.headers.get("x-forwarded-host") || @@ -77,7 +78,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.status === 301 || pageMeta.status === 302 ? pageMeta.status : 302; - return redirect(pageMeta.redirect, status); + throw redirect(pageMeta.redirect, status); } // typecheck @@ -87,7 +88,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.excludePageFromSearch = arg.context.EXCLUDE_FROM_SEARCH; } - return json( + return data( { host, url: url.href, diff --git a/fixtures/webstudio-remix-vercel/app/routes/[form]._index.tsx b/fixtures/webstudio-remix-vercel/app/routes/[form]._index.tsx index 6266caa9509c..34cd1643d5c8 100644 --- a/fixtures/webstudio-remix-vercel/app/routes/[form]._index.tsx +++ b/fixtures/webstudio-remix-vercel/app/routes/[form]._index.tsx @@ -5,7 +5,7 @@ import { type ActionFunctionArgs, type LoaderFunctionArgs, type HeadersFunction, - json, + data, redirect, } from "@remix-run/server-runtime"; import { useLoaderData } from "@remix-run/react"; @@ -50,7 +50,8 @@ const customFetch: typeof fetch = (input, init) => { return fetch(input, init); }; -export const loader = async (arg: LoaderFunctionArgs) => { +// have not idea how to win this error The inferred type of 'loader' cannot be named without a reference to '.pnpm/@remix-run+router@1.21.0/node_modules/@remix-run/router'. This is likely not portable. A type annotation is necessary. +export const loader = async (arg: LoaderFunctionArgs): Promise => { const url = new URL(arg.request.url); const host = arg.request.headers.get("x-forwarded-host") || @@ -77,7 +78,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.status === 301 || pageMeta.status === 302 ? pageMeta.status : 302; - return redirect(pageMeta.redirect, status); + throw redirect(pageMeta.redirect, status); } // typecheck @@ -87,7 +88,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.excludePageFromSearch = arg.context.EXCLUDE_FROM_SEARCH; } - return json( + return data( { host, url: url.href, diff --git a/fixtures/webstudio-remix-vercel/app/routes/[heading-with-id]._index.tsx b/fixtures/webstudio-remix-vercel/app/routes/[heading-with-id]._index.tsx index 540dbedd5748..381daf35e272 100644 --- a/fixtures/webstudio-remix-vercel/app/routes/[heading-with-id]._index.tsx +++ b/fixtures/webstudio-remix-vercel/app/routes/[heading-with-id]._index.tsx @@ -5,7 +5,7 @@ import { type ActionFunctionArgs, type LoaderFunctionArgs, type HeadersFunction, - json, + data, redirect, } from "@remix-run/server-runtime"; import { useLoaderData } from "@remix-run/react"; @@ -50,7 +50,8 @@ const customFetch: typeof fetch = (input, init) => { return fetch(input, init); }; -export const loader = async (arg: LoaderFunctionArgs) => { +// have not idea how to win this error The inferred type of 'loader' cannot be named without a reference to '.pnpm/@remix-run+router@1.21.0/node_modules/@remix-run/router'. This is likely not portable. A type annotation is necessary. +export const loader = async (arg: LoaderFunctionArgs): Promise => { const url = new URL(arg.request.url); const host = arg.request.headers.get("x-forwarded-host") || @@ -77,7 +78,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.status === 301 || pageMeta.status === 302 ? pageMeta.status : 302; - return redirect(pageMeta.redirect, status); + throw redirect(pageMeta.redirect, status); } // typecheck @@ -87,7 +88,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.excludePageFromSearch = arg.context.EXCLUDE_FROM_SEARCH; } - return json( + return data( { host, url: url.href, diff --git a/fixtures/webstudio-remix-vercel/app/routes/[nested].[nested-page]._index.tsx b/fixtures/webstudio-remix-vercel/app/routes/[nested].[nested-page]._index.tsx index a3bad0afa3b9..961825be19df 100644 --- a/fixtures/webstudio-remix-vercel/app/routes/[nested].[nested-page]._index.tsx +++ b/fixtures/webstudio-remix-vercel/app/routes/[nested].[nested-page]._index.tsx @@ -5,7 +5,7 @@ import { type ActionFunctionArgs, type LoaderFunctionArgs, type HeadersFunction, - json, + data, redirect, } from "@remix-run/server-runtime"; import { useLoaderData } from "@remix-run/react"; @@ -50,7 +50,8 @@ const customFetch: typeof fetch = (input, init) => { return fetch(input, init); }; -export const loader = async (arg: LoaderFunctionArgs) => { +// have not idea how to win this error The inferred type of 'loader' cannot be named without a reference to '.pnpm/@remix-run+router@1.21.0/node_modules/@remix-run/router'. This is likely not portable. A type annotation is necessary. +export const loader = async (arg: LoaderFunctionArgs): Promise => { const url = new URL(arg.request.url); const host = arg.request.headers.get("x-forwarded-host") || @@ -77,7 +78,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.status === 301 || pageMeta.status === 302 ? pageMeta.status : 302; - return redirect(pageMeta.redirect, status); + throw redirect(pageMeta.redirect, status); } // typecheck @@ -87,7 +88,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.excludePageFromSearch = arg.context.EXCLUDE_FROM_SEARCH; } - return json( + return data( { host, url: url.href, diff --git a/fixtures/webstudio-remix-vercel/app/routes/[radix]._index.tsx b/fixtures/webstudio-remix-vercel/app/routes/[radix]._index.tsx index 3ae44e0f5692..7b92ad1d2f41 100644 --- a/fixtures/webstudio-remix-vercel/app/routes/[radix]._index.tsx +++ b/fixtures/webstudio-remix-vercel/app/routes/[radix]._index.tsx @@ -5,7 +5,7 @@ import { type ActionFunctionArgs, type LoaderFunctionArgs, type HeadersFunction, - json, + data, redirect, } from "@remix-run/server-runtime"; import { useLoaderData } from "@remix-run/react"; @@ -50,7 +50,8 @@ const customFetch: typeof fetch = (input, init) => { return fetch(input, init); }; -export const loader = async (arg: LoaderFunctionArgs) => { +// have not idea how to win this error The inferred type of 'loader' cannot be named without a reference to '.pnpm/@remix-run+router@1.21.0/node_modules/@remix-run/router'. This is likely not portable. A type annotation is necessary. +export const loader = async (arg: LoaderFunctionArgs): Promise => { const url = new URL(arg.request.url); const host = arg.request.headers.get("x-forwarded-host") || @@ -77,7 +78,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.status === 301 || pageMeta.status === 302 ? pageMeta.status : 302; - return redirect(pageMeta.redirect, status); + throw redirect(pageMeta.redirect, status); } // typecheck @@ -87,7 +88,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.excludePageFromSearch = arg.context.EXCLUDE_FROM_SEARCH; } - return json( + return data( { host, url: url.href, diff --git a/fixtures/webstudio-remix-vercel/app/routes/[resources]._index.tsx b/fixtures/webstudio-remix-vercel/app/routes/[resources]._index.tsx index e65aa5103718..80946a2946cb 100644 --- a/fixtures/webstudio-remix-vercel/app/routes/[resources]._index.tsx +++ b/fixtures/webstudio-remix-vercel/app/routes/[resources]._index.tsx @@ -5,7 +5,7 @@ import { type ActionFunctionArgs, type LoaderFunctionArgs, type HeadersFunction, - json, + data, redirect, } from "@remix-run/server-runtime"; import { useLoaderData } from "@remix-run/react"; @@ -50,7 +50,8 @@ const customFetch: typeof fetch = (input, init) => { return fetch(input, init); }; -export const loader = async (arg: LoaderFunctionArgs) => { +// have not idea how to win this error The inferred type of 'loader' cannot be named without a reference to '.pnpm/@remix-run+router@1.21.0/node_modules/@remix-run/router'. This is likely not portable. A type annotation is necessary. +export const loader = async (arg: LoaderFunctionArgs): Promise => { const url = new URL(arg.request.url); const host = arg.request.headers.get("x-forwarded-host") || @@ -77,7 +78,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.status === 301 || pageMeta.status === 302 ? pageMeta.status : 302; - return redirect(pageMeta.redirect, status); + throw redirect(pageMeta.redirect, status); } // typecheck @@ -87,7 +88,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.excludePageFromSearch = arg.context.EXCLUDE_FROM_SEARCH; } - return json( + return data( { host, url: url.href, diff --git a/fixtures/webstudio-remix-vercel/app/routes/_index.tsx b/fixtures/webstudio-remix-vercel/app/routes/_index.tsx index 83e8ee2cfd3a..13669db847a3 100644 --- a/fixtures/webstudio-remix-vercel/app/routes/_index.tsx +++ b/fixtures/webstudio-remix-vercel/app/routes/_index.tsx @@ -5,7 +5,7 @@ import { type ActionFunctionArgs, type LoaderFunctionArgs, type HeadersFunction, - json, + data, redirect, } from "@remix-run/server-runtime"; import { useLoaderData } from "@remix-run/react"; @@ -50,7 +50,8 @@ const customFetch: typeof fetch = (input, init) => { return fetch(input, init); }; -export const loader = async (arg: LoaderFunctionArgs) => { +// have not idea how to win this error The inferred type of 'loader' cannot be named without a reference to '.pnpm/@remix-run+router@1.21.0/node_modules/@remix-run/router'. This is likely not portable. A type annotation is necessary. +export const loader = async (arg: LoaderFunctionArgs): Promise => { const url = new URL(arg.request.url); const host = arg.request.headers.get("x-forwarded-host") || @@ -77,7 +78,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.status === 301 || pageMeta.status === 302 ? pageMeta.status : 302; - return redirect(pageMeta.redirect, status); + throw redirect(pageMeta.redirect, status); } // typecheck @@ -87,7 +88,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.excludePageFromSearch = arg.context.EXCLUDE_FROM_SEARCH; } - return json( + return data( { host, url: url.href, diff --git a/fixtures/webstudio-remix-vercel/vite.config.ts b/fixtures/webstudio-remix-vercel/vite.config.ts index 137c08462414..1a68023ffd34 100644 --- a/fixtures/webstudio-remix-vercel/vite.config.ts +++ b/fixtures/webstudio-remix-vercel/vite.config.ts @@ -1,6 +1,22 @@ import { defineConfig } from "vite"; import { vitePlugin as remix } from "@remix-run/dev"; +declare module "@remix-run/server-runtime" { + interface Future { + v3_singleFetch: true; + } +} + export default defineConfig({ - plugins: [remix()], + plugins: [ + remix({ + future: { + v3_singleFetch: true, + v3_fetcherPersist: true, + v3_relativeSplatPath: true, + v3_throwAbortReason: true, + v3_lazyRouteDiscovery: true, + }, + }), + ], }); diff --git a/packages/cli/templates/cloudflare/vite.config.ts b/packages/cli/templates/cloudflare/vite.config.ts index 26a4f23dbca3..d5e4613a2d76 100644 --- a/packages/cli/templates/cloudflare/vite.config.ts +++ b/packages/cli/templates/cloudflare/vite.config.ts @@ -8,6 +8,14 @@ export default defineConfig(({ mode }) => ({ plugins: [ // without this, remixCloudflareDevProxy trying to load workerd even for production (it's not needed for production) mode === "production" ? undefined : remixCloudflareDevProxy(), - remix(), + remix({ + future: { + v3_singleFetch: true, + v3_fetcherPersist: true, + v3_relativeSplatPath: true, + v3_throwAbortReason: true, + v3_lazyRouteDiscovery: true, + }, + }), ].filter(Boolean), })); diff --git a/packages/cli/templates/defaults/app/route-templates/html.tsx b/packages/cli/templates/defaults/app/route-templates/html.tsx index 62a37df37bbd..b3555548769e 100644 --- a/packages/cli/templates/defaults/app/route-templates/html.tsx +++ b/packages/cli/templates/defaults/app/route-templates/html.tsx @@ -5,7 +5,7 @@ import { type ActionFunctionArgs, type LoaderFunctionArgs, type HeadersFunction, - json, + data, redirect, } from "@remix-run/server-runtime"; import { useLoaderData } from "@remix-run/react"; @@ -50,7 +50,8 @@ const customFetch: typeof fetch = (input, init) => { return fetch(input, init); }; -export const loader = async (arg: LoaderFunctionArgs) => { +// have not idea how to win this error The inferred type of 'loader' cannot be named without a reference to '.pnpm/@remix-run+router@1.21.0/node_modules/@remix-run/router'. This is likely not portable. A type annotation is necessary. +export const loader = async (arg: LoaderFunctionArgs): Promise => { const url = new URL(arg.request.url); const host = arg.request.headers.get("x-forwarded-host") || @@ -77,7 +78,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.status === 301 || pageMeta.status === 302 ? pageMeta.status : 302; - return redirect(pageMeta.redirect, status); + throw redirect(pageMeta.redirect, status); } // typecheck @@ -87,7 +88,7 @@ export const loader = async (arg: LoaderFunctionArgs) => { pageMeta.excludePageFromSearch = arg.context.EXCLUDE_FROM_SEARCH; } - return json( + return data( { host, url: url.href, diff --git a/packages/cli/templates/defaults/vite.config.ts b/packages/cli/templates/defaults/vite.config.ts index 137c08462414..1a68023ffd34 100644 --- a/packages/cli/templates/defaults/vite.config.ts +++ b/packages/cli/templates/defaults/vite.config.ts @@ -1,6 +1,22 @@ import { defineConfig } from "vite"; import { vitePlugin as remix } from "@remix-run/dev"; +declare module "@remix-run/server-runtime" { + interface Future { + v3_singleFetch: true; + } +} + export default defineConfig({ - plugins: [remix()], + plugins: [ + remix({ + future: { + v3_singleFetch: true, + v3_fetcherPersist: true, + v3_relativeSplatPath: true, + v3_throwAbortReason: true, + v3_lazyRouteDiscovery: true, + }, + }), + ], }); diff --git a/packages/cli/templates/netlify-edge-functions/vite.config.ts b/packages/cli/templates/netlify-edge-functions/vite.config.ts index a03b31397a26..05188ff819ca 100644 --- a/packages/cli/templates/netlify-edge-functions/vite.config.ts +++ b/packages/cli/templates/netlify-edge-functions/vite.config.ts @@ -3,5 +3,16 @@ import { defineConfig } from "vite"; import { netlifyPlugin } from "@netlify/remix-edge-adapter/plugin"; export default defineConfig({ - plugins: [remix(), netlifyPlugin()], + plugins: [ + remix({ + future: { + v3_singleFetch: true, + v3_fetcherPersist: true, + v3_relativeSplatPath: true, + v3_throwAbortReason: true, + v3_lazyRouteDiscovery: true, + }, + }), + netlifyPlugin(), + ], }); diff --git a/packages/cli/templates/netlify-functions/vite.config.ts b/packages/cli/templates/netlify-functions/vite.config.ts index 7bd01662c22c..0fd811806049 100644 --- a/packages/cli/templates/netlify-functions/vite.config.ts +++ b/packages/cli/templates/netlify-functions/vite.config.ts @@ -3,5 +3,16 @@ import { defineConfig } from "vite"; import { netlifyPlugin } from "@netlify/remix-adapter/plugin"; export default defineConfig({ - plugins: [remix(), netlifyPlugin()], + plugins: [ + remix({ + future: { + v3_singleFetch: true, + v3_fetcherPersist: true, + v3_relativeSplatPath: true, + v3_throwAbortReason: true, + v3_lazyRouteDiscovery: true, + }, + }), + netlifyPlugin(), + ], }); From 52f6258e5a162439534aeebcd46ef79a79845568 Mon Sep 17 00:00:00 2001 From: Bogdan Chadkin Date: Sun, 24 Nov 2024 12:00:07 +0700 Subject: [PATCH 2/4] Rebuild From 4e6996ce718616850e60523443ac97e8b0b7ff7b Mon Sep 17 00:00:00 2001 From: Bogdan Chadkin Date: Sun, 24 Nov 2024 15:18:54 +0700 Subject: [PATCH 3/4] log server data --- apps/builder/app/routes/_ui.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/builder/app/routes/_ui.tsx b/apps/builder/app/routes/_ui.tsx index e6eaad8bec83..1c31367814f6 100644 --- a/apps/builder/app/routes/_ui.tsx +++ b/apps/builder/app/routes/_ui.tsx @@ -77,6 +77,7 @@ export const clientLoader = async ({ serverLoader, }: ClientLoaderFunctionArgs) => { const serverData = await serverLoader(); + console.log(serverData); if (clientCsrfToken === undefined) { const { csrfToken } = serverData; From 5f1392cbccf62857de5c404ef924f0b921deab07 Mon Sep 17 00:00:00 2001 From: Bogdan Chadkin Date: Sun, 24 Nov 2024 15:24:30 +0700 Subject: [PATCH 4/4] Ignore null server data --- apps/builder/app/routes/_ui.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/builder/app/routes/_ui.tsx b/apps/builder/app/routes/_ui.tsx index 1c31367814f6..378742fbb631 100644 --- a/apps/builder/app/routes/_ui.tsx +++ b/apps/builder/app/routes/_ui.tsx @@ -77,7 +77,10 @@ export const clientLoader = async ({ serverLoader, }: ClientLoaderFunctionArgs) => { const serverData = await serverLoader(); - console.log(serverData); + // client loader is invoked twice with server data and with null + if (!serverData) { + return; + } if (clientCsrfToken === undefined) { const { csrfToken } = serverData;