# @epmkit/epm-extend-core

> Core library of EPM extension plugin mechanism.

Latest version **1.3.3** (published 2024-04-02) · private license · 0 weekly downloads

## Install

```sh
npm install @epmkit/epm-extend-core
pnpm add @epmkit/epm-extend-core
yarn add @epmkit/epm-extend-core
bun add @epmkit/epm-extend-core
```

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 1.3.3 |
| Published | 2024-04-02 |
| First published | 2023-09-15 |
| Weekly downloads | 0 |
| License | private |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 0 |
| Unpacked size | 26.3 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Author | gaoxiangq |
| Maintainers | luckyliuyz, mangon_cn |
| Keywords | epm, extend, library |

## Links

- npm: https://www.npmjs.com/package/@epmkit/epm-extend-core
- Repository: https://git.yonyou.com/gaoxiangq/epm-extend-core
- npm.io page: https://npm.io/package/@epmkit/epm-extend-core

## Recent versions

- 1.3.3 (latest) — 2024-04-02
- 1.3.2 — 2023-11-18
- 1.3.1 — 2023-11-18
- 1.3.0 — 2023-11-03
- 1.2.1 — 2023-09-15

## README

## epm-extend-core

该项目为 EPM 扩展机制核心库

执行 `npm install @epmkit/epm-extend-core` 来引入该库。

## 开发

### npm start

执行 `npm start` 进行开发

public 目录下的文件并不是用来发布的，而是调试用的例子插件。

### npm run build

执行 `npm run build` 进行编译

## 使用

### 核心库引入

在宿主环境中执行 `npm install @epmkit/epm-extend-core` 来引入该库。
与该库配套使用的 `@epmkit/cra-template-epm-plugin` 用来创建插件仓库。

### 在节点中使用 Extend 机制

引入方法如下所示：

```jsx
import React, { useEffect, useState } from 'react';
import Extend from '@epmkit/epm-extend-core';

const ExtendContext = React.createContext('Extend');

// 在节点中
function App() {

	const [ExtendInstance, setExtendInstance] = useState(new Extend());

	useEffect(() => {
		async function initExtend() {
			cosnt config = await fetchPluginList(nodeCode); // 获取当前节点的插件插槽配置
			ExtendInstance.init(config);
			setExtendInstance(ExtendInstance);
		}
		initExtend();
		return () => {
			ExtendInstance.dispose();
		};
	}, []);

	return (
		<ExtendContext.Provider value={ExtendInstance.Slot}>
			<ChildElement />
		</ExtendContext.Provider>
	);
}

// 在组件中
function ChildElement() {
	const Slot = React.useContext(ExtendContext);

	// 可针对单个插槽关闭 js 沙箱
	return <Slot name='slot-name' sandbox={false} fn={{
		fnAAA: () => {/* 事件回调 */},
		fnBBB: () => {/* 事件回调 */}
	}} data={{
		dataAAA: '', // 传递数据
		dataBBB: {}
	}} />;
}
```

1. 在节点的最外层执行 `React.createContext('Extend')` 创建扩展机制执行上下文
2. 在节点中执行 `new Extend(options)` 创建 扩展机制实例 ExtendInstance

    扩展机制支持对一些配置进行自定义设置，具体可设置属性如下：

    | 字段            | 含义                         | 类型    | 默认值                                                                |
    | --------------- | ---------------------------- | ------- | --------------------------------------------------------------------- |
    | defaultStyleUrl | 默认样式CSS地址              | string  | `//design.yonyoucloud.com/static/tinper-next/release/tinper-next.css` |
    | windowScope     | 插件绑定到window对象上的属性 | string  | `epmPlugin`                                                           |
    | sandbox         | 是否开启js沙箱               | boolean | `true`                                                                |

