Skip to content

feat: router rewrite #7218

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -252,10 +252,6 @@ const time: UnstableMiddleware = async (c: UnstableMiddlewareContext, next) => {
export const unstableMiddleware: UnstableMiddleware[] = [time];
```

:::info
For detailed API and more usage, see [UnstableMiddleware](/apis/app/runtime/web-server/unstable_middleware).
:::

### Hooks

:::warning
Expand Down Expand Up @@ -287,10 +283,6 @@ Best practices when using Hooks:
2. Handle Rewrite and Redirect in afterMatch.
3. Inject HTML content in afterRender.

:::info
For detailed API and more usage, see [Hook](/apis/app/runtime/web-server/hook).
:::

## Migrate to the New Version of Custom Web Server

### Migration Background
Expand Down Expand Up @@ -443,11 +435,11 @@ type AfterRenderContext = {

Hook Context is mostly consistent with Middleware Context, so we need to pay extra attention to the additional parts of different Hooks.

| UnstableMiddleware | Hono | Description |
| :----------------- | :----------- | :----------------------------------------------------------------------------------------- |
| `router.redirect` | `c.redirect` | Refer to [Hono Context redirect](https://hono.dev/docs/api/context#redirect) documentation |
| `router.rewrite` | - | No corresponding capability provided at the moment |
| template API | `c.res` | Refer to [Hono Context res](https://hono.dev/docs/api/context#res) documentation |
| UnstableMiddleware | Hono | Description |
| :----------------- | :----------------- | :----------------------------------------------------------------------------------------- |
| `router.redirect` | `c.redirect` | Refer to [Hono Context redirect](https://hono.dev/docs/api/context#redirect) documentation |
| `router.rewrite` | `c.rewriteByEntry` | Rewrite to the specified entry. Routing or external urls are not supported |
| template API | `c.res` | Refer to [Hono Context res](https://hono.dev/docs/api/context#res) documentation |

### Differences in Next API

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -429,11 +429,11 @@ type AfterRenderContext = {

Hook Context 大部分和 Middleware Context 一致,因此我们要额外关注不同 Hook 多余的部分。

| UnstableMiddleware | Hono | 说明 |
| :----------------- | :----------- | :---------------------------------------------------------------------------- |
| `router.redirect` | `c.redirect` | 参考 [Hono Context redirect](https://hono.dev/docs/api/context#redirect) 文档 |
| `router.rewrite` | - | 暂时没有提供对应的能力 |
| template API | `c.res` | 参考 [Hono Context res](https://hono.dev/docs/api/context#res) 文档 |
| UnstableMiddleware | Hono | 说明 |
| :----------------- | :----------------- | :---------------------------------------------------------------------------- |
| `router.redirect` | `c.redirect` | 参考 [Hono Context redirect](https://hono.dev/docs/api/context#redirect) 文档 |
| `router.rewrite` | `c.rewriteByEntry` | rewrite 到指定 entry,不支持路由或外部 url |
| template API | `c.res` | 参考 [Hono Context res](https://hono.dev/docs/api/context#res) 文档 |

### Next API 差异

Expand Down
1 change: 1 addition & 0 deletions packages/server/core/src/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ export {
} from './default';
export { compatPlugin, handleSetupResult } from './compat';
export { injectConfigMiddlewarePlugin } from './middlewares';
export { routerRewritePlugin } from './rewrite';
38 changes: 38 additions & 0 deletions packages/server/core/src/plugins/rewrite.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import type { Context, Next } from 'hono';
import type { ServerPlugin } from '../types';

declare module 'hono' {
interface Context {
rewriteByEntry: (entry: string) => void;
}
}

export const routerRewritePlugin = (): ServerPlugin => ({
name: '@Modern-js/plugin-router-rewrite-plugin',
setup(api) {
api.onPrepare(() => {
const { middlewares, routes } = api.getServerContext();
if (!routes) {
return;
}

middlewares.push({
name: 'router-rewrite',
order: 'pre',
handler: async (c: Context, next: Next) => {
c.rewriteByEntry = (entry: string) => {
const rewriteRoute = routes
.filter(route => !route.isApi)
.find(route => route.entryName === entry);

if (rewriteRoute) {
c.set('matchPathname', rewriteRoute.urlPath);
c.set('matchEntryName', entry);
}
};
await next();
},
});
});
},
});
2 changes: 2 additions & 0 deletions packages/server/prod-server/src/apply.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
injectConfigMiddlewarePlugin,
onError,
renderPlugin,
routerRewritePlugin,
} from '@modern-js/server-core';
import {
injectNodeSeverPlugin,
Expand Down Expand Up @@ -59,6 +60,7 @@ export async function applyPlugins(
const { middlewares, renderMiddlewares } = options.serverConfig || {};

const plugins = [
routerRewritePlugin(),
...(nodeServer ? [injectNodeSeverPlugin({ nodeServer })] : []),
...createDefaultPlugins({
cacheConfig,
Expand Down
9 changes: 9 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions tests/integration/routes/modern.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export default defineConfig({
loaderFailureMode: 'clientRender',
},
four: false,
rewrite: false,
},
},
});
6 changes: 5 additions & 1 deletion tests/integration/routes/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
"@modern-js/runtime": "workspace:*",
"fs-extra": "^10.1.0",
"react": "^19.1.1",
"react-dom": "^19.1.1"
"react-dom": "^19.1.1",
"@modern-js/server-runtime": "workspace:*",
"ts-node": "^10.9.2",
"tsconfig-paths": "~3.14.1"
},
"devDependencies": {
"@modern-js/app-tools": "workspace:*",
Expand All @@ -24,6 +27,7 @@
"@types/node": "^20",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",

"typescript": "^5"
}
}
18 changes: 18 additions & 0 deletions tests/integration/routes/server/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports = {
root: true,
plugins: ['prettier'],
rules: {
// eslint-disable-next-line
'prettier/prettier': 'error',
},
overrides: [
{
files: ['*.js', '*.jsx'],
extends: '@byted/eslint-config-standard',
},
{
files: ['*.ts', '*.tsx'],
extends: '@byted/eslint-config-standard-ts',
},
],
};
21 changes: 21 additions & 0 deletions tests/integration/routes/server/modern.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {
type MiddlewareHandler,
defineServerConfig,
} from '@modern-js/server-runtime';

const renderTiming: MiddlewareHandler = async (c, next) => {
if (c.req.path === '/rewrite') {
c.rewriteByEntry('one');
}

await next();
};

export default defineServerConfig({
renderMiddlewares: [
{
name: 'render-timing',
handler: renderTiming,
},
],
});
Empty file.
5 changes: 5 additions & 0 deletions tests/integration/routes/src/rewrite/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import './App.css';

const App = () => <p className="description">rewrite page</p>;

export default App;
2 changes: 1 addition & 1 deletion tests/integration/routes/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
"@shared/*": ["./shared/*"]
}
},
"include": ["src", "shared", "config"]
"include": ["src", "shared", "config", "server"]
}
Loading