Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/xams-creator/dusk
Lightweight frontend react framework
https://github.com/xams-creator/dusk
react redux typescript
Last synced: 7 days ago
JSON representation
Lightweight frontend react framework
- Host: GitHub
- URL: https://github.com/xams-creator/dusk
- Owner: xams-creator
- License: mit
- Created: 2021-03-24T09:19:49.000Z (over 3 years ago)
- Default Branch: master
- Last Pushed: 2024-07-19T03:11:32.000Z (4 months ago)
- Last Synced: 2024-07-20T10:59:54.136Z (4 months ago)
- Topics: react, redux, typescript
- Language: TypeScript
- Homepage:
- Size: 2.02 MB
- Stars: 6
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Dusk
Lightweight frontend framework based on
- [react](https://github.com/facebook/react)
- [redux](https://github.com/reactjs/redux)
- [react-redux](https://github.com/reduxjs/react-redux)
- [redux-thunk](https://github.com/reduxjs/redux-thunk)
- [react-router](https://github.com/remix-run/react-router)
- [hotkeys-js](https://github.com/jaywcjlove/hotkeys)
- [axios](https://github.com/axios/axios)
- [immer](https://github.com/immerjs/immer)## Features
- Typescript supports
- App lifecycle
- Plugin
- Simplified redux model
- HMR (craco、vite)## Installation
```
npm i @xams-framework/dusk
```## Usage
- ### Basic ([examples/dusk-example-count](https://github.com/xams-creator/dusk-examples/tree/master/dusk-example-count))
#### index.tsx```tsx
import { createApp, createDuskModel } from '@xams-framework/dusk';const app = createApp({
container: '#root',
});const model = createDuskModel({
namespace: 'app',
initialState: {
value: 1,
},
reducers: {
add(state) {
state.value += 1;
},
},
effects: {
setValue(dispatch, state, action, { set }) {
set((state) => {
state.value = action.payload
})
return {
code: 0,
success: true
msg: 'ok'
}
}
}
});
app.define(model);app.startup(
hello world!);console.log(app.state); // {app: {value : 1}}
app.$store.dispatch({ type: 'app/add' });
console.log(app.state); // {app: {value : 2}}app.$store.dispatch(model.actions.add());
console.log(app.state); // {app: {value : 3}}const promise = app.$store.dispatch(model.commands.setValue(999));
console.log(app.state); // {app: {value : 999}}
promise.then((res) => {
alert(res.msg) // ok
})
```- ### Plugins ([examples/dusk-example-plugins](https://github.com/xams-creator/dusk-examples/tree/master/dusk-example-plugins))
#### index.tsx```tsx
import React from 'react';import { createApp } from '@xams-framework/dusk';
import createDuskAppLifecycle from '@/configuration/plugins/dusk-plugin-app-lifecycle';
import createDuskAppReady from '@/configuration/plugins/dusk-plugin-app-ready';
import createDuskCustomHooks from '@/configuration/plugins/dusk-plugin-custom-hooks';const app = createApp({
container: '#root',
});app.use(createDuskAppLifecycle())
.use(createDuskAppReady())
.use(createDuskCustomHooks())
.startup(按F12请打开控制台);window.app = app;
```![示例图片](public/images/plugin-call-log.png)
- ### HMR ([examples/dusk-example-hmr-craco](https://github.com/xams-creator/dusk-examples/tree/master/dusk-example-hmr-craco))
```shell
npm i -D @xams-framework/craco-plugin-dusk-hmr
npm i @xams-framework/dusk-plugin-hmr
```- #### craco.config.ts
```tsx
import { CracoConfig } from '@craco/types';
import createCracoDuskHmr from '@xams-framework/craco-plugin-dusk-hmr';function defineCraco(options: CracoConfig): CracoConfig {
return options;
}export default defineCraco({
plugins: [createCracoDuskHmr()],
webpack: {
alias: {
'@': 'src',
},
},
});
```- #### index.tsx
```tsx
import { createApp } from '@xams-framework/dusk';
import createDuskHmr from '@xams-framework/dusk-plugin-hmr';const app = createApp({
container: '#root',
});app.use(createDuskHmr()).startup();
```- ### HMR ([examples/dusk-example-hmr-vite](https://github.com/xams-creator/dusk-examples/tree/master/dusk-example-hmr-vite))
```shell
npm i -D @xams-framework/vite-plugin-dusk
npm i @xams-framework/dusk-plugin-hmr
```- #### vite.config.ts
```tsx
import react from '@vitejs/plugin-react';
import createViteDusk from '@xams-framework/vite-plugin-dusk';
import * as path from 'path';
import postcss from 'postcss-preset-env';
import { defineConfig } from 'vite';
import eslint from 'vite-plugin-eslint';// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
// const env = loadEnv(mode, process.cwd(), '');
return {
server: {
port: 1339,
},
css: {
postcss: {
plugins: [postcss()],
},
},
resolve: {
alias: {
'@': path.join(__dirname, 'src'),
src: path.join(__dirname, 'src'),
},
},
plugins: [react(), createViteDusk(), eslint()],
};
});
```- #### index.tsx
```tsx
import { createApp } from '@xams-framework/dusk';
import createDuskHmr from '@xams-framework/dusk-plugin-hmr';const app = createApp({
container: '#root',
});app.use(createDuskHmr()).startup();
```## Apis
- ### createApp
```tsx
import Dusk, { createApp } from '@xams-framework/dusk';const app = createApp({
container: '#root', // 挂载位置
redux: {
// redux相关配置
logger: {
collapsed: true,
},
},
});app.define(model) // 定义一个模型,可以使用 dusk-plugin-context-webpack,vite 跳过手动定义
.use(createPlugin()) // 使用一个插件
.startup(); // 启动 App
```- ### createDuskModel
```tsx
import { Action, DuskEffectPayloadAction, DuskModel, DuskPayloadAction, createDuskModel } from '@xams-framework/dusk';
import { AnyAction } from 'redux';import { passwordLogin } from '@/common/api';
export interface AppState {
value: number;
pending: boolean;
}const model = createDuskModel({
namespace: 'app', // 唯一命名空间
initialState: {
// 支持函数语法 (namespace)=> initialState,也可以在函数体中根据namespace读本地存储的历史状态
value: 111,
pending: false,
} as AppState,
reducers: {
// 更新 store 数据的 reducers,使用了 immer,因此可以直接修改值。创建完成时会同时创建 model.actions 用来dispatch事件
add(state, action) {
state.value += 1;
},
startLoading(state, action) {
state.pending = true;
},
stopLoading(state, action) {
state.pending = false;
},
},
effects: {
// 异步函数,一般用来发 http 请求。创建完成时会同时创建 model.commands 用来dispatch事件
// state: 当前空间的 state 而不是全局state
// payload: 当前action调用时传的值
// set: 看内部示例,可以在这里直接更新state
// sleep: 配合 await 达到延时处理
// app: 全局app示例,可以配合插件做一些事情
// model: 当前model对象
async add(dispatch, state, { payload }, { set, sleep, app, model }) {
// const res = await passwordLogin();// set((state) => {
// state.pending = false
// })// await sleep(1000);
return 999;
},
async foo(dispatch, state, action) {
const a = dispatch(add(1));
const b = dispatch(model.commands.foo());
const c = dispatch({
type: 'add',
payload: 1,
});
const e = dispatch({
type: 'app/add',
payload: 1,
namespace: 'app',
name: 'add',
effect: false,
scoped: true,
effect123: 1,
});
},
},
// 模型被初始化时执行的事件
onInitialization(state, model, app) {
// 可以使用内置的 hotkeys 做快捷键绑定,需要手动在model被移除时清除,否则容易引发内存问题
app.$hotkeys('ctrl+a', () => {
// 把当前函数放在下一批微任务中执行,此时可以拿到完整的 models
app.$scheduler(() => {
console.log('hello micro task', app.models);
});
});
},
// 模型移除时执行
onFinalize(state, model: DuskModel, app) {
app.$hotkeys.unbind('ctrl+a');
},// 当前空间状态被修改后执行,可以在这里把新状态保存到本地存储
onStateChange() {},
});export const { stopLoading } = model.actions;
export const { add, foo } = model.commands;
export default model;
``````tsx
import { useDispatch } from 'react-redux';import model from './app.model';
const dispatch = useDispatch();
const res = await dispatch(model.commands.add()); // 如果是 commands ,那么返回的类型是 Promise
dispatch(model.actions.add()); // 如果是 actions , 那么则是正常返回
```- ### definePlugin
- 定义一个插件```tsx
import { definePlugin } from '@xams-framework/dusk';export default function createDuskAppPlugin(options: any) {
return definePlugin({
name: 'dusk-plugin-app-hello',
setup(app) {
console.log('插件会在ready前调用');
},
onReady({ app }, next) {
next();
},
//...其他生命周期,参考 dusk-examples 中的几个用例
});
}
``````tsx
import createDuskAppPlugin from './createDuskAppPlugin';app.use(createDuskAppPlugin());
```## Hooks
- ### useDusk
- 函数组件中使用,返回当前app实例```tsx
import { useDusk } from '@xams-framework/dusk';const app = useDusk();
```- ### useNamespacedSelector
- 函数组件中使用,类似于 useSelector,提供一个 namespace 用来返回当前命名空间的state```tsx
import { useNamespacedSelector } from '@xams-framework/dusk';const state = useNamespacedSelector('app'); // model.namespace
```## Plugins
- ### dusk-plugin-loading
- 全局loading插件,dispatch effects 函数时会触发```shell
npm i @xams-framework/dusk-plugin-loading
``````tsx
import createDuskLoading from './index';app.use(createDuskLoading);
``````tsx
const [loading] = useLoading();
// 触发 loading start
app.$store.dispatch(model.commands.add());
// 触发 loading stop
```- ### dusk-plugin-context-webpack
- 使用此组件将会自动注册 src/business/inject 下定义的model,不需要手动define
- webpack(craco)中可以用用 dusk-plugin-context-webpack
- vite可以用 dusk-plugin-context-vite```shell
npm i @xams-framework/dusk-plugin-context-webpack
``````tsx
import createDuskContextWebpack from './index';app.use(createDuskContextWebpack());
```[comment]: <> (- ### )
[comment]: <> (## Examples)
[comment]: <> (- ### [examples/dusk-example-count](https://github.com/xams-creator/xams-framework-frontend/tree/master/examples/dusk-example-count))
[comment]: <> (- ### [examples/dusk-example-routes](https://github.com/xams-creator/xams-framework-frontend/tree/master/examples/dusk-example-routes))
[comment]: <> (- ### [examples/dusk-example-styles](https://github.com/xams-creator/xams-framework-frontend/tree/master/examples/dusk-example-styles))
[comment]: <> (- ### [examples/dusk-example-plugins](https://github.com/xams-creator/xams-framework-frontend/tree/master/examples/dusk-example-plugins))
[comment]: <> (- ### [examples/dusk-example-annotation](https://github.com/xams-creator/xams-framework-frontend/tree/master/examples/dusk-example-annotation))
[comment]: <> (- ### [dusk-example-okr](https://github.com/xams-creator/dusk-example-okr))
[comment]: <> ( https://xams-creator.github.io/dusk-example-okr/)
[comment]: <> ( ```)
[comment]: <> ( username: dusk)
[comment]: <> ( password: dusk)
[comment]: <> ( ```)