remix-routes
remix-routes
自动生成类型安全的辅助函数,用于操作 Remix 应用中的内部链接。
https://user-images.githubusercontent.com/465125/205243864-3493733d-8586-405f-94eb-088fdb87fd23.mp4
remix-routes
也适用于 remix-modules
。
安装
$ npm add remix-routes
设置
使用 Vite
将 remix-routes
插件添加到您的 vite.config.ts
中。
import { defineConfig } from "vite";
import { vitePlugin as remix } from "@remix-run/dev";
import { remixRoutes } from "remix-routes/vite";
export default defineConfig({
plugins: [
remix(),
remixRoutes(options?)
],
});
支持的配置选项
strict: boolean
outDir: string
不使用 Vite
在 package.json
中的开发和构建脚本中添加 remix-routes
。
使用 concurrently
包
{
"scripts": {
"build": "remix-routes && remix build",
"dev": "concurrently \"remix-routes -w\" \"remix dev\""
}
}
使用 npm-run-all
包
{
"scripts": {
"build": "run-s build:*",
"build:routes": "remix-routes",
"dev": "run-p dev:*",
"dev:routes": "remix-routes -w",
}
}
用法
基本用法
import type { ActionFunction } from 'remix';
import { redirect } from 'remix';
import { $path } from 'remix-routes'; // <-- Import magical $path helper from remix-routes.
export const action: ActionFunction = async ({ request }) => {
let formData = await request.formData();
const post = await createPost(formData);
return redirect($path('/posts/:id', { id: post.id })); // <-- It's type safe.
};
追加查询字符串
import { $path } from 'remix-routes';
$path('/posts/:id', { id: 6 }, { version: 18 }); // => /posts/6?version=18
$path('/posts', { limit: 10 }); // => /posts?limit=10
// You can pass any URLSearchParams init as param
$path('/posts/delete', [['id', 1], ['id', 2]]); // => /posts/delete?id=1&id=2
类型化查询字符串
通过在路由文件中导出名为 SearchParams
的类型来定义查询字符串的类型。
// app/routes/posts.tsx
export type SearchParams = {
view: 'list' | 'grid',
sort?: 'date' | 'views',
page?: number,
}
import { $path } from 'remix-routes';
// The query string is type-safe.
$path('/posts', { view: 'list', sort: 'date', page: 1 });
您可以将此功能与 zod 和 remix-params-helper 结合使用,以添加运行时参数检查。
import { z } from "zod";
import { getSearchParams } from "remix-params-helper";
const SearchParamsSchema = z.object({
view: z.enum(["list", "grid"]),
sort: z.enum(["price", "size"]).optional(),
page: z.number().int().optional(),
})
export type SearchParams = z.infer<typeof SearchParamsSchema>;
export const loader = async (request) => {
const result = getSearchParams(request, SearchParamsSchema)
if (!result.success) {
return json(result.errors, { status: 400 })
}
const { view, sort, page } = result.data;
}
检查参数
import type { ActionFunction } from 'remix';
import { useParams } from "remix";
import { $params } from 'remix-routes'; // <-- Import $params helper.
export const action: ActionFunction = async ({ params }) => {
const { id } = $params("/posts/:id/update", params) // <-- It's type safe, try renaming `id` param.
// ...
}
export default function Component() {
const params = useParams();
const { id } = $params("/posts/:id/update", params);
...
}
$routeId 辅助函数用于 useRouteLoaderData 路由 ID
remix-routes 导出包含存储库中所有有效路由 ID 列表的 RouteId
类型定义,并提供一个辅助函数 $routeId
,该函数告诉 TypeScript 将给定的字符串限制为有效 RouteId 值之一。
import type { RouteId } from 'remix-routes';
import type { loader as postsLoader } from './_layout.tsx';
import { useRouteLoaderData } from '@remix-run/react';
import { $routeId } from 'remix-routes';
export default function Post() {
const postList = useRouteLoaderData<typeof postsLoader>($routeId('routes/posts/_layout'));
命令行选项
-w
: 监视更改并自动重建。-s
: 启用严格模式。在严格模式下,仅允许定义SearchParams
类型的路由具有查询字符串。-o
: 指定remix-routes.d.ts
的输出路径。如果未提供参数,则默认为./node_modules
。
TypeScript 集成
提供了一个 TypeScript 插件,可帮助您在路由文件之间导航。
安装
$ npm add -D typescript-remix-routes-plugin
设置
将插件添加到您的 tsconfig.json
中。
{
"compilerOptions": {
"plugins": [
{
"name": "typescript-remix-routes-plugin"
}
]
}
}
在 VSCode 中选择工作区版本的 TypeScript。