3. 在适当的时机执行实例的 `init` 方法，并传入插件插槽配置。`init` 时传入的 `config` 变量为当前节点的插件插槽配置项，需要符合特定的数据结构，以下为例子：

    ```js
    config = {
    	pluginList: [
    		{
    			name: 'aSmallBtn',
    			scriptEntry: 'http://localhost:3030/plugin-aSmallBtn.e76d9341.js',
    			styleEntry: 'http://localhost:3030/plugin-aSmallBtn.ababa1e9.css',
    			version: '1.3.0',
				sandbox: false,
    		},
    		{
    			name: 'aSelectExample',
    			scriptEntry: 'http://localhost:3030/plugin-aSelectExample.e86c0e5e.js',
    			styleEntry: 'http://localhost:3030/plugin-aSelectExample.5df6a4d9.css',
    			chunks: ['http://localhost:3030/js/plugin-chunk.155.cb4c80ac.js'],
    			version: '1.4.1',
    		},
    	],
    	slotList: [
    		{
    			name: 'slot-a',
    			plugins: ['aSelectExample', 'aSmallBtn'],
    		},
    		{
    			name: 'slot-b',
    			plugins: ['aSelectExample'],
    		},
    		{
    			name: 'slot-c',
    			plugins: [{ name: 'aSelectExample', version: '1.4.1' }],
    		},
    	],
    };
    ```

    各字段含义如下

    | 字段               | 含义                                                  | 类型                   | 例子                                                        | 是否必需 |
    | ------------------ | ----------------------------------------------------- | ---------------------- | ----------------------------------------------------------- | -------- |
    | pluginList         | 当前节点的插件列表                                    | Array\<Plugin>         | -                                                           | √        |
    | Plugin.name        | 插件名                                                | string                 | aSmallBtn                                                   | √        |
    | Plugin.scriptEntry | 插件脚本文件入口地址                                  | string                 | `http://localhost:3030/plugin-aSmallBtn.e76d9341.js`        | √        |
    | Plugin.styleEntry  | 插件样式文件入口地址                                  | string                 | `http://localhost:3030/plugin-aSmallBtn.ababa1e9.css`       | -        |
    | Plugin.chunks      | 插件的分包                                            | Array\<URL>            | `['http://localhost:3030/js/plugin-chunk.155.cb4c80ac.js']` | -        |
    | Plugin.version     | 插件的版本                                            | string                 | 1.3.0                                                       | -        |
    | Plugin.sandbox     | 是否开启沙箱，默认开启，可设置为 false 对单个插件关闭 | boolean                | false                                                       | -        |
    | slotList           | 当前节点的插槽配置                                    | Array\<Slot>           | -                                                           | √        |
    | Slot.name          | 插槽名                                                | string                 | slot-a                                                      | √        |
    | Slot.plugins       | 当前插槽的插件列表                                    | Array\<string\|Plugin> | -                                                           | √        |

4. 将扩展机制实例的插槽 `ExtendInstance.Slot` 作为上下文的值传递给子组件
5. 在子组件适当的位置使用 `<Slot name='slot-name' />` 注入插槽

### 插件开发

EPM 扩展机制核心库是和插件配置来使用的，插槽的开发者使用核心库来配置插槽和传递的数据方法，插件开发者需要开发插件来注入应用。
插件开发者执行 `npx create-react-app ${plugin-repo-name} --template @epmkit/cra-template-epm-plugin` 来创建插件仓库，其中 `${plugin-repo-name}` 为插件仓库的名称。

插件的开发同普通 React 组件开发方式相同，只不过组件的 props 是通过插槽传递过来的数据。

一个插件例子如下：

```jsx
export default function SamllBtn({ fn, data, emit, on }) {
	const { btnName, isBtnShow } = data;
	const { hideBtn, showBtn } = fn;

	useEffect(() => {
		on('anotherPlugin:message', payload => {
			console.log('receiveMessage', payload);
		});
	}, []);

	const handleClick = useCallback(() => {
		if (isBtnShow) {
			hideBtn();
			return;
		}
		showBtn();
		emit('smallBtnClick', !isBtnShow);
	}, [hideBtn, isBtnShow, showBtn]);

	return (
		<Button
			className='plugin-btn'
			style={{ width: 400 }}
			onClick={handleClick}
			type='primary'>{`${btnName}按钮`}</Button>
	);
}
```

插件的 props 含义如下：

| 字段名 | 含义                                                                                                                                 | 例子                                     |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------- |
| fn     | 由插槽定义的方法，通过执行方法改变页面状态                                                                                           | -                                        |
| data   | 由插槽传递的数据，获取当前插槽传递的实时数据                                                                                         | -                                        |
| emit   | 插件间通信方法，发送事件与数据                                                                                                       | `emit('event', data)`                    |
| on     | 插件间通信方法，监听其他插件发送的事件并对载荷做出处理<br/>需要注意的是，监听时需要带上监听的插件名，插件名和事件之间以冒号 `:` 连接 | `on('pluginName:event', (payload) =>{})` |

---
_Source: https://npm.io/package/@epmkit/epm-extend-core · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
