Skip to content

Commit

Permalink
Release 1.4.0
Browse files Browse the repository at this point in the history
  • Loading branch information
chenbin92 authored May 25, 2020
2 parents b5ab3c1 + bebc7bc commit 2ff7a2e
Show file tree
Hide file tree
Showing 96 changed files with 1,179 additions and 319 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const commonRules = {
"prefer-object-spread": 0,
// TODO: open rule indent, consider of MemberExpression
"indent": 0,
'semi': 2,
};

const jsRules = deepmerge(eslint, {
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/advance/antd.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: 使用 antd 组件
order: 11
order: 12
---

项目开发中如果使用 antd 组件作为基础 UI 组件,可以通过工程插件提供 antd 组件的按需加载和主题定制能力。
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/advance/assets-local.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: CSS 网络资源本地化
order: 9
order: 10
---

组件代码里有可能会依赖一些远程 CDN 的字体文件等,某些网络可能访问不了,出现这个问题有几种情况:
Expand Down
204 changes: 204 additions & 0 deletions docs/guide/advance/auth.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
---
title: 权限管理
order: 7
---

对于一个 Web 应用,权限管理是经常会涉及的需求之一,通常包含以下几种常见的权限管理类型:

- 页面权限:当用户访问某个没有权限的页面时跳转到无权限页面;
- 操作权限:页面中的某些按钮或组件针对无权限的用户直接隐藏;
- 接口权限:当用户通过操作调用没有权限的接口时跳转到无权限页面。

## 初始化权限数据

大多数情况下权限管理通常需要从服务端获取权限数据,然后在前端通过权限对比以此控制页面、操作等等权限行为。在 icejs 框架中约定通过 `getInitialData` 从服务端异步获取初始化的权限数据,并且约定最终返回格式为 `{auth: {[key: string]: boolean }}` 的形式。


```tsx
import { createApp, request, IAppConfig } from 'ice';

const appConfig: IAppConfig = {
app: {
getInitialData: async () => {
// 模拟服务端返回的数据
const data = await request('/api/auth');
const { role, starPermission, followPermission } = data;

// 约定权限必须返回一个 auth 对象
// 返回的每个值对应一条权限
return {
auth: {
admin: role === 'admin',
guest: role === 'guest',
starRepo: starPermission,
followRepo: followPermission
}
}
},
},
auth: {
// 可选的,设置无权限时的展示组件,默认为 null
NoAuthFallback: <div>没有权限...</div>,
}
};

createApp(appConfig);
```

## 页面权限

页面权限通常也称之为路由权限,如需对某些页面进行权限控制只需在页面组件的 `pageConfig` 中配置准入权限即可。

```tsx
import React from 'react';

const Home = () => {
return <>Home Page</>;
};

Home.pageConfig = {
// 可选,配置准入权限,若不配置则代表所有角色都可以访问
auth: ['admin'],
};
```

## 操作权限

在某些场景下,如某个组件中要根据角色判断是否有操作权限,我们可以通过 `useAuth` Hooks 在组件中获取权限数据,同时也可以更新初始的权限数据。

### 获取权限数据

```tsx
import React from 'react';
import { useAuth } from 'ice';

function Foo() {
const [auth] = useAuth();
return (
<>
当前用户权限数据:
<code>{JSON.stringify(auth)}</code>
</>
);
}
```

### 设置权限数据

```tsx
import React from 'react';
import { useAuth } from 'ice';

function Foo() {
const [auth, setAuth] = useAuth();

// 更新权限
function updateAuth() {
setAuth({ starRepo: false, followRepo: false });
}

return (
<>
当前用户角色:
<code>{JSON.stringify(auth)}</code>
<button type="button" onClick={updateAuth}>更新权限</button>
</>
);
}
```

### 自定义权限组件

对于操作类权限,通常我们可以自定义封装权限组件,以便更新粒度的控制权限和复用。

```ts
import React from 'react';
import { useAuth } from 'ice';
import NoAuth from '@/components/NoAuth';

function Auth({ children, authKey, fallback }) {
const [auth] = useAuth();
// 判断是否有权限
const hasAuth = auth[authKey];

// 有权限时直接渲染内容
if (hasAuth) {
return children;
} else {
// 无权限时显示指定 UI
return fallback || NoAuth
}
};

export default Auth;
```

使用如下:

```tsx
function Foo () {
return (
<Auth authKey={'starRepo'}>
<Button type="button">Star</Button>
</Auth>
)
}
```

## 接口鉴权

请参考文档 [数据请求](https://ice.work/docs/guide/basic/request),业务上封装统一的请求方法,与服务端约定接口协议,前端根据状态码判断无权限、未登录等状态,然后跳转到指定页面。

## API

### useAuth

用于在函数组件中获取和设置权限数据的 Hooks。

```ts
const [auth, setAuth] = useAuth();
```

示例:

```tsx
import React from 'react';
import { useAuth } from 'ice';

function Foo() {
const [auth, setAuth] = useAuth();
// auth:当前权限列表数据
// setAuth:设置当前权限列表数据

return (
<>Foo</>
);
}
```

### withAuth

用于在 Class 组件中获取和设置权限数据的高阶函数。

```ts
withAuth(Component)
```

示例:

```tsx
import React from 'react';

Class Foo extends React.Component {
render() {
const { auth, setAuth } = this.props;
// auth:当前权限列表数据
// setAuth:设置当前权限列表数据
return (
<>Foo</>
)
}
}

export default withAuth(Foo)
``
2 changes: 1 addition & 1 deletion docs/guide/advance/backend.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: 后端应用集成
order: 14
order: 15
---

> 如果是阿里内部同学,请参考 [文档](https://yuque.alibaba-inc.com/ice/rdy99p/rpivf3)
Expand Down
8 changes: 4 additions & 4 deletions docs/guide/advance/error-boundaries.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const appConfig: IAppConfig = {
// 是否开启 ErrorBoundary,默认为 false
errorBoundary: true
// 自定义错误边界的 fallback UI
ErrorBoundaryFallback: <div>渲染错误</div>,
ErrorBoundaryFallback: () => <div>渲染错误</div>,
// 自定义错误的处理事件
onErrorBoundaryHander: (error: Error, componentStack: string) {
// Do something with the error
Expand Down Expand Up @@ -63,9 +63,9 @@ import { ErrorBoundary } from 'ice';
export default function Todo() {
return (
<ErrorBoundary
{/* 默认使用全局配置的 ErrorBoundaryFallback */}
Fallback={<div>error</div>}
{/* 默认使用全局配置的 onErrorBoundaryHander */}
{/* 自定义错误边界的 fallback UI */}
Fallback={() => <div>渲染错误</div>}
{/* 自定义错误的处理事件 */}
onError={myErrorHandler}
>
<TodoList />
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/advance/fusion.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: 使用 fusion 组件
order: 10
order: 11
---

项目开发中如果使用 `@alifd/next` 作为基础 UI 组件,可以通过 `build-plugin-fusion` 插件实现组件按需加载和样式主题等相关能力,飞冰官方的模板都是基于 Fusion 组件的,因此一般不需要开发者再手动引入。
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/advance/mock.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: 本地 Mock 数据
order: 7
order: 8
---

在前后端分离的开发中,Mock 数据是前端开发中很重要的一个环节,前端可以不必强依赖后端接口,只需要约定好对应的数据接口,前端可以通过 Mock 模拟数据先行开发,在后端接口开发完成后,只需要切换对应的接口地址即可,可以保证项目的同步开发。
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/advance/proxy.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: 本地 Proxy 方案
order: 8
order: 9
---

本地开发场景下,访问页面的 url 是 `http://127.0.0.1:3333`,但是后端接口可能是其他 ip、域名或端口,此时就会产生跨域问题,导致无法调试,针对这个问题推荐两种代理方式:
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/advance/publish.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: 前端资源发布
order: 12
order: 13
---

> 如果是阿里内部同学,请参考 [文档](https://yuque.antfin-inc.com/ice/rdy99p/syvuzh)
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/advance/quality.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: 代码质量保障
order: 13
order: 14
---

为了保证代码质量,我们推荐使用 lint 相关的工具对代码进行检测,同时为了降低常规 lint 工具的使用成本,我们封装了 [@ice/spec](https://github.com/ice-lab/spec) 这个 npm 包。
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/advance/statistical.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: 页面埋点统计数据
order: 15
order: 16
---

> 阿里内部用户请参考:https://yuque.antfin-inc.com/ice/rdy99p/paswzc
Expand Down
4 changes: 3 additions & 1 deletion docs/guide/basic/app.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ const appConfig = {
return <ConfigProvider>{children}</ConfigProvider>;
},

// 可选,常用于 SSR 场景
// 可选,常用于 SSR 场景或者异步获取数据请求的场景
// 如果返回字段中包含 initialStates 字段将会作为状态管理 store 的初始值
// 如果返回字段中包含 auth 字段将会作为权限管理 auth 的初始值
getInitialData: async() => {
const result = await request();
return result;
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/basic/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ icejs 中一般不允许修改该配置。
}
```

### sourcemap
### sourceMap

- 类型: `boolean` 
- 默认值: `false` 
Expand Down
51 changes: 51 additions & 0 deletions docs/guide/basic/request.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@ RequestConfig:
responseType: 'json', // default
// should be made return full response
withFullResponse: false,
// request instance name
instanceName: 'request2'
}
```

Expand Down Expand Up @@ -364,6 +366,55 @@ const appConfig = {
createApp(appConfig);
```

### 多个请求配置

在某些复杂场景的应用中,我们也可以配置多个请求,每个配置请求都是单一的实例对象。

```ts
import { createApp } from 'ice';

const appConfig = {
request: [
{
baseURL: '/api',
// ...RequestConfig 其他参数

},
{
// 配置 request 实例名称,如果不配默认使用内置的 request 实例
instanceName: 'request2'
baseURL: '/api2',
// ...RequestConfig 其他参数
}
]
};

createApp(appConfig);
```

使用示例:

```ts
import { request } from 'ice';

export default {
// 使用默认的请求方法,即调用 /api/user 接口
async getUser() {
return await request({
url: '/user',
});
},

// 使用自定义的 request 请求方法,即调用接口 /api2/user
async getRepo(id) {
return await request({
instanceName: 'request2',
url: `/repo/${id}`,
});
},
}
```

## 异常处理

无论是拦截器里的错误参数,还是 request/useRequest 返回的错误对象,都符合以下类型:
Expand Down
1 change: 1 addition & 0 deletions docs/guide/basic/store.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ const appConfig = {
// 可选,初始化状态
initialStates: {};

// 已废弃
// 可选,获取初始状态,在 SSR 场景下会将 getInitialData 返回的数据作为入参
getInitialStates: (initialData) => {
return initialData;
Expand Down
Loading

0 comments on commit 2ff7a2e

Please sign in to comment.