In the qiankun
, it is inevitable to encounter communication between applications, such as some customized business requirements based on a certain business format. At this time, it is involved that a certain sub-application needs to know who the current "host" is (identifying which privatization project customized business needs), and to know who the "host" is, the "host" needs to actively inform a certain sub-application , This needs to involve the main and sub-application data communication.
Communication between applications under the micro front end
- Based on the communication method that comes with the
qiankun
api
ininitGlobalState
- Communication method based on tripartite library: such as
@ice/stark-data
for communication
Based on qiankun
own communication method
Based on @ice/stark-data
communication method
The communication mode under the micro-front-end architecture mode based on @ice/stark-data
can realize the communication mode (full duplex) between the main and sub-applications. The performance is as follows:
@/ice/stark-data
>Sub: For this scenario, you can useset
andget
methods of thestore
object in the 061989d03003c8 library- Child -> Main: In view of this scenario, you can use
@/ice/stark-data
libraryevent
objectemit
,on
manner - Sub -> Son: In view of this scenario, you can use
@/ice/stark-data
librarystore
objectset
,get
manner
@ice/stark-data
source code analysis
We know that based on the VueJs
or ReactJs
tripartite state management library vuex
or redux
, the storage of data is stored in the memory (non-persistent). Similarly, when @ice/stark-data
stores data, it is stored based on a namespace combined with a window
object, which is also non-persistent. But @ice/startk-data
implements a simple publish and subscribe mechanism, sharing data between applications through the global window, the content will be relatively simple under normal circumstances
The vuex
and redux
are both state management solutions and they are different in usage scenarios.
Note: The currently parsed source code version is 0.1.3
, warehouse address: https://github.com/ice-lab/icestark/tree/master/packages/icestark-data
The source code of the entire @ice/stark-data
library is actually relatively simple, consisting of the following parts:
utils.ts
: The tool set contains a total of three functionsisObject
,isArray
,warn
, which are used to determine whether a variable is an object, an array type, and a function package for warning message output.cache.ts
setCache
getCache
for access based on the namespaceICESTARK
andwindow
global object encapsulation. The namespace is used here, which can also avoid the pollution problem of variables onwindow
store.ts
: Mainly realize main application and sub-application, sub-application and sub-application one-way data communicationevent.ts
: Mainly realize the sub-application and the main applicationindex.ts
: willstore
,event
for export demand
It can be seen that the core code in the entire library is in the store.ts
and event.ts
, and then the code in these two files will be analyzed specifically.
store.ts
source code analysis
When we need to pass data from the main application to the sub-application, @ice/stark-data
is as follows:
Main application setting data
import { store } from '@ice/stark-data' store.set('someData', 'darkCode')
Sub application receives data
import { store } from '@ice/stark-data' const data: any = store.get('someData')
In store.ts
. Between the lines of code 11
to 14
, an interface IO
set
and get
methods are respectively defined in this interface:
interface IO {
set(key: string | symbol | object, value?: any): void;
get(key?: StringSymbolUnion): void;
}
The set
method receives two parameters, key
is a joint type, and value
is a variable of any type. This method has no return value.
The get
method receives a parameter, and key
is a joint type. This method also has no return value?
20
lines 16
to 061989d0300915, an interface Hooks
And three methods on
, off
, has
are defined in this interface:
interface Hooks {
on(key: StringSymbolUnion, callback: (value: any) => void, force?: boolean): void;
off(key: StringSymbolUnion, callback?: (value: any) => void): void;
has(key: StringSymbolUnion): boolean;
}
The main function of the interface Hooks
is to perform subscription and publication processing for data and "destroy" processing for corresponding "events".
In 22
code, the Store
class is defined, which implements the two interfaces IO
and Hooks
class Store implements IO, Hooks
In class Store
respectively defined store
with storeEmitter
two attributes, and subjected to an initialization operation in the constructor:
store: object;
storeEmitter: object;
constructor() {
this.store = {};
this.storeEmitter = {};
}
Next, two "private" methods are defined, _setValue
and _getValue
to "write" and "output" the "data" respectively.
_getValue(key: StringSymbolUnion) {
return this.store[key];
}
_setValue(key: StringSymbolUnion, value: any) {
this.store[key] = value;
this._emit(key);
}
In _setValue
, first mount the key
attribute to the instance object attribute store
object, and set its value to value
. While the key
by calling _emit
the method _getValue
extracted corresponding values, and the attribute storeEmitter
taken corresponding to "trigger" (in keyEmitter
), and then executes a corresponding correction of its traverse.
Next is the overriding implementation IO
interface set
and get
methods. First look set
method ( 67
line to 84
line) implementation:
set<T>(key: string | symbol | object, value?: T) {
if (typeof key !== 'string'
&& typeof key !== 'symbol'
&& !isObject(key)) {
warn('store.set: key should be string / symbol / object');
return;
}
if (isObject(key)) {
Object.keys(key).forEach(k => {
const v = key[k];
this._setValue(k, v);
});
} else {
this._setValue(key as StringSymbolUnion, value);
}
}
The internal first judges the key
, if it is not one of string
, symbol
, object
return
is performed in between. Conversely, first determine if the key
variable is a object
type, then get the key
"object" and traverse it. k
corresponding to v
in the process of traversal. Call the internal method _setValue
instance object to store the data (value); if key
is not the object type, call the internal method _setValue
instance object to store the data (value).
The get
method is to obtain the corresponding stored data (value) key
key
if it is not one of string
, symbol
, then return null
. Otherwise, call the internal method _getValue
to get the value
The next step is to rewrite the three methods in the Hooks
First look at the first method on
(in 86
row to 106
line):
on(key: StringSymbolUnion, callback: (value: any) => void, force?: boolean) {
if (typeof key !== 'string' && typeof key !== 'symbol') {
warn('store.on: key should be string / symbol');
return;
}
if (callback === undefined || typeof callback !== 'function') {
warn('store.on: callback is required, should be function');
return;
}
if (!this.storeEmitter[key]) {
this.storeEmitter[key] = [];
}
this.storeEmitter[key].push(callback);
if (force) {
callback(this._getValue(key));
}
}
on
method receives three parameters:
key
: The parameterkey
is the combination type ofstring
andsymbol
callback
: The parametercallback
is a callback functionforce
: The parameterforce
is an optional parameter, and the type is aboolean
type
It can be seen from the source code implementation that the main function of the on
method is the process of storing elements storeEmitter
based on the parameters of key
and callback
If the parameter force
is true
, use the parameter key
to obtain the corresponding value from the method _getValue
callback
, and execute the callback function callback
.
For the second method off
(in 108
row to 125
line), achieve the following:
off(key: StringSymbolUnion, callback?: (value: any) => void) {
if (typeof key !== 'string' && typeof key !== 'symbol') {
warn('store.off: key should be string / symbol');
return;
}
if (!isArray(this.storeEmitter[key])) {
warn(`store.off: ${String(key)} has no callback`);
return;
}
if (callback === undefined) {
this.storeEmitter[key] = undefined;
return;
}
this.storeEmitter[key] = this.storeEmitter[key].filter(cb => cb !== callback);
}
off
method receives two parameters:
key
: The parameterkey
is the combination type ofstring
andsymbol
callback
: The parametercallback
is a callback function
As can be seen from the source to achieve, off
primary method of action is based on the object instance storeEmitter
property of binding key
to filter out callback
(similar deleting an element from the array.)
Next, create the variable store
by calling the function getCache
. If the variable store
has no value, call the class Store
create an instance object and assign the store
variable, and mount the variable to window
object storeNameSpace
as the namespace. Finally, the store
variable is derived.
let store = getCache(storeNameSpace);
if (!store) {
store = new Store();
setCache(storeNameSpace, store);
}
export default store;
Small summary:
- When we call
store.set
method by key-value pairs (key
,value
when setting a value in the form of) the internal first determinekey
type, ifkey
object type. Then byObject.keys
method for acquiring all properties on the object, and (traverse extracted attribute for the property setk
) corresponding to a value (v
), then callsstore
inside example_setValue
method corresponding to property (k
) value (v
) Assign a value to the instancestore
attribute. Then the internal method_emit
method is called, and the corresponding value (keyEmitter
,value
) is obtained from the instance attributestoreEmitter
_getValue
according to the attributek
Finally, traversekeyEmitter
(callback function), and execute its callback functionvalue
- In the implementation of the library, the purpose of the use of namespaces is to isolate (directly) cause pollution of the
window
- When we call the
store.get
method to obtain the corresponding value through the key|attribute (key
), the internal will first determine whetherkey
exists, and if it does not exist, then return to the instance object'sstore
attribute; ifkey
exists, but its type is notstring
/symbol
of 061989d0300f9f will returnnull
. On the contrary, call the_getValue
method inside the instance to obtain the corresponding value from the instance attributestore
through the attributekey
- Here, the two attributes
store
andstoreEmitter
Store
class are involved in the operation of the queue in their definition and value access operations. The types of the two properties are both "object" types, but they can also be defined as array types (from the perspective of the implementation role) or better handledWeakMap
event.ts
source code analysis
When processing data from the sub-application to the main application based on @ice/stark-data
Sub application:
import { event } from '@ice/stark-data' event.emit('refreshToken', 'cdacavfsasxxs')
Main application
import { event } from '@ice/stark-data' event.on('refreshToken', (val: any) => { console.log('the value from subApp is:', val) })
This kind of realization is realized with the help of publish and subscribe mode, similar to the communication between the child component and the parent component in VueJs
Next, understand their internal implementation details from the perspective of source code.
In the code of store.ts
6
defines a constant eventNameSpace
in the namespace const eventNameSpace = 'event';
, and the 8
defines a union type StringSymbolUnion
(definition of the type), type StringSymbolUnion = string | symbol;
Then in the 10
row to 15
line defines the interface Hooks
, and defines in its interior four methods are:
emit
:emit(key: StringSymbolUnion, value: any): void;
The role of this method in the implementation phase is to subscribe to "events", traverse all "events" from the queue, and execute the corresponding callbacks.on
:on(key: StringSymbolUnion, callback: (value: any) => void): void;
The function of this method in the implementation order is to store the callback functioncallback
in the queueoff
:off(key: StringSymbolUnion, callback?: (value: any) => void): void;
The function of this method in the implementation stage is to findcallback
from the queue for removal (filtering) operationhas
:has(key: StringSymbolUnion): boolean;
The function of this method in the implementation order is to determine whether the corresponding "value" set exists in the queuekey
The 17
line in the event.ts
file defines the class Event
and implements the Hooks
interface class Event implements Hooks
. The class Event
defines the attribute eventEmitter
and initializes it in the constructor.
eventEmitter: object;
constructor() {
this.eventEmitter = {};
}
The next step is to rewrite the four methods defined in Hooks
Let's first look at the implementation on
on(key: StringSymbolUnion, callback: (value: any) => void) {
if (typeof key !== 'string' && typeof key !== 'symbol') {
warn('event.on: key should be string / symbol');
return;
}
if (callback === undefined || typeof callback !== 'function') {
warn('event.on: callback is required, should be function');
return;
}
if (!this.eventEmitter[key]) {
this.eventEmitter[key] = [];
}
this.eventEmitter[key].push(callback);
}
As can be seen from source on
implementation of the method is also very simple, and store.ts
code class Store
in on
implementation of the method is almost the same. I won't go into details here.
As for the implementation of the other three methods, it is almost the same as the implementation of the corresponding three methods in Store
Finally, by calling the function getCache
to create an object variable of type event
, then event
does not exist (is null, undefined, etc.). Then call the object instance created by the new
Event
assign the value to the variable event
, and call the setCache
function to mount the variable event
based on the namespace constant eventNameSpace
to the window
object. Then export the variable event
(object type).
Summarize
- The implementation of full-duplex communication between the main and sub-applications based on
@ice/stark-data
in the micro-front-end frameworkqiankun
is very simple. The core is based on the publish-subscriber model, distinguished by different namespace variables, and the corresponding attributes (key
) The value of (value
) is mounted on the globalwindow
object, so that in the same "application", as long as you know the corresponding namespace, you can access its corresponding value; @ice/stark-data
source code has some shortcomings, such asHooks
store.ts
andevent.ts
, which did not achieve the effect of reuse (each defined once, unnecessary). In addition, instore.ts
andevent.ts
respectively, theEvent
Store
and 061989d030145f is the same. It is not necessary to implement both of them once. You can write a base class (parent class) and then inheritextends
. It is much better to rewrite the method that needs to be rewritten;- The code robustness processing in the source code is still good, such as the judgment processing
key
in the four methods implemented in theEvent
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。