diff --git a/.changeset/lazy-dots-sip.md b/.changeset/lazy-dots-sip.md new file mode 100644 index 00000000000..d812bcc3d57 --- /dev/null +++ b/.changeset/lazy-dots-sip.md @@ -0,0 +1,6 @@ +--- +"remix": patch +"@remix-run/dev": patch +--- + +add warning when `future.v2_routeConvention` is not enabled diff --git a/integration/flat-routes-test.ts b/integration/flat-routes-test.ts index 9254ca16ee5..49a4937f555 100644 --- a/integration/flat-routes-test.ts +++ b/integration/flat-routes-test.ts @@ -5,6 +5,7 @@ import { PlaywrightFixture } from "./helpers/playwright-fixture"; import type { Fixture, AppFixture } from "./helpers/create-fixture"; import { createFixtureProject } from "./helpers/create-fixture"; import { createAppFixture, createFixture, js } from "./helpers/create-fixture"; +import { flatRoutesWarning } from "../packages/remix-dev/config"; let fixture: Fixture; let appFixture: AppFixture; @@ -147,6 +148,51 @@ test.describe("flat routes", () => { } }); +test.describe("warns when v1 routesConvention is used", () => { + let buildStdio = new PassThrough(); + let buildOutput: string; + + let originalConsoleLog = console.log; + let originalConsoleWarn = console.warn; + let originalConsoleError = console.error; + + test.beforeAll(async () => { + console.log = () => {}; + console.warn = () => {}; + console.error = () => {}; + await createFixtureProject({ + buildStdio, + files: { + "routes/index.tsx": js` + export default function () { + return

routes/index

; + } + `, + }, + }); + + let chunks: Buffer[] = []; + buildOutput = await new Promise((resolve, reject) => { + buildStdio.on("data", (chunk) => chunks.push(Buffer.from(chunk))); + buildStdio.on("error", (err) => reject(err)); + buildStdio.on("end", () => + resolve(Buffer.concat(chunks).toString("utf8")) + ); + }); + }); + + test.afterAll(() => { + console.log = originalConsoleLog; + console.warn = originalConsoleWarn; + console.error = originalConsoleError; + }); + + test("warns about conflicting routes", () => { + console.log(buildOutput); + expect(buildOutput).toContain(flatRoutesWarning); + }); +}); + test.describe("emits warnings for route conflicts", async () => { let buildStdio = new PassThrough(); let buildOutput: string; diff --git a/integration/hmr-test.ts b/integration/hmr-test.ts index 1381038e0e4..63a88293661 100644 --- a/integration/hmr-test.ts +++ b/integration/hmr-test.ts @@ -14,6 +14,7 @@ let fixture = (options: { port: number; appServerPort: number }) => ({ appServerPort: options.appServerPort, }, unstable_tailwind: true, + v2_routeConvention: true, }, files: { "package.json": ` @@ -124,7 +125,7 @@ let fixture = (options: { port: number; appServerPort: number }) => ({ ); } `, - "app/routes/index.tsx": ` + "app/routes/_index.tsx": ` import { useLoaderData } from "@remix-run/react"; export default function Index() { const t = useLoaderData(); @@ -235,7 +236,7 @@ test("HMR", async ({ page }) => { await counter.click(); await page.waitForSelector(`#root-counter:has-text("inc 1")`); - let indexPath = path.join(projectDir, "app", "routes", "index.tsx"); + let indexPath = path.join(projectDir, "app", "routes", "_index.tsx"); let originalIndex = fs.readFileSync(indexPath, "utf8"); let counterPath = path.join(projectDir, "app", "components", "counter.tsx"); let originalCounter = fs.readFileSync(counterPath, "utf8"); diff --git a/integration/tsconfig.json b/integration/tsconfig.json index b8fd6c97ac7..d2215944147 100644 --- a/integration/tsconfig.json +++ b/integration/tsconfig.json @@ -17,6 +17,7 @@ "rootDir": "." }, "references": [ + { "path": "../packages/remix-dev" }, { "path": "../packages/remix-express" }, { "path": "../packages/remix-react" }, { "path": "../packages/remix-server-runtime" } diff --git a/packages/remix-dev/__tests__/create-test.ts b/packages/remix-dev/__tests__/create-test.ts index 4a0fbed9768..4508ac91907 100644 --- a/packages/remix-dev/__tests__/create-test.ts +++ b/packages/remix-dev/__tests__/create-test.ts @@ -8,6 +8,7 @@ import stripAnsi from "strip-ansi"; import { run } from "../cli/run"; import { server } from "./msw"; +import { flatRoutesWarning } from "../config"; beforeAll(() => server.listen({ onUnhandledRequest: "error" })); afterAll(() => server.close()); @@ -347,7 +348,9 @@ describe("the create command", () => { "--no-typescript", ]); expect(output.trim()).toBe( - getOptOutOfInstallMessage() + + flatRoutesWarning + + "\n\n" + + getOptOutOfInstallMessage() + "\n\n" + getSuccessMessage(path.join("", "template-to-js")) ); diff --git a/packages/remix-dev/config.ts b/packages/remix-dev/config.ts index 4c6f161eb86..8686777438a 100644 --- a/packages/remix-dev/config.ts +++ b/packages/remix-dev/config.ts @@ -560,9 +560,14 @@ export async function readConfig( root: { path: "", id: "root", file: rootRouteFile }, }; - let routesConvention = appConfig.future?.v2_routeConvention - ? flatRoutes - : defineConventionalRoutes; + let routesConvention: typeof flatRoutes; + + if (appConfig.future?.v2_routeConvention) { + routesConvention = flatRoutes; + } else { + warnOnce(flatRoutesWarning, "v2_routeConvention"); + routesConvention = defineConventionalRoutes; + } if (fse.existsSync(path.resolve(appDirectory, "routes"))) { let conventionalRoutes = routesConvention( @@ -726,4 +731,6 @@ let listFormat = new Intl.ListFormat("en", { type: "conjunction", }); -export let serverBuildTargetWarning = `The "serverBuildTarget" config option is deprecated. Use a combination of "publicPath", "serverBuildPath", "serverConditions", "serverDependenciesToBundle", "serverMainFields", "serverMinify", "serverModuleFormat" and/or "serverPlatform" instead.`; +export let serverBuildTargetWarning = `⚠️ DEPRECATED: The "serverBuildTarget" config option is deprecated. Use a combination of "publicPath", "serverBuildPath", "serverConditions", "serverDependenciesToBundle", "serverMainFields", "serverMinify", "serverModuleFormat" and/or "serverPlatform" instead.`; + +export let flatRoutesWarning = `⚠️ DEPRECATED: The old nested folders route convention has been deprecated in favor of "flat routes". Please enable the new routing convention via the \`future.v2_routeConvention\` flag in your \`remix.config.js\` file. For more information, please see https://remix.run/docs/en/main/file-conventions/route-files-v2.`;