Skip to content

Commit

Permalink
feat: ❇️ 发布beta版本
Browse files Browse the repository at this point in the history
  • Loading branch information
2534290808 committed Jan 22, 2022
1 parent d577627 commit fa4f19c
Show file tree
Hide file tree
Showing 10 changed files with 562 additions and 64 deletions.
15 changes: 7 additions & 8 deletions packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tanfu-core",
"version": "1.0.0-alpha.2",
"version": "1.0.0-beta.1",
"scripts": {
"start": "dumi dev",
"docs:build": "dumi build",
Expand All @@ -11,14 +11,17 @@
"test": "umi-test",
"test:coverage": "umi-test --coverage",
"prepublishOnly": "npm run build",
"publish:alpha": "npm publish --tag=alpha --registry=https://registry.npmjs.org"
"publish:alpha": "npm publish --tag=alpha --registry=https://registry.npmjs.org",
"publish:beta": "npm publish --tag=beta --registry=https://registry.npmjs.org"
},
"module": "es/index.js",
"typings": "es/index.d.ts",
"gitHooks": {
"pre-commit": "lint-staged"
},
"files": ["es"],
"files": [
"es"
],
"lint-staged": {
"*.{js,jsx,less,md,json}": [
"prettier --write"
Expand All @@ -30,13 +33,9 @@
"dependencies": {
"immer": "^9.0.12",
"lodash.get": "^4.4.2",
"lodash.set": "^4.3.2",
"react": "^16.12.0 || ^17.0.0"
"lodash.set": "^4.3.2"
},
"devDependencies": {
"@testing-library/jest-dom": "^5.15.1",
"@testing-library/react": "^12.1.2",
"@types/jest": "^27.0.3",
"@types/lodash.get": "*",
"@types/lodash.set": "*",
"@umijs/fabric": "^2.8.1",
Expand Down
13 changes: 13 additions & 0 deletions packages/core/src/controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Engine } from "./engine";

// 控制器,负责处理业务逻辑,并处理数据模型和view的交互(MVC中的C)
export default abstract class Controller {

/** 设置了name的Controller可以被替换 */
getName(): string | void {
}

apply(engine: Engine, controller: Controller) {

}
}
23 changes: 13 additions & 10 deletions packages/core/src/engine.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import set from 'lodash.set';
import get from 'lodash.get';
import { produce } from 'immer'
import Plugin from './plugin';
import Controller from './controller';

// 定义元素id类型
type ElementId<VM extends ViewModel = ViewModel> = StringKeys<keyof VM>;
Expand Down Expand Up @@ -55,17 +55,18 @@ type PickNotFunction<T> = {
[K in keyof T as (T[K] extends (Function | undefined) ? never : K)]: T[K]
}


/** 暴露给控制器 */
export interface Engine<VM extends ViewModel = ViewModel> extends Pick<CoreEngine<VM>, 'setState' | 'getState' | 'watchElement' | 'injectCallback' | 'didMount' | 'willUnmount'> {

}

/** 核心引擎 */
export default class CoreEngine<VM extends ViewModel = ViewModel> {
_watchFns: Record<string, Record<DependencyProperty, Array<WatchFunction>>>
_callBackFns: Record<string, Record<InJectCallBackName, Array<InJectCallBackFunction>>>
_forceUpdate: Partial<Record<ElementId<VM>, ForceUpdate>>
_store: Record<string, any>
_plugins: Map<string | Plugin, Plugin>
_controllers: Map<string | Controller, Controller>
_elements: Partial<Record<ElementId<VM>, any>>
_didMountFns: Record<string, Array<DidMountFunction>>
_willUnmountFns: Record<string, Array<WillUnmountFunction>>
Expand All @@ -74,7 +75,7 @@ export default class CoreEngine<VM extends ViewModel = ViewModel> {
this._callBackFns = {};
this._forceUpdate = {};
this._store = {};
this._plugins = new Map();
this._controllers = new Map();
this._elements = {}
this._didMountFns = {}
this._willUnmountFns = {}
Expand All @@ -91,11 +92,13 @@ export default class CoreEngine<VM extends ViewModel = ViewModel> {
}
}

/** 组件加载完成 */
didMount(elementId: ElementId<VM>, fn: DidMountFunction) {
if (!this._didMountFns[elementId]) this._didMountFns[elementId] = [];
this._didMountFns[elementId].push(fn)
}

/** 组件卸载完成 */
willUnmount(elementId: ElementId<VM>, fn: WillUnmountFunction) {
if (!this._willUnmountFns[elementId]) this._willUnmountFns[elementId] = [];
this._willUnmountFns[elementId].push(fn)
Expand All @@ -106,12 +109,12 @@ export default class CoreEngine<VM extends ViewModel = ViewModel> {
this._elements = Object.assign({}, this._elements, elements)
}

/** 注册plugin */
registerPlugin(plugins: Plugin[]) {
plugins.forEach(plugin => {
this._plugins.set(plugin.getName() || plugin, plugin)
/** 使用controller */
useControllers(controllers: Controller[]) {
controllers.forEach(controller => {
this._controllers.set(controller.getName() || controller, controller)
})
this._plugins.forEach(plugin => plugin.apply(this.toEngine() as Engine))
this._controllers.forEach(controller => controller.apply(this.toEngine() as Engine, controller))
}

/** 设置状态 */
Expand All @@ -136,7 +139,7 @@ export default class CoreEngine<VM extends ViewModel = ViewModel> {
}

/** 监听元素属性变化 */
watchElement(elementId: ElementId<VM>, fn: WatchFunction, deps: string[]) {
watchElement<E extends ElementId<VM>>(elementId: E, fn: WatchFunction, deps: StringKeys<keyof PickNotFunction<VM[E]>>[]) {
if (!this._watchFns[elementId]) this._watchFns[elementId] = {}
deps?.forEach(dep => {
if (!this._watchFns[elementId][dep]) this._watchFns[elementId][dep] = []
Expand Down
16 changes: 14 additions & 2 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,14 @@
export { default as CoreEngine } from './engine'
export { default as Plugin } from './plugin'
import Tanfu, { Plugin, GLOBAL_ELEMENTS_KEY } from "./tanfu";
import CoreEngine, { Engine } from "./engine";
import Controller from "./controller";
export default Tanfu
export {
CoreEngine,
Engine,
Controller,
Plugin,
GLOBAL_ELEMENTS_KEY
}



13 changes: 0 additions & 13 deletions packages/core/src/plugin.ts

This file was deleted.

49 changes: 49 additions & 0 deletions packages/core/src/tanfu.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import Controller from "./controller"
import CoreEngine from "./engine"

// 函数式插件
type PluginFunction = () => void
// 对象式插件
type PluginObject = { install: () => void }
// 插件
export type Plugin = PluginFunction | PluginObject
// 存储全局元素
const globalElements: Record<string, any> = {}

export const GLOBAL_ELEMENTS_KEY = '__$_TANFU_GLOBAL_ELEMENTS_$__'

export interface Tanfu {
Controller: typeof Controller;
CoreEngine: typeof CoreEngine;
/** 使用插件 */
use: (plugin: Plugin) => void;
/** 注册元素 */
element: (elementId: string, ui: any) => void;
/** 设置controller的原型 */
setPrototypeOfController: (key: string, value: any) => void
}

const tanfu: Tanfu = {
Controller,
CoreEngine,
use(plugin: Plugin) {
if (typeof plugin === 'function') plugin()
else plugin?.install()
},
element(elementId, ui) {
globalElements[elementId] = ui
},
setPrototypeOfController(key, value) {
//@ts-ignore
Controller.prototype[key] = value
},

/**
* 全局组件注册,不建议外部使用
*/
// @ts-ignore
[GLOBAL_ELEMENTS_KEY]: globalElements
}


export default tanfu;
5 changes: 3 additions & 2 deletions packages/react/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tanfu-react",
"version": "1.0.0-alpha.2",
"version": "1.0.0-beta.1",
"scripts": {
"start": "dumi dev",
"docs:build": "dumi build",
Expand All @@ -11,7 +11,8 @@
"test": "umi-test",
"test:coverage": "umi-test --coverage",
"prepublishOnly": "npm run build",
"publish:alpha": "npm publish --tag=alpha --registry=https://registry.npmjs.org"
"publish:alpha": "npm publish --tag=alpha --registry=https://registry.npmjs.org",
"publish:beta": "npm publish --tag=beta --registry=https://registry.npmjs.org"
},
"files": ["es"],
"module": "es/index.js",
Expand Down
29 changes: 23 additions & 6 deletions packages/react/src/Foo/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
import React from 'react';
import { createUI, createContainer, Engine, Plugin } from '../index'
import Tanfu, { createUI, createContainer, Engine, Controller, Template } from '../index'
export default ({ title }: { title: string }) => <Root />;

interface ControllerIntance extends Controller {
getMyName: string
}

class PluginA extends Plugin {
apply(engine: Engine<ViewModel>): void {
Tanfu.use(function () {
Tanfu.setPrototypeOfController('getMyName', 'dsasfsafds')
})
Tanfu.use(function () {
Tanfu.element('myelementId', function ({ text }) {
return <div>这是我的自定义组件{text}</div>
})
})

class ControllerA extends Controller {
apply(engine: Engine<ViewModel>, controller: ControllerIntance): void {
engine.didMount('elementA', () => {
console.log('a加载完成了')
})
Expand All @@ -15,7 +27,10 @@ class PluginA extends Plugin {
console.log('点击了')
engine.setState({
elementA: {
text: '点击了'
text: controller.getMyName
},
myelementId: {
text: '黎明宇'
}
})
})
Expand All @@ -26,18 +41,20 @@ class PluginA extends Plugin {
}
}

const Root = createContainer([new PluginA], function () {
const Root = createContainer(function () {
return (
<div>
<A elementId='elementA' />
<Template elementId='myelementId' />
<B elementId='elementB' />
</div>
)
})
}, [new ControllerA()])

type ViewModel = {
elementA: Aprops,
elementB: Bprops,
myelementId: Aprops
}

type Aprops = {
Expand Down
55 changes: 42 additions & 13 deletions packages/react/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,60 @@
import React, { useContext, useEffect, useMemo, useReducer, useRef } from 'react';
import { CoreEngine, Plugin } from 'tanfu-core';
export { Engine } from 'tanfu-core/es/engine';
export { default as Plugin } from 'tanfu-core/es/plugin'
import TanfuCore, { CoreEngine, Controller, GLOBAL_ELEMENTS_KEY } from 'tanfu-core';
export { Controller, Engine, Plugin } from 'tanfu-core'
import get from 'lodash.get'

const Tanfu: Tanfu = TanfuCore
// 重写element方法,使用createUI包裹
Tanfu.element = function (elementId: string, ui: React.ComponentType<any>) {
// @ts-ignore
Tanfu[GLOBAL_ELEMENTS_KEY][elementId] = createUI(ui)
}

export type Tanfu = Omit<typeof TanfuCore, 'element'> & {
element: (elementId: string, ui: React.ComponentType<any>) => void
}

export default Tanfu;


// @ts-ignore
const ReactViewContext = React.createContext<CoreEngine>(null);

export function ReactView({ children, plugins = [] }: { children: React.ReactChild, plugins: Plugin[] }) {
/** 如果注册了全局组件可用这个进行渲染 ,默认渲染children */
export function Template(props: { elementId: string, children?: React.ReactChild }) {
const { elementId, children } = props
// @ts-ignore
const RenderUI = TanfuCore[GLOBAL_ELEMENTS_KEY][elementId]
return <>{RenderUI ? <RenderUI elementId={elementId} /> : children}</>
}

/** 包裹React视图组件,生成CoreEngine并执行控制器 */
export function ReactView({ children, controllers = [] }: { children: React.ReactChild, controllers?: Controller[] }) {
const engine = useMemo(() => {
const engine = new CoreEngine();
engine.registerPlugin(plugins);
engine.useControllers(controllers);
return engine;
}, [])
return <ReactViewContext.Provider value={engine}>{children}</ReactViewContext.Provider>
}

ReactView.displayName = '$REACT_VIEW$'

export function createContainer<P = {}>(plugins: any[], UI: React.ComponentType<P>) {
return createElement(plugins, UI, ReactView)
/** 创建容器组件 */
export function createContainer<P = {}>(UI: React.ComponentType<P>, controllers: Controller[]) {
return createElement(controllers, UI, ReactView)
}


function createElement<P = {}>(plugins: any[], UI: React.ComponentType<P>, ReactView: React.ComponentType<any> = React.Fragment) {
/** 创建视图元素 */
function createElement<P = {}>(controllers: Controller[], UI: React.ComponentType<P>, ReactView: React.ComponentType<any> = React.Fragment) {
const Element = React.memo(function (props: React.ComponentProps<typeof UI> & { elementId?: string }) {
const { elementId, ...others } = props
// 获取engien
const engine = useContext(ReactViewContext)

// 获取元素state
const state = elementId ? engine?.getState(elementId) : {}

// 构建injectCallback生成的回调属性
const callbackFnProps = useMemo(() => {
if (elementId && engine?._callBackFns[elementId]) {
const callbackFns = engine?._callBackFns[elementId];
Expand All @@ -46,7 +71,10 @@ function createElement<P = {}>(plugins: any[], UI: React.ComponentType<P>, React
return _callbackFnProps;
}
return {}
}, [])
}, [others])

// 元素属性,注意:直接值元素设置的属性值会覆盖使用engine.setState设置的元素值,
// 如果想两种方式都生效,需要使用受控的模式进行更新属性
const elementProps = Object.assign({}, state, { elementId, ...others, ...callbackFnProps })
const previousProps = usePrevious(elementProps)
const forceUpdate = useForceUpdate();
Expand All @@ -73,13 +101,14 @@ function createElement<P = {}>(plugins: any[], UI: React.ComponentType<P>, React
}
}, [])
const RenderUI = engine?._elements?.[elementId || ''] || UI
const reactViewProps: { plugins?: Plugin[] } = {};
if (ReactView.displayName === '$REACT_VIEW$') reactViewProps['plugins'] = plugins
const reactViewProps: { controllers?: Controller[] } = {};
if (ReactView.displayName === '$REACT_VIEW$') reactViewProps['controllers'] = controllers
return <ReactView {...reactViewProps}><RenderUI {...elementProps} /></ReactView>;
})
return Element;
}

/** 创建UI组件 */
export function createUI<P = {}>(UI: React.ComponentType<P>) {
return createElement([], UI)
}
Expand Down
Loading

0 comments on commit fa4f19c

Please sign in to comment.