@modern-js/main-doc 2.33.1 → 2.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/en/apis/app/hooks/config/public.mdx +2 -2
- package/docs/en/apis/app/hooks/config/upload.mdx +3 -3
- package/docs/en/components/tech-stack-node-framework.mdx +1 -0
- package/docs/en/configure/app/server/ssr.mdx +2 -0
- package/docs/en/configure/app/source/config-dir.mdx +2 -2
- package/docs/en/guides/advanced-features/eslint.mdx +1 -1
- package/docs/en/guides/basic-features/alias.mdx +11 -50
- package/docs/en/guides/basic-features/env-vars.mdx +1 -1
- package/docs/en/guides/basic-features/routes.mdx +4 -4
- package/docs/en/guides/concept/builder.mdx +1 -1
- package/docs/en/guides/get-started/glossary.mdx +1 -1
- package/docs/en/guides/get-started/introduction.mdx +21 -1
- package/docs/en/guides/get-started/tech-stack.mdx +138 -0
- package/docs/en/guides/topic-detail/changesets/add.mdx +1 -1
- package/docs/en/guides/topic-detail/changesets/changelog.mdx +3 -3
- package/docs/en/guides/topic-detail/changesets/commit.mdx +3 -3
- package/docs/en/guides/topic-detail/changesets/release-note.mdx +3 -3
- package/docs/en/guides/topic-detail/changesets/release.mdx +1 -1
- package/docs/en/guides/topic-detail/framework-plugin/implement.mdx +4 -4
- package/docs/en/guides/topic-detail/generator/create/use.mdx +1 -9
- package/docs/en/guides/topic-detail/generator/plugin/context.md +1 -1
- package/docs/en/tutorials/examples/_category_.json +5 -0
- package/docs/en/tutorials/examples/csr-auth.mdx +214 -0
- package/docs/en/tutorials/foundations/introduction.mdx +10 -1
- package/docs/zh/community/blog/2022-0708-updates.md +4 -4
- package/docs/zh/community/blog/overview.md +1 -1
- package/docs/zh/components/tech-stack-node-framework.mdx +1 -0
- package/docs/zh/configure/app/server/ssr.mdx +3 -0
- package/docs/zh/guides/advanced-features/eslint.mdx +1 -1
- package/docs/zh/guides/basic-features/alias.mdx +11 -50
- package/docs/zh/guides/basic-features/routes.mdx +1 -1
- package/docs/zh/guides/get-started/introduction.mdx +20 -0
- package/docs/zh/guides/get-started/tech-stack.mdx +138 -0
- package/docs/zh/guides/topic-detail/changesets/add.mdx +1 -1
- package/docs/zh/guides/topic-detail/changesets/changelog.mdx +3 -3
- package/docs/zh/guides/topic-detail/changesets/commit.mdx +3 -3
- package/docs/zh/guides/topic-detail/changesets/release-note.mdx +3 -3
- package/docs/zh/guides/topic-detail/changesets/release.mdx +1 -1
- package/docs/zh/guides/topic-detail/framework-plugin/implement.mdx +5 -5
- package/docs/zh/guides/topic-detail/generator/create/use.mdx +0 -8
- package/docs/zh/guides/topic-detail/generator/plugin/context.md +1 -1
- package/docs/zh/tutorials/examples/_category_.json +5 -0
- package/docs/zh/tutorials/examples/csr-auth.mdx +214 -0
- package/docs/zh/tutorials/foundations/introduction.mdx +8 -0
- package/package.json +8 -5
- package/src/components/Sandpack/index.css +10 -0
- package/src/components/Sandpack/index.tsx +30 -0
@@ -26,7 +26,7 @@ export default function (context: IPluginContext) {
|
|
26
26
|
|
27
27
|
## 自定义 Input
|
28
28
|
|
29
|
-
Modern.js
|
29
|
+
Modern.js Framework 和 Modern.js Module 都存在一些默认的 Input 交互,使用这里的 API 可以对这些 Input 进行添加、修改、隐藏、提供默认值等操作。
|
30
30
|
|
31
31
|
例如:
|
32
32
|
|
@@ -0,0 +1,214 @@
|
|
1
|
+
---
|
2
|
+
title: 路由鉴权
|
3
|
+
---
|
4
|
+
|
5
|
+
# 路由鉴权
|
6
|
+
|
7
|
+
Modern.js 默认提供的路由方式是基于 React Router 6 的约定式路由,具体可查看[路由方案](/guides/basic-features/routes.html#路由方案)。
|
8
|
+
|
9
|
+
在一个 Web 应用中如果存在多个路由,我们可能需要对部分路由进行鉴权后才能访问。例如下面这个案例:
|
10
|
+
|
11
|
+
- 访问 `/` 路由,无需鉴权,可直接访问。
|
12
|
+
- 访问 `/protected` 路由,需要鉴权,如果无,自动跳转到 `/login` 路由,登录成功后返回 `/protected`。
|
13
|
+
|
14
|
+
import Sandpack from '@site/src/components/Sandpack';
|
15
|
+
|
16
|
+
<Sandpack template="web-app">
|
17
|
+
```tsx title="src/routes/page.tsx"
|
18
|
+
import { Helmet } from '@modern-js/runtime/head';
|
19
|
+
import './index.css';
|
20
|
+
|
21
|
+
const PublicPage = (): JSX.Element => (
|
22
|
+
<div className="container-box">
|
23
|
+
<Helmet>
|
24
|
+
<link
|
25
|
+
rel="icon"
|
26
|
+
type="image/x-icon"
|
27
|
+
href="https://lf3-static.bytednsdoc.com/obj/eden-cn/uhbfnupenuhf/favicon.ico"
|
28
|
+
/>
|
29
|
+
</Helmet>
|
30
|
+
<h3>Public</h3>
|
31
|
+
</div>
|
32
|
+
);
|
33
|
+
|
34
|
+
export default PublicPage;
|
35
|
+
|
36
|
+
```
|
37
|
+
```tsx title="src/routes/layout.tsx"
|
38
|
+
import { Link, Outlet } from '@modern-js/runtime/router';
|
39
|
+
import { AuthProvider, AuthStatus } from './Auth';
|
40
|
+
|
41
|
+
export default function Layout() {
|
42
|
+
return (
|
43
|
+
<AuthProvider>
|
44
|
+
<AuthStatus />
|
45
|
+
|
46
|
+
<ul>
|
47
|
+
<li>
|
48
|
+
<Link to="/">Public Page</Link>
|
49
|
+
</li>
|
50
|
+
<li>
|
51
|
+
<Link to="/protected">Protected Page</Link>
|
52
|
+
</li>
|
53
|
+
</ul>
|
54
|
+
|
55
|
+
<Outlet />
|
56
|
+
</AuthProvider>
|
57
|
+
);
|
58
|
+
}
|
59
|
+
|
60
|
+
```
|
61
|
+
```ts title="src/routes/fakeAuth.ts"
|
62
|
+
/**
|
63
|
+
* This represents some generic auth provider API, like Firebase.
|
64
|
+
*/
|
65
|
+
const fakeAuthProvider = {
|
66
|
+
isAuthenticated: false,
|
67
|
+
signin(callback: VoidFunction) {
|
68
|
+
fakeAuthProvider.isAuthenticated = true;
|
69
|
+
setTimeout(callback, 100); // fake async
|
70
|
+
},
|
71
|
+
signout(callback: VoidFunction) {
|
72
|
+
fakeAuthProvider.isAuthenticated = false;
|
73
|
+
setTimeout(callback, 100);
|
74
|
+
},
|
75
|
+
};
|
76
|
+
|
77
|
+
export { fakeAuthProvider };
|
78
|
+
|
79
|
+
```
|
80
|
+
```ts title="src/routes/Auth.tsx"
|
81
|
+
import React from 'react';
|
82
|
+
import { useNavigate, Navigate, useLocation } from '@modern-js/runtime/router';
|
83
|
+
import { fakeAuthProvider } from './fakeAuth';
|
84
|
+
|
85
|
+
interface AuthContextType {
|
86
|
+
user: any;
|
87
|
+
signin: (user: string, callback: VoidFunction) => void;
|
88
|
+
signout: (callback: VoidFunction) => void;
|
89
|
+
}
|
90
|
+
|
91
|
+
const AuthContext = React.createContext<AuthContextType>(null!);
|
92
|
+
|
93
|
+
export function AuthProvider({ children }: { children: React.ReactNode }) {
|
94
|
+
const [user, setUser] = React.useState<any>(null);
|
95
|
+
|
96
|
+
const signin = (newUser: string, callback: VoidFunction) =>
|
97
|
+
fakeAuthProvider.signin(() => {
|
98
|
+
setUser(newUser);
|
99
|
+
callback();
|
100
|
+
});
|
101
|
+
|
102
|
+
const signout = (callback: VoidFunction) =>
|
103
|
+
fakeAuthProvider.signout(() => {
|
104
|
+
setUser(null);
|
105
|
+
callback();
|
106
|
+
});
|
107
|
+
|
108
|
+
const value = { user, signin, signout };
|
109
|
+
|
110
|
+
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
|
111
|
+
}
|
112
|
+
|
113
|
+
export function useAuth() {
|
114
|
+
return React.useContext(AuthContext);
|
115
|
+
}
|
116
|
+
|
117
|
+
export function AuthStatus() {
|
118
|
+
const auth = useAuth();
|
119
|
+
console.log('auth', auth);
|
120
|
+
const navigate = useNavigate();
|
121
|
+
|
122
|
+
if (!auth.user) {
|
123
|
+
return <p>You are not logged in.</p>;
|
124
|
+
}
|
125
|
+
|
126
|
+
return (
|
127
|
+
<p>
|
128
|
+
Welcome {auth.user}!{' '}
|
129
|
+
<button
|
130
|
+
type="button"
|
131
|
+
onClick={() => {
|
132
|
+
auth.signout(() => navigate('/'));
|
133
|
+
}}
|
134
|
+
>
|
135
|
+
Sign out
|
136
|
+
</button>
|
137
|
+
</p>
|
138
|
+
);
|
139
|
+
}
|
140
|
+
|
141
|
+
export function RequireAuth({ children }: { children: JSX.Element }) {
|
142
|
+
const auth = useAuth();
|
143
|
+
const location = useLocation();
|
144
|
+
|
145
|
+
if (!auth.user) {
|
146
|
+
// Redirect them to the /login page, but save the current location they were
|
147
|
+
// trying to go to when they were redirected. This allows us to send them
|
148
|
+
// along to that page after they login, which is a nicer user experience
|
149
|
+
// than dropping them off on the home page.
|
150
|
+
return <Navigate to="/login" state={{ from: location }} replace />;
|
151
|
+
}
|
152
|
+
|
153
|
+
return children;
|
154
|
+
}
|
155
|
+
|
156
|
+
```
|
157
|
+
```ts title="src/routes/protected/page.tsx"
|
158
|
+
import { RequireAuth } from '../Auth';
|
159
|
+
|
160
|
+
export default function ProtectedPage() {
|
161
|
+
return (
|
162
|
+
<div className="container-box">
|
163
|
+
<RequireAuth>
|
164
|
+
<h3>Protected</h3>
|
165
|
+
</RequireAuth>
|
166
|
+
</div>
|
167
|
+
);
|
168
|
+
}
|
169
|
+
|
170
|
+
```
|
171
|
+
```ts title="src/routes/login/page.tsx"
|
172
|
+
import { useLocation, useNavigate } from '@modern-js/runtime/router';
|
173
|
+
import { useAuth } from '../Auth';
|
174
|
+
|
175
|
+
export default function Login() {
|
176
|
+
const navigate = useNavigate();
|
177
|
+
const location = useLocation();
|
178
|
+
const auth = useAuth();
|
179
|
+
|
180
|
+
const from = location.state?.from?.pathname || '/';
|
181
|
+
|
182
|
+
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
|
183
|
+
event.preventDefault();
|
184
|
+
|
185
|
+
const formData = new FormData(event.currentTarget);
|
186
|
+
const username = formData.get('username') as string;
|
187
|
+
|
188
|
+
auth.signin(username, () => {
|
189
|
+
// Send them back to the page they tried to visit when they were
|
190
|
+
// redirected to the login page. Use { replace: true } so we don't create
|
191
|
+
// another entry in the history stack for the login page. This means that
|
192
|
+
// when they get to the protected page and click the back button, they
|
193
|
+
// won't end up back on the login page, which is also really nice for the
|
194
|
+
// user experience.
|
195
|
+
navigate(from, { replace: true });
|
196
|
+
});
|
197
|
+
}
|
198
|
+
|
199
|
+
return (
|
200
|
+
<div>
|
201
|
+
<p>You must log in to view the page at {from}</p>
|
202
|
+
|
203
|
+
<form onSubmit={handleSubmit}>
|
204
|
+
<label>
|
205
|
+
Username: <input name="username" type="text" />
|
206
|
+
</label>{' '}
|
207
|
+
<button type="submit">Login</button>
|
208
|
+
</form>
|
209
|
+
</div>
|
210
|
+
);
|
211
|
+
}
|
212
|
+
|
213
|
+
```
|
214
|
+
</Sandpack>
|
package/package.json
CHANGED
@@ -15,14 +15,17 @@
|
|
15
15
|
"modern",
|
16
16
|
"modern.js"
|
17
17
|
],
|
18
|
-
"version": "2.
|
18
|
+
"version": "2.35.0",
|
19
19
|
"publishConfig": {
|
20
20
|
"registry": "https://registry.npmjs.org/",
|
21
21
|
"access": "public",
|
22
22
|
"provenance": true
|
23
23
|
},
|
24
|
+
"dependencies": {
|
25
|
+
"@modern-js/sandpack-react": "2.35.0"
|
26
|
+
},
|
24
27
|
"peerDependencies": {
|
25
|
-
"@modern-js/builder-doc": "^2.
|
28
|
+
"@modern-js/builder-doc": "^2.35.0"
|
26
29
|
},
|
27
30
|
"devDependencies": {
|
28
31
|
"classnames": "^2",
|
@@ -32,12 +35,12 @@
|
|
32
35
|
"ts-node": "^10.9.1",
|
33
36
|
"typescript": "^5",
|
34
37
|
"fs-extra": "^10",
|
35
|
-
"rspress": "0.0.
|
38
|
+
"rspress": "0.0.10",
|
36
39
|
"@rspress/shared": "0.0.6",
|
37
40
|
"@types/node": "^16",
|
38
41
|
"@types/fs-extra": "^9",
|
39
|
-
"@modern-js/builder-doc": "2.
|
40
|
-
"@modern-js/doc-plugin-auto-sidebar": "2.
|
42
|
+
"@modern-js/builder-doc": "2.35.0",
|
43
|
+
"@modern-js/doc-plugin-auto-sidebar": "2.35.0"
|
41
44
|
},
|
42
45
|
"scripts": {
|
43
46
|
"dev": "rspress dev",
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import ModernSandpack, { ModernSandpackProps } from '@modern-js/sandpack-react';
|
2
|
+
import React, { PropsWithChildren } from 'react';
|
3
|
+
import { useDark, NoSSR } from 'rspress/runtime';
|
4
|
+
|
5
|
+
import './index.css';
|
6
|
+
|
7
|
+
const Sandpack = (props: PropsWithChildren<ModernSandpackProps>) => {
|
8
|
+
const dark = useDark();
|
9
|
+
const { children, ...otherProps } = props;
|
10
|
+
const files: Record<string, string> = {};
|
11
|
+
React.Children.forEach(children, (child: any) => {
|
12
|
+
if (child) {
|
13
|
+
const { meta, children } = child.props.children.props;
|
14
|
+
const matches = meta.match(/title="(.*)"/);
|
15
|
+
if (matches.length > 1) {
|
16
|
+
files[matches[1]] = children;
|
17
|
+
}
|
18
|
+
}
|
19
|
+
});
|
20
|
+
return (
|
21
|
+
<NoSSR>
|
22
|
+
<ModernSandpack
|
23
|
+
files={files}
|
24
|
+
theme={dark ? 'dark' : 'light'}
|
25
|
+
{...otherProps}
|
26
|
+
/>
|
27
|
+
</NoSSR>
|
28
|
+
);
|
29
|
+
};
|
30
|
+
export default Sandpack;
|