From 8cdb67d18e36e4224dbed8fdf0a2fc94a12963d7 Mon Sep 17 00:00:00 2001 From: qixuan <58852732+GiveMe-A-Name@users.noreply.github.com> Date: Mon, 17 Jun 2024 11:04:16 +0800 Subject: [PATCH] fix: render function dynamic router match error (#5831) --- .changeset/plenty-ducks-itch.md | 6 +++ .../base/middlewares/renderHandler/render.ts | 20 ++++++- pnpm-lock.yaml | 43 +++++++++++++-- .../integration/routes-match/modern.config.ts | 23 ++++++++ tests/integration/routes-match/package.json | 34 ++++++++++++ tests/integration/routes-match/src/a/App.tsx | 1 + tests/integration/routes-match/src/b/App.tsx | 1 + tests/integration/routes-match/src/c/App.tsx | 1 + .../routes-match/tests/index.test.ts | 54 +++++++++++++++++++ tests/integration/routes-match/tsconfig.json | 13 +++++ 10 files changed, 191 insertions(+), 5 deletions(-) create mode 100644 .changeset/plenty-ducks-itch.md create mode 100644 tests/integration/routes-match/modern.config.ts create mode 100644 tests/integration/routes-match/package.json create mode 100644 tests/integration/routes-match/src/a/App.tsx create mode 100644 tests/integration/routes-match/src/b/App.tsx create mode 100644 tests/integration/routes-match/src/c/App.tsx create mode 100644 tests/integration/routes-match/tests/index.test.ts create mode 100644 tests/integration/routes-match/tsconfig.json diff --git a/.changeset/plenty-ducks-itch.md b/.changeset/plenty-ducks-itch.md new file mode 100644 index 000000000000..2a07eebd6553 --- /dev/null +++ b/.changeset/plenty-ducks-itch.md @@ -0,0 +1,6 @@ +--- +'@modern-js/server-core': patch +--- + +fix: render function dynamic router match error +fix: render 函数动态路由匹配错误 diff --git a/packages/server/core/src/base/middlewares/renderHandler/render.ts b/packages/server/core/src/base/middlewares/renderHandler/render.ts index 8a0ddf15760c..3815f5df2e82 100644 --- a/packages/server/core/src/base/middlewares/renderHandler/render.ts +++ b/packages/server/core/src/base/middlewares/renderHandler/render.ts @@ -38,12 +38,28 @@ interface CreateRenderOptions { nonce?: string; } +const DYNAMIC_ROUTE_REG = /\/:./; + function getRouter(routes: ServerRoute[]): Router { - const sorted = routes.sort(sortRoutes); + const dynamicRoutes: ServerRoute[] = []; + const normalRoutes: ServerRoute[] = []; + + routes.forEach(route => { + if (DYNAMIC_ROUTE_REG.test(route.urlPath)) { + dynamicRoutes.push(route); + } else { + normalRoutes.push(route); + } + }); + + const finalRoutes = [ + ...normalRoutes.sort(sortRoutes), + ...dynamicRoutes.sort(sortRoutes), + ]; const router = new TrieRouter(); - for (const route of sorted) { + for (const route of finalRoutes) { const { urlPath: originUrlPath } = route; const urlPath = originUrlPath.endsWith('/') diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2dda7b6cf85c..fb3ec191d092 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6575,6 +6575,43 @@ importers: specifier: ^5 version: 5.3.3 + tests/integration/routes-match: + dependencies: + '@modern-js/runtime': + specifier: workspace:* + version: link:../../../packages/runtime/plugin-runtime + fs-extra: + specifier: ^10.1.0 + version: 10.1.0 + react: + specifier: ^18 + version: 18.2.0 + react-dom: + specifier: ^18 + version: 18.2.0(react@18.2.0) + devDependencies: + '@modern-js/app-tools': + specifier: workspace:* + version: link:../../../packages/solutions/app-tools + '@types/fs-extra': + specifier: 9.0.13 + version: 9.0.13 + '@types/jest': + specifier: ^29 + version: 29.2.6 + '@types/node': + specifier: ^14 + version: 14.18.35 + '@types/react': + specifier: ^18 + version: 18.0.21 + '@types/react-dom': + specifier: ^18 + version: 18.0.6 + typescript: + specifier: ^5 + version: 5.4.5 + tests/integration/runtime: {} tests/integration/runtime/fixtures/file-based-router: @@ -35288,12 +35325,12 @@ packages: uglify-js: optional: true dependencies: - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.20 esbuild: 0.18.20 jest-worker: 27.5.1 schema-utils: 3.3.0 - serialize-javascript: 6.0.2 - terser: 5.31.1 + serialize-javascript: 6.0.1 + terser: 5.29.2 webpack: 5.92.0(esbuild@0.18.20) dev: false diff --git a/tests/integration/routes-match/modern.config.ts b/tests/integration/routes-match/modern.config.ts new file mode 100644 index 000000000000..07dc68652948 --- /dev/null +++ b/tests/integration/routes-match/modern.config.ts @@ -0,0 +1,23 @@ +import { appTools, defineConfig } from '@modern-js/app-tools'; + +const bundler = process.env.BUNDLER; + +export default defineConfig({ + plugins: [ + appTools({ + bundler: bundler === 'rspack' ? 'experimental-rspack' : 'webpack', + }), + ], + runtime: { + router: false, + state: false, + }, + server: { + ssr: true, + routes: { + a: '/detail/:id', + b: '/detail/1', + c: '/detail/12', + }, + }, +}); diff --git a/tests/integration/routes-match/package.json b/tests/integration/routes-match/package.json new file mode 100644 index 000000000000..24da999f56a9 --- /dev/null +++ b/tests/integration/routes-match/package.json @@ -0,0 +1,34 @@ +{ + "private": true, + "name": "routes-match", + "version": "2.9.0", + "scripts": { + "dev": "modern dev", + "build": "modern build", + "serve": "modern serve", + "new": "modern new", + "lint": "modern lint" + }, + "engines": { + "node": ">=14.17.6" + }, + "eslintIgnore": [ + "node_modules/", + "dist/" + ], + "dependencies": { + "@modern-js/runtime": "workspace:*", + "react": "^18", + "react-dom": "^18", + "fs-extra": "^10.1.0" + }, + "devDependencies": { + "@modern-js/app-tools": "workspace:*", + "@types/fs-extra": "9.0.13", + "@types/node": "^14", + "@types/react": "^18", + "@types/react-dom": "^18", + "typescript": "^5", + "@types/jest": "^29" + } +} diff --git a/tests/integration/routes-match/src/a/App.tsx b/tests/integration/routes-match/src/a/App.tsx new file mode 100644 index 000000000000..6daf3e6125c1 --- /dev/null +++ b/tests/integration/routes-match/src/a/App.tsx @@ -0,0 +1 @@ +export default () =>
AAA
; diff --git a/tests/integration/routes-match/src/b/App.tsx b/tests/integration/routes-match/src/b/App.tsx new file mode 100644 index 000000000000..e9c289ee6843 --- /dev/null +++ b/tests/integration/routes-match/src/b/App.tsx @@ -0,0 +1 @@ +export default () =>
BBB
; diff --git a/tests/integration/routes-match/src/c/App.tsx b/tests/integration/routes-match/src/c/App.tsx new file mode 100644 index 000000000000..f410a8f71426 --- /dev/null +++ b/tests/integration/routes-match/src/c/App.tsx @@ -0,0 +1 @@ +export default () =>
CCC
; diff --git a/tests/integration/routes-match/tests/index.test.ts b/tests/integration/routes-match/tests/index.test.ts new file mode 100644 index 000000000000..03c8a81ac65f --- /dev/null +++ b/tests/integration/routes-match/tests/index.test.ts @@ -0,0 +1,54 @@ +import dns from 'node:dns'; +import path from 'path'; +import puppeteer, { Page, Browser } from 'puppeteer'; +import { + launchApp, + getPort, + killApp, + launchOptions, +} from '../../../utils/modernTestUtils'; + +dns.setDefaultResultOrder('ipv4first'); + +const appDir = path.resolve(__dirname, '../'); + +describe('map routes match', () => { + let app: any; + let appPort: number; + let page: Page; + let browser: Browser; + + beforeAll(async () => { + appPort = await getPort(); + app = await launchApp(appDir, appPort, {}); + + browser = await puppeteer.launch(launchOptions as any); + page = await browser.newPage(); + }); + + afterAll(async () => { + if (browser) { + browser.close(); + } + if (app) { + await killApp(app); + } + }); + + test('should match route correctly', async () => { + const res1 = await page.goto(`http://localhost:${appPort}/detail/123`); + const text1 = await res1.text(); + + expect(text1).toMatch('AAA'); + + const res2 = await page.goto(`http://localhost:${appPort}/detail/1`); + const text2 = await res2.text(); + + expect(text2).toMatch('BBB'); + + const res3 = await page.goto(`http://localhost:${appPort}/detail/12`); + const text3 = await res3.text(); + + expect(text3).toMatch('CCC'); + }); +}); diff --git a/tests/integration/routes-match/tsconfig.json b/tests/integration/routes-match/tsconfig.json new file mode 100644 index 000000000000..f2c10d4cd9e9 --- /dev/null +++ b/tests/integration/routes-match/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "@modern-js/tsconfig/base", + "compilerOptions": { + "declaration": false, + "jsx": "preserve", + "baseUrl": "./", + "paths": { + "@/*": ["./src/*"], + "@shared/*": ["./shared/*"] + } + }, + "include": ["src", "shared", "config"] +}