>
+
+ return (
+ <>
+ ServerComponent (unused)
+ Loader data: {"server" in loaderData ? loaderData.server : loaderData.client}
+ {actionData && Action data: {"server" in actionData ? actionData.server : actionData.client}
}
+ >
+ )
+ }
+
+ export function ErrorBoundary({
+ loaderData,
+ actionData
+ }: Route.ErrorBoundaryProps) {
+ type TestLoaderData = Expect>
+ type TestActionData = Expect>
+
+ return (
+ <>
+ ErrorBoundary
+ {loaderData && Loader data: {"server" in loaderData ? loaderData.server : loaderData.client}
}
+ {actionData && Action data: {"server" in actionData ? actionData.server : actionData.client}
}
+ >
+ )
+ }
+
+ export function HydrateFallback({
+ loaderData,
+ actionData
+ }: Route.HydrateFallbackProps) {
+ type TestLoaderData = Expect>
+ type TestActionData = Expect>
+
+ return (
+ <>
+ HydrateFallback
+ {loaderData && Loader data: {"server" in loaderData ? loaderData.server : loaderData.client}
}
+ {actionData && Action data: {"server" in actionData ? actionData.server : actionData.client}
}
+ >
+ )
+ }
+ `,
+ });
+ const proc = typecheck(cwd);
+ expect(proc.stdout.toString()).toBe("");
+ expect(proc.stderr.toString()).toBe("");
+ expect(proc.status).toBe(0);
+ });
+ });
+
+ test.describe("default export", async () => {
+ async function createClientFirstRouteProject({ rsc }: { rsc: boolean }) {
+ return await await createProject({
+ "vite.config.ts": viteConfig({ rsc }),
+ "app/expect-type.ts": expectType,
+ "app/routes.ts": tsx`
+ import { type RouteConfig, route } from "@react-router/dev/routes";
+
+ export default [
+ route("client-component/:id", "routes/client-component.tsx")
+ ] satisfies RouteConfig;
+ `,
+ "app/routes/client-component.tsx": tsx`
+ import type { Expect, Equal } from "../expect-type"
+ import type { Route } from "./+types/client-component"
+
+ export function loader({ params }: Route.LoaderArgs) {
+ type Test = Expect>
+ return { server: "server" }
+ }
+
+ export function clientLoader() {
+ return { client: "client" }
+ }
+
+ export function action() {
+ return { server: "server" }
+ }
+
+ export function clientAction() {
+ return { client: "client" }
+ }
+
+ export default function ClientComponent({
+ loaderData,
+ actionData
+ }: Route.ComponentProps) {
+ type TestLoaderData = Expect>
+ type TestActionData = Expect>
+
+ return (
+ <>
+ default (Component)
+ Loader data: {"server" in loaderData ? loaderData.server : loaderData.client}
+ {actionData && Action data: {"server" in actionData ? actionData.server : actionData.client}
}
+ >
+ )
+ }
+
+ export function ErrorBoundary({
+ loaderData,
+ actionData
+ }: Route.ErrorBoundaryProps) {
+ type TestLoaderData = Expect>
+ type TestActionData = Expect>
+
+ return (
+ <>
+ ErrorBoundary
+ {loaderData && Loader data: {"server" in loaderData ? loaderData.server : loaderData.client}
}
+ {actionData && Action data: {"server" in actionData ? actionData.server : actionData.client}
}
+ >
+ )
+ }
+
+ export function HydrateFallback({
+ loaderData,
+ actionData
+ }: Route.HydrateFallbackProps) {
+ type TestLoaderData = Expect>
+ type TestActionData = Expect>
+
+ return (
+ <>
+ HydrateFallback
+ {loaderData && Loader data: {"server" in loaderData ? loaderData.server : loaderData.client}
}
+ {actionData && Action data: {"server" in actionData ? actionData.server : actionData.client}
}
+ >
+ )
+ }
+ `,
+ });
+ }
+
+ test("when RSC Framework Mode plugin is present", async () => {
+ const cwd = await createClientFirstRouteProject({ rsc: true });
+ const proc = typecheck(cwd);
+ expect(proc.stdout.toString()).toBe("");
+ expect(proc.stderr.toString()).toBe("");
+ expect(proc.status).toBe(0);
+ });
+
+ test("when RSC Framework Mode plugin is not present", async () => {
+ const cwd = await createClientFirstRouteProject({ rsc: false });
+ const proc = typecheck(cwd);
+ expect(proc.stdout.toString()).toBe("");
+ expect(proc.stderr.toString()).toBe("");
+ expect(proc.status).toBe(0);
+ });
+ });
+ });
+
test("custom app dir", async () => {
const cwd = await createProject({
- "vite.config.ts": viteConfig,
+ "vite.config.ts": viteConfig(),
"react-router.config.ts": tsx`
export default {
appDirectory: "src/myapp",
@@ -391,7 +682,7 @@ test.describe("typegen", () => {
test("matches", async () => {
const cwd = await createProject({
- "vite.config.ts": viteConfig,
+ "vite.config.ts": viteConfig(),
"app/expect-type.ts": expectType,
"app/routes.ts": tsx`
import { type RouteConfig, route } from "@react-router/dev/routes";
@@ -488,7 +779,7 @@ test.describe("typegen", () => {
test("route files with absolute paths", async () => {
const cwd = await createProject({
- "vite.config.ts": viteConfig,
+ "vite.config.ts": viteConfig(),
"app/expect-type.ts": expectType,
"app/routes.ts": tsx`
import path from "node:path";
@@ -522,7 +813,7 @@ test.describe("typegen", () => {
test("href", async () => {
const cwd = await createProject({
- "vite.config.ts": viteConfig,
+ "vite.config.ts": viteConfig(),
"app/expect-type.ts": expectType,
"app/routes.ts": tsx`
import path from "node:path";
@@ -592,7 +883,7 @@ test.describe("typegen", () => {
test.describe("virtual:react-router/server-build", async () => {
test("static import matches 'createRequestHandler' argument type", async () => {
const cwd = await createProject({
- "vite.config.ts": viteConfig,
+ "vite.config.ts": viteConfig(),
"app/routes.ts": tsx`
import { type RouteConfig } from "@react-router/dev/routes";
export default [] satisfies RouteConfig;
@@ -612,7 +903,7 @@ test.describe("typegen", () => {
test("works with tsconfig 'moduleDetection' set to 'force'", async () => {
const cwd = await createProject({
- "vite.config.ts": viteConfig,
+ "vite.config.ts": viteConfig(),
"app/routes.ts": tsx`
import { type RouteConfig } from "@react-router/dev/routes";
export default [] satisfies RouteConfig;
@@ -642,7 +933,7 @@ test.describe("typegen", () => {
test("dynamic import matches 'createRequestHandler' function argument type", async () => {
const cwd = await createProject({
- "vite.config.ts": viteConfig,
+ "vite.config.ts": viteConfig(),
"app/routes.ts": tsx`
import { type RouteConfig } from "@react-router/dev/routes";
export default [] satisfies RouteConfig;
@@ -664,7 +955,7 @@ test.describe("typegen", () => {
test("reuse route file at multiple paths", async () => {
const cwd = await createProject({
- "vite.config.ts": viteConfig,
+ "vite.config.ts": viteConfig(),
"app/expect-type.ts": expectType,
"app/routes.ts": tsx`
import { type RouteConfig, route } from "@react-router/dev/routes";
diff --git a/integration/vite-dotenv-test.ts b/integration/vite-dotenv-test.ts
index 4c70dcbee9..c9faf7ad54 100644
--- a/integration/vite-dotenv-test.ts
+++ b/integration/vite-dotenv-test.ts
@@ -2,18 +2,32 @@ import { test, expect } from "@playwright/test";
import getPort from "get-port";
import {
+ type TemplateName,
createProject,
customDev,
EXPRESS_SERVER,
viteConfig,
} from "./helpers/vite.js";
-let getFiles = async ({ envDir, port }: { envDir?: string; port: number }) => {
+const templateNames = [
+ "vite-5-template",
+ "rsc-vite-framework",
+] as const satisfies TemplateName[];
+
+let getFiles = async ({
+ templateName,
+ envDir,
+ port,
+}: {
+ templateName: TemplateName;
+ envDir?: string;
+ port: number;
+}) => {
let envPath = `${envDir ? `${envDir}/` : ""}.env`;
return {
- "vite.config.js": await viteConfig.basic({ port, envDir }),
- "server.mjs": EXPRESS_SERVER({ port }),
+ "vite.config.js": await viteConfig.basic({ templateName, port, envDir }),
+ "server.mjs": EXPRESS_SERVER({ port, templateName }),
[envPath]: `
ENV_VAR_FROM_DOTENV_FILE=Content from ${envPath} file
`,
@@ -49,72 +63,90 @@ let getFiles = async ({ envDir, port }: { envDir?: string; port: number }) => {
};
test.describe("Vite .env", () => {
- test.describe("defaults", async () => {
- let port: number;
- let cwd: string;
- let stop: () => void;
-
- test.beforeAll(async () => {
- port = await getPort();
- cwd = await createProject(await getFiles({ port }));
- stop = await customDev({ cwd, port });
- });
- test.afterAll(() => stop());
-
- test("express", async ({ page }) => {
- let pageErrors: unknown[] = [];
- page.on("pageerror", (error) => pageErrors.push(error));
-
- await page.goto(`http://localhost:${port}/dotenv`, {
- waitUntil: "networkidle",
+ for (const templateName of templateNames) {
+ test.describe(`template: ${templateName}`, () => {
+ test.describe("defaults", async () => {
+ let port: number;
+ let cwd: string;
+ let stop: () => void;
+
+ test.beforeAll(async () => {
+ port = await getPort();
+ cwd = await createProject(
+ await getFiles({ port, templateName }),
+ templateName,
+ );
+ stop = await customDev({ cwd, port });
+ });
+ test.afterAll(() => stop());
+
+ test("express", async ({ page }) => {
+ let pageErrors: unknown[] = [];
+ page.on("pageerror", (error) => pageErrors.push(error));
+
+ await page.goto(`http://localhost:${port}/dotenv`, {
+ waitUntil: "networkidle",
+ });
+ expect(pageErrors).toEqual([]);
+
+ let loaderContent = page.locator(
+ "[data-dotenv-route-loader-content]",
+ );
+ await expect(loaderContent).toHaveText("Content from .env file");
+
+ let clientContent = page.locator(
+ "[data-dotenv-route-client-content]",
+ );
+ await expect(clientContent).toHaveText(
+ "process.env.ENV_VAR_FROM_DOTENV_FILE not available on the client, which is a good thing",
+ );
+
+ expect(pageErrors).toEqual([]);
+ });
});
- expect(pageErrors).toEqual([]);
-
- let loaderContent = page.locator("[data-dotenv-route-loader-content]");
- await expect(loaderContent).toHaveText("Content from .env file");
-
- let clientContent = page.locator("[data-dotenv-route-client-content]");
- await expect(clientContent).toHaveText(
- "process.env.ENV_VAR_FROM_DOTENV_FILE not available on the client, which is a good thing",
- );
-
- expect(pageErrors).toEqual([]);
- });
- });
-
- test.describe("custom env dir", async () => {
- let port: number;
- let cwd: string;
- let stop: () => void;
-
- test.beforeAll(async () => {
- const envDir = "custom-env-dir";
- port = await getPort();
- cwd = await createProject(await getFiles({ envDir, port }));
- stop = await customDev({ cwd, port });
- });
- test.afterAll(() => stop());
-
- test("express", async ({ page }) => {
- let pageErrors: unknown[] = [];
- page.on("pageerror", (error) => pageErrors.push(error));
- await page.goto(`http://localhost:${port}/dotenv`, {
- waitUntil: "networkidle",
+ test.describe("custom env dir", async () => {
+ let port: number;
+ let cwd: string;
+ let stop: () => void;
+
+ test.beforeAll(async () => {
+ const envDir = "custom-env-dir";
+ port = await getPort();
+ cwd = await createProject(
+ await getFiles({ envDir, port, templateName }),
+ templateName,
+ );
+ stop = await customDev({ cwd, port });
+ });
+ test.afterAll(() => stop());
+
+ test("express", async ({ page }) => {
+ let pageErrors: unknown[] = [];
+ page.on("pageerror", (error) => pageErrors.push(error));
+
+ await page.goto(`http://localhost:${port}/dotenv`, {
+ waitUntil: "networkidle",
+ });
+ expect(pageErrors).toEqual([]);
+
+ let loaderContent = page.locator(
+ "[data-dotenv-route-loader-content]",
+ );
+ await expect(loaderContent).toHaveText(
+ "Content from custom-env-dir/.env file",
+ );
+
+ let clientContent = page.locator(
+ "[data-dotenv-route-client-content]",
+ );
+ await expect(clientContent).toHaveText(
+ "process.env.ENV_VAR_FROM_DOTENV_FILE not available on the client, which is a good thing",
+ );
+
+ expect(pageErrors).toEqual([]);
+ });
});
- expect(pageErrors).toEqual([]);
-
- let loaderContent = page.locator("[data-dotenv-route-loader-content]");
- await expect(loaderContent).toHaveText(
- "Content from custom-env-dir/.env file",
- );
-
- let clientContent = page.locator("[data-dotenv-route-client-content]");
- await expect(clientContent).toHaveText(
- "process.env.ENV_VAR_FROM_DOTENV_FILE not available on the client, which is a good thing",
- );
-
- expect(pageErrors).toEqual([]);
});
- });
+ }
});
diff --git a/packages/create-react-router/CHANGELOG.md b/packages/create-react-router/CHANGELOG.md
index 7eff0ca5d5..3389ec3b20 100644
--- a/packages/create-react-router/CHANGELOG.md
+++ b/packages/create-react-router/CHANGELOG.md
@@ -1,5 +1,9 @@
# `create-react-router`
+## 7.9.1
+
+_No changes_
+
## 7.9.0
_No changes_
diff --git a/packages/create-react-router/package.json b/packages/create-react-router/package.json
index 8c9a1349ab..757459ba8a 100644
--- a/packages/create-react-router/package.json
+++ b/packages/create-react-router/package.json
@@ -1,6 +1,6 @@
{
"name": "create-react-router",
- "version": "7.9.0",
+ "version": "7.9.1",
"description": "Create a new React Router app",
"homepage": "https://reactrouter.com/",
"bugs": {
diff --git a/packages/react-router-architect/CHANGELOG.md b/packages/react-router-architect/CHANGELOG.md
index f3697f945b..c24b6ee0cb 100644
--- a/packages/react-router-architect/CHANGELOG.md
+++ b/packages/react-router-architect/CHANGELOG.md
@@ -1,5 +1,13 @@
# `@react-router/architect`
+## 7.9.1
+
+### Patch Changes
+
+- Updated dependencies:
+ - `react-router@7.9.1`
+ - `@react-router/node@7.9.1`
+
## 7.9.0
### Minor Changes
diff --git a/packages/react-router-architect/package.json b/packages/react-router-architect/package.json
index 33656d777d..2fff134271 100644
--- a/packages/react-router-architect/package.json
+++ b/packages/react-router-architect/package.json
@@ -1,6 +1,6 @@
{
"name": "@react-router/architect",
- "version": "7.9.0",
+ "version": "7.9.1",
"description": "Architect server request handler for React Router",
"bugs": {
"url": "https://github.com/remix-run/react-router/issues"
diff --git a/packages/react-router-cloudflare/CHANGELOG.md b/packages/react-router-cloudflare/CHANGELOG.md
index 548ac9d80c..1df5d8f4e8 100644
--- a/packages/react-router-cloudflare/CHANGELOG.md
+++ b/packages/react-router-cloudflare/CHANGELOG.md
@@ -1,5 +1,12 @@
# `@react-router/cloudflare`
+## 7.9.1
+
+### Patch Changes
+
+- Updated dependencies:
+ - `react-router@7.9.1`
+
## 7.9.0
### Minor Changes
diff --git a/packages/react-router-cloudflare/package.json b/packages/react-router-cloudflare/package.json
index 287872d694..e7aa699130 100644
--- a/packages/react-router-cloudflare/package.json
+++ b/packages/react-router-cloudflare/package.json
@@ -1,6 +1,6 @@
{
"name": "@react-router/cloudflare",
- "version": "7.9.0",
+ "version": "7.9.1",
"description": "Cloudflare platform abstractions for React Router",
"bugs": {
"url": "https://github.com/remix-run/react-router/issues"
diff --git a/packages/react-router-dev/CHANGELOG.md b/packages/react-router-dev/CHANGELOG.md
index 47d3aa31a9..96589802c0 100644
--- a/packages/react-router-dev/CHANGELOG.md
+++ b/packages/react-router-dev/CHANGELOG.md
@@ -1,5 +1,15 @@
# `@react-router/dev`
+## 7.9.1
+
+### Patch Changes
+
+- Fix internal `Future` interface naming from `middleware` -> `v8_middleware` ([#14327](https://github.com/remix-run/react-router/pull/14327))
+- Updated dependencies:
+ - `react-router@7.9.1`
+ - `@react-router/node@7.9.1`
+ - `@react-router/serve@7.9.1`
+
## 7.9.0
### Minor Changes
diff --git a/packages/react-router-dev/cli/commands.ts b/packages/react-router-dev/cli/commands.ts
index 04d338754b..90b900ddcf 100644
--- a/packages/react-router-dev/cli/commands.ts
+++ b/packages/react-router-dev/cli/commands.ts
@@ -247,6 +247,14 @@ export async function typegen(
) {
root = resolveRootDirectory(root, flags);
+ const rsc = await hasReactRouterRscPlugin({
+ root,
+ viteBuildOptions: {
+ config: flags.config,
+ mode: flags.mode,
+ },
+ });
+
if (flags.watch) {
await preloadVite();
const vite = getVite();
@@ -254,6 +262,7 @@ export async function typegen(
await Typegen.watch(root, {
mode: flags.mode ?? "development",
+ rsc,
logger,
});
await new Promise(() => {}); // keep alive
@@ -262,5 +271,6 @@ export async function typegen(
await Typegen.run(root, {
mode: flags.mode ?? "production",
+ rsc,
});
}
diff --git a/packages/react-router-dev/config/config.ts b/packages/react-router-dev/config/config.ts
index 68ef25cb12..c0d92b2714 100644
--- a/packages/react-router-dev/config/config.ts
+++ b/packages/react-router-dev/config/config.ts
@@ -345,6 +345,8 @@ type Result =
error: string;
};
+type ConfigResult = Result;
+
function ok(value: T): Result {
return { ok: true, value };
}
@@ -365,7 +367,7 @@ async function resolveConfig({
reactRouterConfigFile?: string;
skipRoutes?: boolean;
validateConfig?: ValidateConfigFunction;
-}): Promise> {
+}): Promise {
let reactRouterUserConfig: ReactRouterConfig = {};
if (reactRouterConfigFile) {
@@ -506,7 +508,7 @@ async function resolveConfig({
let appDirectory = Path.resolve(root, userAppDirectory || "app");
let buildDirectory = Path.resolve(root, userBuildDirectory);
- let rootRouteFile = findEntry(appDirectory, "root");
+ let rootRouteFile = findEntry(appDirectory, "root", { absolute: true });
if (!rootRouteFile) {
let rootRouteDisplayPath = Path.relative(
root,
@@ -556,7 +558,7 @@ async function resolveConfig({
{
id: "root",
path: "",
- file: rootRouteFile,
+ file: Path.relative(appDirectory, rootRouteFile),
children: result.routeConfig,
},
];
@@ -622,7 +624,7 @@ async function resolveConfig({
type ChokidarEventName = ChokidarEmitArgs[0];
type ChangeHandler = (args: {
- result: Result;
+ result: ConfigResult;
configCodeChanged: boolean;
routeConfigCodeChanged: boolean;
configChanged: boolean;
@@ -632,7 +634,7 @@ type ChangeHandler = (args: {
}) => void;
export type ConfigLoader = {
- getConfig: () => Promise>;
+ getConfig: () => Promise;
onChange: (handler: ChangeHandler) => () => void;
close: () => Promise;
};
diff --git a/packages/react-router-dev/package.json b/packages/react-router-dev/package.json
index 361fe17038..35540a8efa 100644
--- a/packages/react-router-dev/package.json
+++ b/packages/react-router-dev/package.json
@@ -1,6 +1,6 @@
{
"name": "@react-router/dev",
- "version": "7.9.0",
+ "version": "7.9.1",
"description": "Dev tools and CLI for React Router",
"homepage": "https://reactrouter.com/",
"bugs": {
diff --git a/packages/react-router-dev/typegen/context.ts b/packages/react-router-dev/typegen/context.ts
index 31909eb92f..efad1e28dc 100644
--- a/packages/react-router-dev/typegen/context.ts
+++ b/packages/react-router-dev/typegen/context.ts
@@ -8,16 +8,19 @@ export type Context = {
rootDirectory: string;
configLoader: ConfigLoader;
config: ResolvedReactRouterConfig;
+ rsc: boolean;
};
export async function createContext({
rootDirectory,
watch,
mode,
+ rsc,
}: {
rootDirectory: string;
watch: boolean;
mode: string;
+ rsc: boolean;
}): Promise {
const configLoader = await createConfigLoader({ rootDirectory, mode, watch });
const configResult = await configLoader.getConfig();
@@ -32,5 +35,6 @@ export async function createContext({
configLoader,
rootDirectory,
config,
+ rsc,
};
}
diff --git a/packages/react-router-dev/typegen/generate.ts b/packages/react-router-dev/typegen/generate.ts
index 6bb3742db3..74df004ee6 100644
--- a/packages/react-router-dev/typegen/generate.ts
+++ b/packages/react-router-dev/typegen/generate.ts
@@ -23,7 +23,7 @@ export function generateFuture(ctx: Context): VirtualFile {
declare module "react-router" {
interface Future {
- middleware: ${ctx.config.future.v8_middleware}
+ v8_middleware: ${ctx.config.future.v8_middleware}
}
}
`;
@@ -274,7 +274,7 @@ function getRouteAnnotations({
Babel.generate(matchesType).code +
"\n\n" +
ts`
- type Annotations = GetAnnotations;
+ type Annotations = GetAnnotations;
export namespace Route {
// links
diff --git a/packages/react-router-dev/typegen/index.ts b/packages/react-router-dev/typegen/index.ts
index d8cd731454..32ff56292b 100644
--- a/packages/react-router-dev/typegen/index.ts
+++ b/packages/react-router-dev/typegen/index.ts
@@ -29,8 +29,11 @@ async function write(...files: Array) {
);
}
-export async function run(rootDirectory: string, { mode }: { mode: string }) {
- const ctx = await createContext({ rootDirectory, mode, watch: false });
+export async function run(
+ rootDirectory: string,
+ { mode, rsc }: { mode: string; rsc: boolean },
+) {
+ const ctx = await createContext({ rootDirectory, mode, rsc, watch: false });
await fs.rm(typesDirectory(ctx), { recursive: true, force: true });
await write(
generateFuture(ctx),
@@ -45,9 +48,9 @@ export type Watcher = {
export async function watch(
rootDirectory: string,
- { mode, logger }: { mode: string; logger?: vite.Logger },
+ { mode, logger, rsc }: { mode: string; logger?: vite.Logger; rsc: boolean },
): Promise {
- const ctx = await createContext({ rootDirectory, mode, watch: true });
+ const ctx = await createContext({ rootDirectory, mode, rsc, watch: true });
await fs.rm(typesDirectory(ctx), { recursive: true, force: true });
await write(
generateFuture(ctx),
diff --git a/packages/react-router-dev/vite/load-dotenv.ts b/packages/react-router-dev/vite/load-dotenv.ts
new file mode 100644
index 0000000000..ddde2c6bc0
--- /dev/null
+++ b/packages/react-router-dev/vite/load-dotenv.ts
@@ -0,0 +1,24 @@
+import type * as Vite from "vite";
+
+export async function loadDotenv({
+ rootDirectory,
+ viteUserConfig,
+ mode,
+}: {
+ rootDirectory: string;
+ viteUserConfig: Vite.UserConfig;
+ mode: string;
+}) {
+ const vite = await import("vite");
+ Object.assign(
+ process.env,
+ vite.loadEnv(
+ mode,
+ viteUserConfig.envDir ?? rootDirectory,
+ // We override the default prefix of "VITE_" with a blank string since
+ // we're targeting the server, so we want to load all environment
+ // variables, not just those explicitly marked for the client
+ "",
+ ),
+ );
+}
diff --git a/packages/react-router-dev/vite/plugin.ts b/packages/react-router-dev/vite/plugin.ts
index bda01f6c4c..4f86b5b3f3 100644
--- a/packages/react-router-dev/vite/plugin.ts
+++ b/packages/react-router-dev/vite/plugin.ts
@@ -81,6 +81,7 @@ import {
} from "../config/config";
import { getOptimizeDepsEntries } from "./optimize-deps-entries";
import { decorateComponentExportsWithProps } from "./with-props";
+import { loadDotenv } from "./load-dotenv";
import { validatePluginOrder } from "./plugins/validate-plugin-order";
import { warnOnClientSourceMaps } from "./plugins/warn-on-client-source-maps";
@@ -1197,6 +1198,7 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => {
if (viteCommand === "serve") {
typegenWatcherPromise = Typegen.watch(rootDirectory, {
mode,
+ rsc: false,
// ignore `info` logs from typegen since they are redundant when Vite plugin logs are active
logger: vite.createLogger("warn", { prefix: "[react-router]" }),
});
@@ -1210,17 +1212,11 @@ export const reactRouterVitePlugin: ReactRouterVitePlugin = () => {
await updatePluginContext();
- Object.assign(
- process.env,
- vite.loadEnv(
- viteConfigEnv.mode,
- viteUserConfig.envDir ?? ctx.rootDirectory,
- // We override the default prefix of "VITE_" with a blank string since
- // we're targeting the server, so we want to load all environment
- // variables, not just those explicitly marked for the client
- "",
- ),
- );
+ await loadDotenv({
+ rootDirectory,
+ viteUserConfig,
+ mode,
+ });
let environments = await getEnvironmentsOptions(ctx, viteCommand, {
viteUserConfig,
diff --git a/packages/react-router-dev/vite/rsc/plugin.ts b/packages/react-router-dev/vite/rsc/plugin.ts
index 4cc139f281..79777bf1a9 100644
--- a/packages/react-router-dev/vite/rsc/plugin.ts
+++ b/packages/react-router-dev/vite/rsc/plugin.ts
@@ -1,5 +1,6 @@
import type * as Vite from "vite";
import { init as initEsModuleLexer } from "es-module-lexer";
+import * as Path from "pathe";
import * as babel from "@babel/core";
import colors from "picocolors";
@@ -23,12 +24,12 @@ import {
isVirtualClientRouteModuleId,
CLIENT_NON_COMPONENT_EXPORTS,
} from "./virtual-route-modules";
+import { loadDotenv } from "../load-dotenv";
import { validatePluginOrder } from "../plugins/validate-plugin-order";
import { warnOnClientSourceMaps } from "../plugins/warn-on-client-source-maps";
export function reactRouterRSCVitePlugin(): Vite.PluginOption[] {
let configLoader: ConfigLoader;
- let config: ResolvedReactRouterConfig;
let typegenWatcherPromise: Promise | undefined;
let viteCommand: Vite.ConfigEnv["command"];
let routeIdByFile: Map | undefined;
@@ -36,6 +37,16 @@ export function reactRouterRSCVitePlugin(): Vite.PluginOption[] {
const defaultEntries = getDefaultEntries();
+ let config: ResolvedReactRouterConfig;
+ let rootRouteFile: string;
+ function updateConfig(newConfig: ResolvedReactRouterConfig) {
+ config = newConfig;
+ rootRouteFile = Path.resolve(
+ newConfig.appDirectory,
+ newConfig.routes.root.file,
+ );
+ }
+
return [
{
name: "react-router/rsc",
@@ -75,7 +86,7 @@ export function reactRouterRSCVitePlugin(): Vite.PluginOption[] {
const configResult = await configLoader.getConfig();
if (!configResult.ok) throw new Error(configResult.error);
- config = configResult.value;
+ updateConfig(configResult.value);
if (
viteUserConfig.base &&
@@ -91,6 +102,12 @@ export function reactRouterRSCVitePlugin(): Vite.PluginOption[] {
);
}
+ await loadDotenv({
+ rootDirectory,
+ viteUserConfig,
+ mode,
+ });
+
const vite = await import("vite");
logger = vite.createLogger(viteUserConfig.logLevel, {
prefix: "[react-router]",
@@ -246,7 +263,7 @@ export function reactRouterRSCVitePlugin(): Vite.PluginOption[] {
});
// Update shared plugin config reference
- config = result.value;
+ updateConfig(result.value);
if (configChanged || routeConfigChanged) {
invalidateVirtualModules(viteDevServer);
@@ -267,6 +284,7 @@ export function reactRouterRSCVitePlugin(): Vite.PluginOption[] {
getRootDirectory(viteUserConfig),
{
mode,
+ rsc: true,
// ignore `info` logs from typegen since they are
// redundant when Vite plugin logs are active
logger: vite.createLogger("warn", {
@@ -314,6 +332,7 @@ export function reactRouterRSCVitePlugin(): Vite.PluginOption[] {
id,
viteCommand,
routeIdByFile,
+ rootRouteFile,
viteEnvironment: this.environment,
});
},
diff --git a/packages/react-router-dev/vite/rsc/virtual-route-config.ts b/packages/react-router-dev/vite/rsc/virtual-route-config.ts
index a9a4352b4a..1edddcb042 100644
--- a/packages/react-router-dev/vite/rsc/virtual-route-config.ts
+++ b/packages/react-router-dev/vite/rsc/virtual-route-config.ts
@@ -28,7 +28,7 @@ export function createVirtualRouteConfig({
const routeId = route.id || createRouteId(route.file, appDirectory);
routeIdByFile.set(routeFile, routeId);
code += `lazy: () => import(${JSON.stringify(
- `${routeFile}?route-module${routeId === "root" ? "&root-route=true" : ""}`,
+ `${routeFile}?route-module`,
)}),`;
code += `id: ${JSON.stringify(routeId)},`;
diff --git a/packages/react-router-dev/vite/rsc/virtual-route-modules.ts b/packages/react-router-dev/vite/rsc/virtual-route-modules.ts
index 0dc93141ff..5c5cdea04e 100644
--- a/packages/react-router-dev/vite/rsc/virtual-route-modules.ts
+++ b/packages/react-router-dev/vite/rsc/virtual-route-modules.ts
@@ -97,40 +97,54 @@ export function transformVirtualRouteModules({
code,
viteCommand,
routeIdByFile,
+ rootRouteFile,
viteEnvironment,
}: {
id: string;
code: string;
viteCommand: ViteCommand;
routeIdByFile: Map;
+ rootRouteFile: string;
viteEnvironment: Vite.Environment;
}) {
if (isVirtualRouteModuleId(id) || routeIdByFile.has(id)) {
return createVirtualRouteModuleCode({
id,
code,
+ rootRouteFile,
viteCommand,
viteEnvironment,
});
}
if (isVirtualServerRouteModuleId(id)) {
- return createVirtualServerRouteModuleCode({ id, code, viteEnvironment });
+ return createVirtualServerRouteModuleCode({
+ id,
+ code,
+ viteEnvironment,
+ });
}
if (isVirtualClientRouteModuleId(id)) {
- return createVirtualClientRouteModuleCode({ id, code, viteCommand });
+ return createVirtualClientRouteModuleCode({
+ id,
+ code,
+ rootRouteFile,
+ viteCommand,
+ });
}
}
async function createVirtualRouteModuleCode({
id,
code: routeSource,
+ rootRouteFile,
viteCommand,
viteEnvironment,
}: {
id: string;
code: string;
+ rootRouteFile: string;
viteCommand: ViteCommand;
viteEnvironment: Vite.Environment;
}) {
@@ -183,7 +197,10 @@ async function createVirtualRouteModuleCode({
}
}
- if (isRootRouteId(id) && !staticExports.includes("ErrorBoundary")) {
+ if (
+ isRootRouteFile({ id, rootRouteFile }) &&
+ !staticExports.includes("ErrorBoundary")
+ ) {
code += `export { ErrorBoundary } from "${clientModuleId}";\n`;
}
@@ -236,10 +253,12 @@ function createVirtualServerRouteModuleCode({
function createVirtualClientRouteModuleCode({
id,
code: routeSource,
+ rootRouteFile,
viteCommand,
}: {
id: string;
code: string;
+ rootRouteFile: string;
viteCommand: ViteCommand;
}) {
const { staticExports, isServerFirstRoute, hasClientExports } =
@@ -256,7 +275,10 @@ function createVirtualClientRouteModuleCode({
const generatorResult = babel.generate(clientRouteModuleAst);
generatorResult.code = '"use client";' + generatorResult.code;
- if (isRootRouteId(id) && !staticExports.includes("ErrorBoundary")) {
+ if (
+ isRootRouteFile({ id, rootRouteFile }) &&
+ !staticExports.includes("ErrorBoundary")
+ ) {
const hasRootLayout = staticExports.includes("Layout");
generatorResult.code += `\nimport { createElement as __rr_createElement } from "react";\n`;
generatorResult.code += `import { UNSAFE_RSCDefaultRootErrorBoundary } from "react-router";\n`;
@@ -288,15 +310,11 @@ export function parseRouteExports(code: string) {
}
function getVirtualClientModuleId(id: string): string {
- return `${id.split("?")[0]}?client-route-module${isRootRouteId(id) ? "&root-route=true" : ""}`;
+ return `${id.split("?")[0]}?client-route-module`;
}
function getVirtualServerModuleId(id: string): string {
- return `${id.split("?")[0]}?server-route-module${isRootRouteId(id) ? "&root-route=true" : ""}`;
-}
-
-function isRootRouteId(id: string): boolean {
- return /(\?|&)root-route=true(&|$)/.test(id);
+ return `${id.split("?")[0]}?server-route-module`;
}
function isVirtualRouteModuleId(id: string): boolean {
@@ -310,3 +328,14 @@ export function isVirtualClientRouteModuleId(id: string): boolean {
function isVirtualServerRouteModuleId(id: string): boolean {
return /(\?|&)server-route-module(&|$)/.test(id);
}
+
+function isRootRouteFile({
+ id,
+ rootRouteFile,
+}: {
+ id: string;
+ rootRouteFile: string;
+}): boolean {
+ const filePath = id.split("?")[0];
+ return filePath === rootRouteFile;
+}
diff --git a/packages/react-router-dom/CHANGELOG.md b/packages/react-router-dom/CHANGELOG.md
index a354aeaa86..e0b98360a6 100644
--- a/packages/react-router-dom/CHANGELOG.md
+++ b/packages/react-router-dom/CHANGELOG.md
@@ -1,5 +1,12 @@
# react-router-dom
+## 7.9.1
+
+### Patch Changes
+
+- Updated dependencies:
+ - `react-router@7.9.1`
+
## 7.9.0
### Patch Changes
diff --git a/packages/react-router-dom/package.json b/packages/react-router-dom/package.json
index 0f6a117a57..61cb4ea2ee 100644
--- a/packages/react-router-dom/package.json
+++ b/packages/react-router-dom/package.json
@@ -1,6 +1,6 @@
{
"name": "react-router-dom",
- "version": "7.9.0",
+ "version": "7.9.1",
"description": "Declarative routing for React web applications",
"keywords": [
"react",
diff --git a/packages/react-router-express/CHANGELOG.md b/packages/react-router-express/CHANGELOG.md
index b7501da330..86d0634bf4 100644
--- a/packages/react-router-express/CHANGELOG.md
+++ b/packages/react-router-express/CHANGELOG.md
@@ -1,5 +1,13 @@
# `@react-router/express`
+## 7.9.1
+
+### Patch Changes
+
+- Updated dependencies:
+ - `react-router@7.9.1`
+ - `@react-router/node@7.9.1`
+
## 7.9.0
### Minor Changes
diff --git a/packages/react-router-express/package.json b/packages/react-router-express/package.json
index a58c403c92..89d58cbbd8 100644
--- a/packages/react-router-express/package.json
+++ b/packages/react-router-express/package.json
@@ -1,6 +1,6 @@
{
"name": "@react-router/express",
- "version": "7.9.0",
+ "version": "7.9.1",
"description": "Express server request handler for React Router",
"bugs": {
"url": "https://github.com/remix-run/react-router/issues"
diff --git a/packages/react-router-fs-routes/CHANGELOG.md b/packages/react-router-fs-routes/CHANGELOG.md
index 619521de63..a67fdbfc2e 100644
--- a/packages/react-router-fs-routes/CHANGELOG.md
+++ b/packages/react-router-fs-routes/CHANGELOG.md
@@ -1,5 +1,12 @@
# `@react-router/fs-routes`
+## 7.9.1
+
+### Patch Changes
+
+- Updated dependencies:
+ - `@react-router/dev@7.9.1`
+
## 7.9.0
### Patch Changes
diff --git a/packages/react-router-fs-routes/package.json b/packages/react-router-fs-routes/package.json
index b8ca3f3de1..47a846e5d5 100644
--- a/packages/react-router-fs-routes/package.json
+++ b/packages/react-router-fs-routes/package.json
@@ -1,6 +1,6 @@
{
"name": "@react-router/fs-routes",
- "version": "7.9.0",
+ "version": "7.9.1",
"description": "File system routing conventions for React Router, for use within routes.ts",
"bugs": {
"url": "https://github.com/remix-run/react-router/issues"
diff --git a/packages/react-router-node/CHANGELOG.md b/packages/react-router-node/CHANGELOG.md
index e8f6d1b735..4ffca342fc 100644
--- a/packages/react-router-node/CHANGELOG.md
+++ b/packages/react-router-node/CHANGELOG.md
@@ -1,5 +1,12 @@
# `@react-router/node`
+## 7.9.1
+
+### Patch Changes
+
+- Updated dependencies:
+ - `react-router@7.9.1`
+
## 7.9.0
### Minor Changes
diff --git a/packages/react-router-node/package.json b/packages/react-router-node/package.json
index 9d93b27ac0..2ea5049029 100644
--- a/packages/react-router-node/package.json
+++ b/packages/react-router-node/package.json
@@ -1,6 +1,6 @@
{
"name": "@react-router/node",
- "version": "7.9.0",
+ "version": "7.9.1",
"description": "Node.js platform abstractions for React Router",
"bugs": {
"url": "https://github.com/remix-run/react-router/issues"
diff --git a/packages/react-router-remix-routes-option-adapter/CHANGELOG.md b/packages/react-router-remix-routes-option-adapter/CHANGELOG.md
index 94585601cf..6af5a0305a 100644
--- a/packages/react-router-remix-routes-option-adapter/CHANGELOG.md
+++ b/packages/react-router-remix-routes-option-adapter/CHANGELOG.md
@@ -1,5 +1,12 @@
# `@react-router/remix-config-routes-adapter`
+## 7.9.1
+
+### Patch Changes
+
+- Updated dependencies:
+ - `@react-router/dev@7.9.1`
+
## 7.9.0
### Patch Changes
diff --git a/packages/react-router-remix-routes-option-adapter/package.json b/packages/react-router-remix-routes-option-adapter/package.json
index 1f1359d1dc..c819e0503c 100644
--- a/packages/react-router-remix-routes-option-adapter/package.json
+++ b/packages/react-router-remix-routes-option-adapter/package.json
@@ -1,6 +1,6 @@
{
"name": "@react-router/remix-routes-option-adapter",
- "version": "7.9.0",
+ "version": "7.9.1",
"description": "Adapter for Remix's \"routes\" config option, for use within routes.ts",
"bugs": {
"url": "https://github.com/remix-run/react-router/issues"
diff --git a/packages/react-router-serve/CHANGELOG.md b/packages/react-router-serve/CHANGELOG.md
index f84c990c1f..770fb25277 100644
--- a/packages/react-router-serve/CHANGELOG.md
+++ b/packages/react-router-serve/CHANGELOG.md
@@ -1,5 +1,14 @@
# `@react-router/serve`
+## 7.9.1
+
+### Patch Changes
+
+- Updated dependencies:
+ - `react-router@7.9.1`
+ - `@react-router/node@7.9.1`
+ - `@react-router/express@7.9.1`
+
## 7.9.0
### Patch Changes
diff --git a/packages/react-router-serve/package.json b/packages/react-router-serve/package.json
index 18bd23a0e6..b087d4e44d 100644
--- a/packages/react-router-serve/package.json
+++ b/packages/react-router-serve/package.json
@@ -1,6 +1,6 @@
{
"name": "@react-router/serve",
- "version": "7.9.0",
+ "version": "7.9.1",
"description": "Production application server for React Router",
"bugs": {
"url": "https://github.com/remix-run/react-router/issues"
diff --git a/packages/react-router/CHANGELOG.md b/packages/react-router/CHANGELOG.md
index cd1d12b459..657d2583b7 100644
--- a/packages/react-router/CHANGELOG.md
+++ b/packages/react-router/CHANGELOG.md
@@ -1,5 +1,11 @@
# `react-router`
+## 7.9.1
+
+### Patch Changes
+
+- Fix internal `Future` interface naming from `middleware` -> `v8_middleware` ([#14327](https://github.com/remix-run/react-router/pull/14327))
+
## 7.9.0
### Minor Changes
diff --git a/packages/react-router/lib/types/future.ts b/packages/react-router/lib/types/future.ts
index 57e9e879fe..683a2185d7 100644
--- a/packages/react-router/lib/types/future.ts
+++ b/packages/react-router/lib/types/future.ts
@@ -2,8 +2,13 @@
* An augmentable interface users can modify in their app-code to opt into
* future-flag-specific types
*/
-export interface Future {}
+export interface Future {
+ // We list the potential fields here in comments strictly for clarity.
+ // They will be generated by the react-router/dev/typegen/generate.ts module
+ //
+ // v8_middleware: boolean
+}
// prettier-ignore
export type MiddlewareEnabled =
- Future extends { middleware: infer T extends boolean; } ? T : false
+ Future extends { v8_middleware: infer T extends boolean; } ? T : false
diff --git a/packages/react-router/lib/types/route-module-annotations.ts b/packages/react-router/lib/types/route-module-annotations.ts
index ceef11ede2..30ba7c983e 100644
--- a/packages/react-router/lib/types/route-module-annotations.ts
+++ b/packages/react-router/lib/types/route-module-annotations.ts
@@ -120,11 +120,33 @@ type CreateClientActionArgs = ClientDataFunctionArgs<
serverAction: () => Promise>;
};
-type CreateHydrateFallbackProps = {
+type IsServerFirstRoute<
+ T extends RouteInfo,
+ RSCEnabled extends boolean,
+> = RSCEnabled extends true
+ ? T["module"] extends { ServerComponent: Func }
+ ? true
+ : false
+ : false;
+
+type CreateHydrateFallbackProps<
+ T extends RouteInfo,
+ RSCEnabled extends boolean,
+> = {
params: T["params"];
- loaderData?: T["loaderData"];
- actionData?: T["actionData"];
-};
+} & (IsServerFirstRoute extends true
+ ? {
+ /** The data returned from the `loader` */
+ loaderData?: ServerDataFrom;
+ /** The data returned from the `action` following an action submission. */
+ actionData?: ServerDataFrom;
+ }
+ : {
+ /** The data returned from the `loader` or `clientLoader` */
+ loaderData?: T["loaderData"];
+ /** The data returned from the `action` or `clientAction` following an action submission. */
+ actionData?: T["actionData"];
+ });
type Match = Pretty<{
id: T["id"];
@@ -142,7 +164,7 @@ type Matches> =
? [Match, ...Matches]
: Array | undefined>;
-type CreateComponentProps = {
+type CreateComponentProps = {
/**
* {@link https://reactrouter.com/start/framework/routing#dynamic-segments Dynamic route params} for the current route.
* @example
@@ -158,15 +180,26 @@ type CreateComponentProps = {
* }
**/
params: T["params"];
- /** The data returned from the `loader` or `clientLoader` */
- loaderData: T["loaderData"];
- /** The data returned from the `action` or `clientAction` following an action submission. */
- actionData?: T["actionData"];
/** An array of the current {@link https://api.reactrouter.com/v7/interfaces/react_router.UIMatch.html route matches}, including parent route matches. */
matches: Matches;
-};
-
-type CreateErrorBoundaryProps = {
+} & (IsServerFirstRoute extends true
+ ? {
+ /** The data returned from the `loader` */
+ loaderData: ServerDataFrom;
+ /** The data returned from the `action` following an action submission. */
+ actionData?: ServerDataFrom;
+ }
+ : {
+ /** The data returned from the `loader` or `clientLoader` */
+ loaderData: T["loaderData"];
+ /** The data returned from the `action` or `clientAction` following an action submission. */
+ actionData?: T["actionData"];
+ });
+
+type CreateErrorBoundaryProps<
+ T extends RouteInfo,
+ RSCEnabled extends boolean,
+> = {
/**
* {@link https://reactrouter.com/start/framework/routing#dynamic-segments Dynamic route params} for the current route.
* @example
@@ -183,11 +216,24 @@ type CreateErrorBoundaryProps = {
**/
params: T["params"];
error: unknown;
- loaderData?: T["loaderData"];
- actionData?: T["actionData"];
-};
-
-export type GetAnnotations = {
+} & (IsServerFirstRoute extends true
+ ? {
+ /** The data returned from the `loader` */
+ loaderData?: ServerDataFrom;
+ /** The data returned from the `action` following an action submission. */
+ actionData?: ServerDataFrom;
+ }
+ : {
+ /** The data returned from the `loader` or `clientLoader` */
+ loaderData?: T["loaderData"];
+ /** The data returned from the `action` or `clientAction` following an action submission. */
+ actionData?: T["actionData"];
+ });
+
+export type GetAnnotations<
+ Info extends RouteInfo,
+ RSCEnabled extends boolean,
+> = {
// links
LinkDescriptors: LinkDescriptor[];
LinksFunction: () => LinkDescriptor[];
@@ -220,13 +266,13 @@ export type GetAnnotations = {
ClientActionArgs: CreateClientActionArgs;
// HydrateFallback
- HydrateFallbackProps: CreateHydrateFallbackProps;
+ HydrateFallbackProps: CreateHydrateFallbackProps;
// default (Component)
- ComponentProps: CreateComponentProps;
+ ComponentProps: CreateComponentProps;
// ErrorBoundary
- ErrorBoundaryProps: CreateErrorBoundaryProps;
+ ErrorBoundaryProps: CreateErrorBoundaryProps;
};
// eslint-disable-next-line @typescript-eslint/no-unused-vars
diff --git a/packages/react-router/package.json b/packages/react-router/package.json
index f58103527a..0954e6129b 100644
--- a/packages/react-router/package.json
+++ b/packages/react-router/package.json
@@ -1,6 +1,6 @@
{
"name": "react-router",
- "version": "7.9.0",
+ "version": "7.9.1",
"description": "Declarative routing for React",
"keywords": [
"react",
diff --git a/scripts/delete-pre-tags.sh b/scripts/delete-pre-tags.sh
new file mode 100755
index 0000000000..2959d37279
--- /dev/null
+++ b/scripts/delete-pre-tags.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+echo "Pruning tags before looking for tags to delete..."
+git fetch --prune --prune-tags
+
+PATTERN="@7\.\d\+\.\d\+-pre"
+
+TAGS=$(git tag | grep -e "${PATTERN}")
+
+if [[ $TAGS == "" ]]; then
+ echo "No tags to delete, exiting"
+ exit 0
+fi
+
+# Delay setting this because if it's set when no tags exist the program exits
+# on the TAGS assignment above
+set -e
+
+NUM_TAGS=$(git tag | grep -e "${PATTERN}" | wc -l | sed 's/ //g')
+TAGS_LINE=$(git tag | grep -e "${PATTERN}" | tr '\n' ' ')
+
+echo ""
+echo "Found ${NUM_TAGS} tags to delete. To delete, run the following commands:"
+echo ""
+echo "git push origin --delete ${TAGS_LINE}"
+echo "git fetch --prune --prune-tags"
+
+set +e
diff --git a/scripts/finish-stable-release.sh b/scripts/finish-stable-release.sh
index 1949d7d041..a34ff751e5 100755
--- a/scripts/finish-stable-release.sh
+++ b/scripts/finish-stable-release.sh
@@ -40,40 +40,10 @@ git push
git branch -d release-next
if [[ -n $(git show-ref refs/heads/changeset-release/release-next) ]]; then
- git branch -d changeset-release/release-next
+ git branch -D changeset-release/release-next
fi
-# If this is set when no tags exist the program exits on the TAGS assignment
-set +e
-
-echo "Pruning tags before looking for tags to delete:"
-git fetch --prune --prune-tags
-
-PATTERN="@7\.\d\+\.\d\+-pre"
-
-# Don't keep around prerelease tags for all packages - only the `react-router` package
-TAGS=$(git tag | grep -e "${PATTERN}" | grep -ve "^react-router@")
-
-if [[ $TAGS == "" ]]; then
- echo "No tags to delete, exiting"
- exit 0
-fi
-
-set -e
-
-NUM_TAGS=$(git tag | grep -e "${PATTERN}" | grep -ve "^react-router@" | wc -l | sed 's/ //g')
-TAGS_LINE=$(git tag | grep -e "${PATTERN}" | grep -ve "^react-router@" | tr '\n' ' ')
-
-echo "Found ${NUM_TAGS} tags to delete: ${TAGS_LINE}"
-
-echo "To delete, run the following commands:"
-echo ""
-echo "git push origin --delete ${TAGS_LINE}"
-echo "git fetch --prune --prune-tags"
-
-set +e
-set +x
-
+./scripts/delete-pre-tags.sh
set +e
set +x
\ No newline at end of file