New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@remix-run/react

Package Overview
Dependencies
Maintainers
2
Versions
1052
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@remix-run/react - npm Package Compare versions

Comparing version 2.10.3 to 2.11.0-pre.0

36

CHANGELOG.md
# `@remix-run/react`
## 2.11.0-pre.0
### Minor Changes
- Add a new `unstable_data()` API for usage with Remix Single Fetch ([#9769](https://github.com/remix-run/remix/pull/9769))
- Add a new `replace(url, init?)` alternative to `redirect(url, init?)` that performs a `history.replaceState` instead of a `history.pushState` on client-side navigation redirects ([#9764](https://github.com/remix-run/remix/pull/9764))
- Rename `future.unstable_fogOfWar` to `future.unstable_lazyRouteDiscovery` for clarity ([#9763](https://github.com/remix-run/remix/pull/9763))
- Single Fetch: Remove `responseStub` in favor of `headers` ([#9769](https://github.com/remix-run/remix/pull/9769))
- Background
- The original Single Fetch approach was based on an assumption that an eventual `middleware` implementation would require something like `ResponseStub` so users could mutate `status`/`headers` in `middleware` before/after handlers as well as during handlers
- We wanted to align how `headers` got merged between document and data requests
- So we made document requests also use `ResponseStub` and removed the usage of `headers` in Single Fetch
- The realization/alignment between Michael and Ryan on the recent [roadmap planning](https://www.youtube.com/watch?v=f5z_axCofW0) made us realize that the original assumption was incorrect
- `middleware` won't need a stub - users can just mutate the `Response` they get from `await next()` directly
- With that gone, and still wanting to align how `headers` get merged, it makes more sense to stick with the current `headers` API and apply that to Single Fetch and avoid introducing a totally new thing in `RepsonseStub` (that always felt a bit awkward to work with anyway)
- With this change:
- You are encouraged to stop returning `Response` instances in favor of returning raw data from loaders and actions:
- ~~`return json({ data: whatever });`~~
- `return { data: whatever };`
- In most cases, you can remove your `json()` and `defer()` calls in favor of returning raw data if they weren't setting custom `status`/`headers`
- We will be removing both `json` and `defer` in the next major version, but both _should_ still work in Single Fetch in v2 to allow for incremental adoption of the new behavior
- If you need custom `status`/`headers`:
- We've added a new `unstable_data({...}, responseInit)` utility that will let you send back `status`/`headers` alongside your raw data without having to encode it into a `Response`
- The `headers()` function will let you control header merging for both document and data requests
### Patch Changes
- Ensure single fetch calls don't include any trailing slash from the pathname (i.e., /path/.data) ([#9792](https://github.com/remix-run/remix/pull/9792))
- Single Fetch: Add `undefined` to the `useRouteLoaderData` type override ([#9796](https://github.com/remix-run/remix/pull/9796))
- Change initial hydration route mismatch from a URL check to a matches check to be resistant to URL inconsistencies ([#9695](https://github.com/remix-run/remix/pull/9695))
- Updated dependencies:
- `@remix-run/server-runtime@2.11.0-pre.0`
## 2.10.3

@@ -4,0 +40,0 @@

2

dist/_virtual/_rollupPluginBabelHelpers.js
/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

@@ -7,3 +7,3 @@ import type { HydrationState, Router } from "@remix-run/router";

var __remixContext: {
url: string;
ssrMatches: string[];
basename?: string;

@@ -10,0 +10,0 @@ state: HydrationState;

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -75,20 +75,2 @@ * Copyright (c) Remix Software Inc.

if (!router) {
// Hard reload if the path we tried to load is not the current path.
// This is usually the result of 2 rapid back/forward clicks from an
// external site into a Remix app, where we initially start the load for
// one URL and while the JS chunks are loading a second forward click moves
// us to a new URL. Avoid comparing search params because of CDNs which
// can be configured to ignore certain params and only pathname is relevant
// towards determining the route matches.
let initialPathname = window.__remixContext.url;
let hydratedPathname = window.location.pathname;
if (initialPathname !== hydratedPathname && !window.__remixContext.isSpaMode) {
let errorMsg = `Initial URL (${initialPathname}) does not match URL at time of hydration ` + `(${hydratedPathname}), reloading page...`;
console.error(errorMsg);
window.location.reload();
// Get out of here so the reload can happen - don't create the router
// since it'll then kick off unnecessary route.lazy() loads
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null);
}
// When single fetch is enabled, we need to suspend until the initial state

@@ -134,2 +116,24 @@ // snapshot is decoded into window.__remixContext.state

let initialMatches = reactRouterDom.matchRoutes(routes$1, window.location, window.__remixContext.basename);
// Hard reload if the matches we rendered on the server aren't the matches
// we matched in the client, otherwise we'll try to hydrate without the
// right modules and throw a hydration error, which can put React into an
// infinite hydration loop when hydrating the full `<html>` document.
// This is usually the result of 2 rapid back/forward clicks from an
// external site into a Remix app, where we initially start the load for
// one URL and while the JS chunks are loading a second forward click moves
// us to a new URL.
let ssrMatches = window.__remixContext.ssrMatches;
let hasDifferentSSRMatches = (initialMatches || []).length !== ssrMatches.length || !(initialMatches || []).every((m, i) => ssrMatches[i] === m.route.id);
if (hasDifferentSSRMatches && !window.__remixContext.isSpaMode) {
let ssr = ssrMatches.join(",");
let client = (initialMatches || []).map(m => m.route.id).join(",");
let errorMsg = `SSR Matches (${ssr}) do not match client matches (${client}) at ` + `time of hydration , reloading page...`;
console.error(errorMsg);
window.location.reload();
// Get out of here so the reload can happen - don't create the router
// since it'll then kick off unnecessary route.lazy() loads
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null);
}
if (initialMatches) {

@@ -136,0 +140,0 @@ for (let match of initialMatches) {

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

@@ -35,3 +35,3 @@ import type { StaticHandlerContext } from "@remix-run/router";

v3_relativeSplatPath: boolean;
unstable_fogOfWar: boolean;
unstable_lazyRouteDiscovery: boolean;
unstable_singleFetch: boolean;

@@ -38,0 +38,0 @@ }

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -115,20 +115,2 @@ * Copyright (c) Remix Software Inc.

if (!router) {
// Hard reload if the path we tried to load is not the current path.
// This is usually the result of 2 rapid back/forward clicks from an
// external site into a Remix app, where we initially start the load for
// one URL and while the JS chunks are loading a second forward click moves
// us to a new URL. Avoid comparing search params because of CDNs which
// can be configured to ignore certain params and only pathname is relevant
// towards determining the route matches.
let initialPathname = window.__remixContext.url;
let hydratedPathname = window.location.pathname;
if (initialPathname !== hydratedPathname && !window.__remixContext.isSpaMode) {
let errorMsg = `Initial URL (${initialPathname}) does not match URL at time of hydration ` + `(${hydratedPathname}), reloading page...`;
console.error(errorMsg);
window.location.reload();
// Get out of here so the reload can happen - don't create the router
// since it'll then kick off unnecessary route.lazy() loads
return /*#__PURE__*/React.createElement(React.Fragment, null);
}
// When single fetch is enabled, we need to suspend until the initial state

@@ -174,2 +156,24 @@ // snapshot is decoded into window.__remixContext.state

let initialMatches = matchRoutes(routes, window.location, window.__remixContext.basename);
// Hard reload if the matches we rendered on the server aren't the matches
// we matched in the client, otherwise we'll try to hydrate without the
// right modules and throw a hydration error, which can put React into an
// infinite hydration loop when hydrating the full `<html>` document.
// This is usually the result of 2 rapid back/forward clicks from an
// external site into a Remix app, where we initially start the load for
// one URL and while the JS chunks are loading a second forward click moves
// us to a new URL.
let ssrMatches = window.__remixContext.ssrMatches;
let hasDifferentSSRMatches = (initialMatches || []).length !== ssrMatches.length || !(initialMatches || []).every((m, i) => ssrMatches[i] === m.route.id);
if (hasDifferentSSRMatches && !window.__remixContext.isSpaMode) {
let ssr = ssrMatches.join(",");
let client = (initialMatches || []).map(m => m.route.id).join(",");
let errorMsg = `SSR Matches (${ssr}) do not match client matches (${client}) at ` + `time of hydration , reloading page...`;
console.error(errorMsg);
window.location.reload();
// Get out of here so the reload can happen - don't create the router
// since it'll then kick off unnecessary route.lazy() loads
return /*#__PURE__*/React.createElement(React.Fragment, null);
}
if (initialMatches) {

@@ -176,0 +180,0 @@ for (let match of initialMatches) {

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -20,3 +20,3 @@ * Copyright (c) Remix Software Inc.

function isFogOfWarEnabled(future, isSpaMode) {
return future.unstable_fogOfWar === true && !isSpaMode;
return future.unstable_lazyRouteDiscovery === true && !isSpaMode;
}

@@ -23,0 +23,0 @@ function getPartialManifest(manifest, router) {

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -12,3 +12,3 @@ * Copyright (c) Remix Software Inc.

export { Navigate, NavigationType, Outlet, Route, Routes, createPath, createRoutesFromChildren, createRoutesFromElements, createSearchParams, generatePath, isRouteErrorResponse, matchPath, matchRoutes, parsePath, renderMatches, resolvePath, unstable_usePrompt, unstable_useViewTransitionState, useAsyncError, useAsyncValue, useBeforeUnload, useBlocker, useFetchers, useFormAction, useHref, useInRouterContext, useLinkClickHandler, useLocation, useMatch, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useRoutes, useSearchParams, useSubmit } from 'react-router-dom';
export { defer, json, redirect, redirectDocument } from '@remix-run/server-runtime';
export { defer, json, redirect, redirectDocument, replace, unstable_data } from '@remix-run/server-runtime';
export { RemixBrowser } from './browser.js';

@@ -15,0 +15,0 @@ export { Await, Form, Link, Links, LiveReload, Meta, NavLink, PrefetchPageLinks, Scripts, RemixContext as UNSAFE_RemixContext, useActionData, useFetcher, useLoaderData, useMatches, useRouteLoaderData } from './components.js';

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -390,2 +390,6 @@ * Copyright (c) Remix Software Inc.

}
let replace = response.headers.get("X-Remix-Replace");
if (replace) {
headers["X-Remix-Replace"] = replace;
}
return redirect(url, {

@@ -392,0 +396,0 @@ status,

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -12,6 +12,6 @@ * Copyright (c) Remix Software Inc.

import * as React from 'react';
import { UNSAFE_ErrorResponseImpl, redirect } from '@remix-run/router';
import { UNSAFE_ErrorResponseImpl, isRouteErrorResponse, unstable_data, redirect } from '@remix-run/router';
import { UNSAFE_SingleFetchRedirectSymbol } from '@remix-run/server-runtime';
import { decode } from 'turbo-stream';
import { createRequestInit } from './data.js';
import { createRequestInit, isResponse } from './data.js';
import { escapeHtml } from './markup.js';

@@ -117,10 +117,14 @@ import invariant from './invariant.js';

type: "data",
result,
status: actionStatus
result
};
});
if (isResponse(result.result) || isRouteErrorResponse(result.result)) {
return result;
}
// For non-responses, proxy along the statusCode via unstable_data()
// (most notably for skipping action error revalidation)
return {
...result,
// Proxy along the action HTTP response status for thrown errors
status: actionStatus
type: result.type,
result: unstable_data(result.result, actionStatus)
};

@@ -223,3 +227,7 @@ }));

let url = typeof reqUrl === "string" ? new URL(reqUrl, window.location.origin) : reqUrl;
url.pathname = `${url.pathname === "/" ? "_root" : url.pathname}.data`;
if (url.pathname === "/") {
url.pathname = "_root.data";
} else {
url.pathname = `${url.pathname.replace(/\/$/, "")}.data`;
}
return url;

@@ -302,2 +310,5 @@ }

}
if (result.replace) {
headers["X-Remix-Replace"] = "yes";
}
return redirect(result.redirect, {

@@ -304,0 +315,0 @@ status: result.status,

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -44,3 +44,3 @@ * Copyright (c) Remix Software Inc.

function isFogOfWarEnabled(future, isSpaMode) {
return future.unstable_fogOfWar === true && !isSpaMode;
return future.unstable_lazyRouteDiscovery === true && !isSpaMode;
}

@@ -47,0 +47,0 @@ function getPartialManifest(manifest, router$1) {

export type { ErrorResponse, Fetcher, FetcherWithComponents, FormEncType, FormMethod, Location, NavigateFunction, Navigation, Params, Path, ShouldRevalidateFunction, ShouldRevalidateFunctionArgs, SubmitFunction, SubmitOptions, Blocker, BlockerFunction, } from "react-router-dom";
export { createPath, createRoutesFromChildren, createRoutesFromElements, createSearchParams, generatePath, matchPath, matchRoutes, parsePath, renderMatches, resolvePath, Navigate, NavigationType, Outlet, Route, Routes, useAsyncError, useAsyncValue, isRouteErrorResponse, useBeforeUnload, useFetchers, useFormAction, useHref, useInRouterContext, useLinkClickHandler, useLocation, useMatch, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useRoutes, useSearchParams, useSubmit, useBlocker, unstable_usePrompt, unstable_useViewTransitionState, } from "react-router-dom";
export { defer, json, redirect, redirectDocument, } from "@remix-run/server-runtime";
export { defer, json, redirect, redirectDocument, replace, unstable_data, } from "@remix-run/server-runtime";
export type { RemixBrowserProps } from "./browser";

@@ -5,0 +5,0 @@ export { RemixBrowser } from "./browser";

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -205,2 +205,10 @@ * Copyright (c) Remix Software Inc.

});
Object.defineProperty(exports, 'replace', {
enumerable: true,
get: function () { return serverRuntime.replace; }
});
Object.defineProperty(exports, 'unstable_data', {
enumerable: true,
get: function () { return serverRuntime.unstable_data; }
});
exports.RemixBrowser = browser.RemixBrowser;

@@ -207,0 +215,0 @@ exports.Await = components.Await;

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -414,2 +414,6 @@ * Copyright (c) Remix Software Inc.

}
let replace = response.headers.get("X-Remix-Replace");
if (replace) {
headers["X-Remix-Replace"] = replace;
}
return reactRouterDom.redirect(url, {

@@ -416,0 +420,0 @@ status,

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v2.10.3
* @remix-run/react v2.11.0-pre.0
*

@@ -140,10 +140,14 @@ * Copyright (c) Remix Software Inc.

type: "data",
result,
status: actionStatus
result
};
});
if (data.isResponse(result.result) || router.isRouteErrorResponse(result.result)) {
return result;
}
// For non-responses, proxy along the statusCode via unstable_data()
// (most notably for skipping action error revalidation)
return {
...result,
// Proxy along the action HTTP response status for thrown errors
status: actionStatus
type: result.type,
result: router.unstable_data(result.result, actionStatus)
};

@@ -246,3 +250,7 @@ }));

let url = typeof reqUrl === "string" ? new URL(reqUrl, window.location.origin) : reqUrl;
url.pathname = `${url.pathname === "/" ? "_root" : url.pathname}.data`;
if (url.pathname === "/") {
url.pathname = "_root.data";
} else {
url.pathname = `${url.pathname.replace(/\/$/, "")}.data`;
}
return url;

@@ -325,2 +333,5 @@ }

}
if (result.replace) {
headers["X-Remix-Replace"] = "yes";
}
return router.redirect(result.redirect, {

@@ -327,0 +338,0 @@ status: result.status,

@@ -29,3 +29,3 @@ import type {

routeId: string
): Serialize<T>;
): Serialize<T> | undefined;

@@ -32,0 +32,0 @@ export function useFetcher<T extends Loader | Action>(

{
"name": "@remix-run/react",
"version": "2.10.3",
"version": "2.11.0-pre.0",
"description": "React DOM bindings for Remix",

@@ -19,7 +19,7 @@ "bugs": {

"dependencies": {
"@remix-run/router": "1.18.0",
"react-router": "6.25.0",
"react-router-dom": "6.25.0",
"@remix-run/router": "1.19.0-pre.0",
"react-router": "6.26.0-pre.0",
"react-router-dom": "6.26.0-pre.0",
"turbo-stream": "2.2.0",
"@remix-run/server-runtime": "2.10.3"
"@remix-run/server-runtime": "2.11.0-pre.0"
},

@@ -34,4 +34,4 @@ "devDependencies": {

"typescript": "^5.1.6",
"@remix-run/node": "2.10.3",
"@remix-run/react": "2.10.3"
"@remix-run/node": "2.11.0-pre.0",
"@remix-run/react": "2.11.0-pre.0"
},

@@ -38,0 +38,0 @@ "peerDependencies": {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc