@ddm-center/create-plugin 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -0
- package/bin/create-plugin.js +143 -0
- package/package.json +16 -0
- package/templates/mixed-js/README.md.tpl +10 -0
- package/templates/mixed-js/jsconfig.json.tpl +13 -0
- package/templates/mixed-js/package.json.tpl +31 -0
- package/templates/mixed-js/src/i18n/index.js.tpl +15 -0
- package/templates/mixed-js/src/main/index.js.tpl +31 -0
- package/templates/mixed-js/src/renderer/index.js.tpl +39 -0
- package/templates/mixed-js/src/renderer/views/Settings.vue.tpl +35 -0
- package/templates/mixed-js/webpack.config.js.tpl +48 -0
- package/templates/mixed-ts/README.md.tpl +11 -0
- package/templates/mixed-ts/package.json.tpl +34 -0
- package/templates/mixed-ts/src/i18n/index.ts.tpl +19 -0
- package/templates/mixed-ts/src/main/index.ts.tpl +39 -0
- package/templates/mixed-ts/src/renderer/index.ts.tpl +49 -0
- package/templates/mixed-ts/src/renderer/views/Settings.vue.tpl +43 -0
- package/templates/mixed-ts/src/types/vue.d.ts.tpl +4 -0
- package/templates/mixed-ts/tsconfig.json.tpl +17 -0
- package/templates/mixed-ts/webpack.config.js.tpl +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# @ddm-center/create-plugin
|
|
2
|
+
|
|
3
|
+
`@ddm-center/create-plugin` 是 Dubbo Desktop Manager 的插件工程脚手架。
|
|
4
|
+
|
|
5
|
+
它只创建一种推荐工程形态:`renderer + main` mixed 插件。单独 renderer 或单独 main 的插件可以在生成后自行删除不需要的入口。
|
|
6
|
+
|
|
7
|
+
## 创建 TypeScript 插件
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm create @ddm-center/plugin my-plugin -- --ts
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## 创建 JavaScript 插件
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm create @ddm-center/plugin my-plugin -- --js
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
如果插件名没有 `ddm-plugin-` 前缀,脚手架会自动补齐。例如 `my-plugin` 会生成 `ddm-plugin-my-plugin`。
|
|
20
|
+
|
|
21
|
+
## 生成目录
|
|
22
|
+
|
|
23
|
+
TypeScript 模板会生成:
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
ddm-plugin-my-plugin/
|
|
27
|
+
src/main/index.ts
|
|
28
|
+
src/renderer/index.ts
|
|
29
|
+
src/renderer/views/Settings.vue
|
|
30
|
+
src/i18n/index.ts
|
|
31
|
+
package.json
|
|
32
|
+
tsconfig.json
|
|
33
|
+
webpack.config.js
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
JavaScript 模板会生成:
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
ddm-plugin-my-plugin/
|
|
40
|
+
src/main/index.js
|
|
41
|
+
src/renderer/index.js
|
|
42
|
+
src/renderer/views/Settings.vue
|
|
43
|
+
src/i18n/index.js
|
|
44
|
+
package.json
|
|
45
|
+
jsconfig.json
|
|
46
|
+
webpack.config.js
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## 常用命令
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npm install
|
|
53
|
+
npm run build
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
TypeScript 模板额外提供:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm run typecheck
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## 入口约定
|
|
63
|
+
|
|
64
|
+
生成的插件包含三个入口:
|
|
65
|
+
|
|
66
|
+
- `main`:主进程入口,默认输出 `dist/main.js`。
|
|
67
|
+
- `rendererMain`:渲染进程入口,默认输出 `dist/renderer.js`。
|
|
68
|
+
- `i18nMain`:国际化入口,默认输出 `dist/i18n.js`。
|
|
69
|
+
|
|
70
|
+
`package.json` 中会自动写入:
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"main": "dist/main.js",
|
|
75
|
+
"rendererMain": "dist/renderer.js",
|
|
76
|
+
"i18nMain": "dist/i18n.js"
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## 类型提示
|
|
81
|
+
|
|
82
|
+
生成的插件默认依赖:
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"devDependencies": {
|
|
87
|
+
"@ddm-center/plugin-api": "^0.0.1"
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`@ddm-center/plugin-api` 提供 `appMain`、`appView`、`MainEntry`、`RendererEntry` 等类型提示。运行时对象仍由 DDM 宿主注入。
|
|
93
|
+
|
|
94
|
+
## 参数
|
|
95
|
+
|
|
96
|
+
- `--ts`:创建 TypeScript mixed 插件。
|
|
97
|
+
- `--js`:创建 JavaScript mixed 插件。
|
|
98
|
+
- `--language=ts`:等同于 `--ts`。
|
|
99
|
+
- `--language=js`:等同于 `--js`。
|
|
100
|
+
- `--force`:目标目录不为空时仍然写入。
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const readline = require('readline');
|
|
6
|
+
|
|
7
|
+
const TEMPLATE_ROOT = path.join(__dirname, '..', 'templates');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 只解析脚手架需要的少量参数,避免引入额外命令行依赖。
|
|
11
|
+
*/
|
|
12
|
+
function parseArgs(argv) {
|
|
13
|
+
const result = {
|
|
14
|
+
name: null,
|
|
15
|
+
language: null,
|
|
16
|
+
force: false,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
argv.forEach(arg => {
|
|
20
|
+
if (arg === '--force' || arg === '-f') {
|
|
21
|
+
result.force = true;
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (arg.startsWith('--language=')) {
|
|
26
|
+
result.language = arg.slice('--language='.length);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (arg === '--js') {
|
|
31
|
+
result.language = 'js';
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (arg === '--ts') {
|
|
36
|
+
result.language = 'ts';
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!result.name) {
|
|
41
|
+
result.name = arg;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 没有传插件名或语言时,用交互问题补齐。
|
|
50
|
+
*/
|
|
51
|
+
function ask(question) {
|
|
52
|
+
const rl = readline.createInterface({
|
|
53
|
+
input: process.stdin,
|
|
54
|
+
output: process.stdout,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return new Promise(resolve => {
|
|
58
|
+
rl.question(question, answer => {
|
|
59
|
+
rl.close();
|
|
60
|
+
resolve(answer.trim());
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* DDM 插件默认使用 ddm-plugin- 前缀,scope 包名保留用户输入。
|
|
67
|
+
*/
|
|
68
|
+
function normalizePluginName(name) {
|
|
69
|
+
const normalized = name.trim().toLowerCase().replace(/[^a-z0-9-_./@]/g, '-').replace(/--+/g, '-');
|
|
70
|
+
if (!normalized) {
|
|
71
|
+
throw new Error('插件名称不能为空');
|
|
72
|
+
}
|
|
73
|
+
return normalized.startsWith('ddm-plugin-') || normalized.startsWith('@') ? normalized : `ddm-plugin-${normalized}`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 根据包名生成一个适合展示在插件列表里的默认名称。
|
|
78
|
+
*/
|
|
79
|
+
function toTitle(name) {
|
|
80
|
+
const rawName = name.includes('/') ? name.split('/').pop() : name;
|
|
81
|
+
return rawName.replace(/^ddm-plugin-/, '').split(/[-_]/).filter(Boolean).map(item => item.charAt(0).toUpperCase() + item.slice(1)).join(' ');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 模板文件统一用 .tpl 后缀,复制时替换占位符并去掉后缀。
|
|
86
|
+
*/
|
|
87
|
+
function copyTemplate(sourceDir, targetDir, variables) {
|
|
88
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
89
|
+
|
|
90
|
+
fs.readdirSync(sourceDir, { withFileTypes: true }).forEach(entry => {
|
|
91
|
+
const sourcePath = path.join(sourceDir, entry.name);
|
|
92
|
+
const targetName = entry.name.replace(/\.tpl$/, '');
|
|
93
|
+
const targetPath = path.join(targetDir, targetName);
|
|
94
|
+
|
|
95
|
+
if (entry.isDirectory()) {
|
|
96
|
+
copyTemplate(sourcePath, targetPath, variables);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
let content = fs.readFileSync(sourcePath, 'utf8');
|
|
101
|
+
Object.keys(variables).forEach(key => {
|
|
102
|
+
content = content.replace(new RegExp(`__${key}__`, 'g'), variables[key]);
|
|
103
|
+
});
|
|
104
|
+
fs.writeFileSync(targetPath, content);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* 创建 mixed 插件工程:主进程、渲染进程和 i18n 入口一起生成。
|
|
110
|
+
*/
|
|
111
|
+
async function main() {
|
|
112
|
+
const args = parseArgs(process.argv.slice(2));
|
|
113
|
+
const inputName = args.name || await ask('插件名称: ');
|
|
114
|
+
const pluginName = normalizePluginName(inputName);
|
|
115
|
+
const languageInput = args.language || await ask('语言(js/ts,默认 ts): ');
|
|
116
|
+
const language = (languageInput || 'ts').toLowerCase();
|
|
117
|
+
|
|
118
|
+
if (!['js', 'ts', 'javascript', 'typescript'].includes(language)) {
|
|
119
|
+
throw new Error('language 只支持 js 或 ts');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const templateName = language.startsWith('j') ? 'mixed-js' : 'mixed-ts';
|
|
123
|
+
const targetDir = path.resolve(process.cwd(), pluginName.includes('/') ? pluginName.split('/').pop() : pluginName);
|
|
124
|
+
|
|
125
|
+
if (fs.existsSync(targetDir) && !args.force && fs.readdirSync(targetDir).length > 0) {
|
|
126
|
+
throw new Error(`目标目录已存在且不为空: ${targetDir}`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
copyTemplate(path.join(TEMPLATE_ROOT, templateName), targetDir, {
|
|
130
|
+
PLUGIN_NAME: pluginName,
|
|
131
|
+
PLUGIN_TITLE: toTitle(pluginName),
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
console.log(`已创建 ${pluginName}`);
|
|
135
|
+
console.log(`cd ${path.basename(targetDir)}`);
|
|
136
|
+
console.log('npm install');
|
|
137
|
+
console.log('npm run build');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
main().catch(error => {
|
|
141
|
+
console.error(error.message);
|
|
142
|
+
process.exit(1);
|
|
143
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ddm-center/create-plugin",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Create a mixed renderer and main plugin project for Dubbo Desktop Manager.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"create-plugin": "bin/create-plugin.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"README.md",
|
|
10
|
+
"bin",
|
|
11
|
+
"templates"
|
|
12
|
+
],
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=14"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"allowJs": true,
|
|
4
|
+
"baseUrl": ".",
|
|
5
|
+
"moduleResolution": "node",
|
|
6
|
+
"paths": {
|
|
7
|
+
"appMain": ["node_modules/@ddm-center/plugin-api/appMain.d.ts"],
|
|
8
|
+
"appView": ["node_modules/@ddm-center/plugin-api/appView.d.ts"]
|
|
9
|
+
},
|
|
10
|
+
"types": ["@ddm-center/plugin-api"]
|
|
11
|
+
},
|
|
12
|
+
"include": ["src/**/*"]
|
|
13
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PLUGIN_NAME__",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "__PLUGIN_TITLE__ plugin for Dubbo Desktop Manager.",
|
|
5
|
+
"pluginNickName": "__PLUGIN_TITLE__",
|
|
6
|
+
"main": "dist/main.js",
|
|
7
|
+
"rendererMain": "dist/renderer.js",
|
|
8
|
+
"i18nMain": "dist/i18n.js",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "webpack --mode production",
|
|
11
|
+
"dev": "webpack --mode development --watch"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@ddm-center/plugin-api": "^0.0.1",
|
|
16
|
+
"css-loader": "^6.11.0",
|
|
17
|
+
"vue": "^2.6.14",
|
|
18
|
+
"vue-loader": "^15.11.1",
|
|
19
|
+
"vue-style-loader": "^4.1.3",
|
|
20
|
+
"vue-template-compiler": "^2.6.14",
|
|
21
|
+
"webpack": "^5.92.0",
|
|
22
|
+
"webpack-cli": "^5.1.4"
|
|
23
|
+
},
|
|
24
|
+
"pluginSandbox": {
|
|
25
|
+
"permissions": {
|
|
26
|
+
"require": {
|
|
27
|
+
"allow": []
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* i18n 入口用于注册当前插件自己的语言包。
|
|
3
|
+
*/
|
|
4
|
+
export default function installI18n(registrar) {
|
|
5
|
+
return {
|
|
6
|
+
async install() {
|
|
7
|
+
registrar.addPluginLocaleMessage('zh-CN', {
|
|
8
|
+
title: '__PLUGIN_TITLE__',
|
|
9
|
+
});
|
|
10
|
+
registrar.addPluginLocaleMessage('en-US', {
|
|
11
|
+
title: '__PLUGIN_TITLE__',
|
|
12
|
+
});
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import appMain from 'appMain';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 主进程入口由 DDM 宿主加载。
|
|
5
|
+
*/
|
|
6
|
+
export default function installMain() {
|
|
7
|
+
return {
|
|
8
|
+
async install() {
|
|
9
|
+
appMain.logger.info('__PLUGIN_TITLE__ main installed');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 暴露给渲染进程调用的服务,渲染端通过 referenceService('helloService') 获取。
|
|
13
|
+
*/
|
|
14
|
+
appMain.exportPluginService('helloService', {
|
|
15
|
+
async sayHello(name) {
|
|
16
|
+
return {
|
|
17
|
+
message: `Hello ${name || 'DDM'} from ${appMain.pluginName}`,
|
|
18
|
+
time: new Date().toISOString(),
|
|
19
|
+
};
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 插件卸载时宿主会优先调用 uninstall,可在这里释放资源。
|
|
26
|
+
*/
|
|
27
|
+
async uninstall() {
|
|
28
|
+
appMain.logger.info('__PLUGIN_TITLE__ main uninstalled');
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import appView from 'appView';
|
|
2
|
+
import Settings from './views/Settings.vue';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 渲染进程入口由 DDM 宿主加载。
|
|
6
|
+
*/
|
|
7
|
+
export default function installRenderer() {
|
|
8
|
+
return {
|
|
9
|
+
async install() {
|
|
10
|
+
/**
|
|
11
|
+
* 调用主进程通过 exportPluginService 暴露的服务。
|
|
12
|
+
*/
|
|
13
|
+
const helloService = appView.referenceService('helloService');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 注册一个插件设置页,Settings 组件会被宿主自动注入插件上下文。
|
|
17
|
+
*/
|
|
18
|
+
appView.addPluginSettingPage({
|
|
19
|
+
label: '__PLUGIN_TITLE__',
|
|
20
|
+
component: Settings,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 注册标题栏菜单,演示渲染进程调用主进程服务后发通知。
|
|
25
|
+
*/
|
|
26
|
+
appView.addToolbarMenu({
|
|
27
|
+
label: '__PLUGIN_TITLE__',
|
|
28
|
+
icon: 'plugin',
|
|
29
|
+
click: async () => {
|
|
30
|
+
const result = await helloService.sayHello('__PLUGIN_TITLE__');
|
|
31
|
+
appView.notify({
|
|
32
|
+
title: '__PLUGIN_TITLE__',
|
|
33
|
+
body: result.message,
|
|
34
|
+
});
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="ddm-plugin-settings">
|
|
3
|
+
<h3>{{ title }}</h3>
|
|
4
|
+
<p>{{ message }}</p>
|
|
5
|
+
<el-button size="mini" type="primary" @click="loadMessage">调用主进程服务</el-button>
|
|
6
|
+
</div>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script>
|
|
10
|
+
import appView from 'appView';
|
|
11
|
+
|
|
12
|
+
const helloService = appView.referenceService('helloService');
|
|
13
|
+
|
|
14
|
+
export default {
|
|
15
|
+
name: 'PluginSettings',
|
|
16
|
+
data() {
|
|
17
|
+
return {
|
|
18
|
+
title: '__PLUGIN_TITLE__',
|
|
19
|
+
message: 'Ready',
|
|
20
|
+
};
|
|
21
|
+
},
|
|
22
|
+
methods: {
|
|
23
|
+
async loadMessage() {
|
|
24
|
+
const result = await helloService.sayHello(this.title);
|
|
25
|
+
this.message = result.message;
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<style scoped>
|
|
32
|
+
.ddm-plugin-settings {
|
|
33
|
+
padding: 12px;
|
|
34
|
+
}
|
|
35
|
+
</style>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const { VueLoaderPlugin } = require('vue-loader');
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
target: 'electron-renderer',
|
|
6
|
+
entry: {
|
|
7
|
+
main: './src/main/index.js',
|
|
8
|
+
renderer: './src/renderer/index.js',
|
|
9
|
+
i18n: './src/i18n/index.js',
|
|
10
|
+
},
|
|
11
|
+
output: {
|
|
12
|
+
path: path.resolve(__dirname, 'dist'),
|
|
13
|
+
filename: '[name].js',
|
|
14
|
+
library: {
|
|
15
|
+
type: 'commonjs2',
|
|
16
|
+
export: 'default',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
resolve: {
|
|
20
|
+
extensions: ['.js', '.vue', '.json'],
|
|
21
|
+
alias: {
|
|
22
|
+
'@': path.resolve(__dirname, 'src'),
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
externals: {
|
|
26
|
+
appMain: 'commonjs appMain',
|
|
27
|
+
appView: 'commonjs appView',
|
|
28
|
+
axios: 'commonjs axios',
|
|
29
|
+
constant: 'commonjs constant',
|
|
30
|
+
logger: 'commonjs logger',
|
|
31
|
+
appConfig: 'commonjs appConfig',
|
|
32
|
+
},
|
|
33
|
+
module: {
|
|
34
|
+
rules: [
|
|
35
|
+
{
|
|
36
|
+
test: /\.vue$/,
|
|
37
|
+
loader: 'vue-loader',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
test: /\.css$/,
|
|
41
|
+
use: ['vue-style-loader', 'css-loader'],
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
plugins: [
|
|
46
|
+
new VueLoaderPlugin(),
|
|
47
|
+
],
|
|
48
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PLUGIN_NAME__",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "__PLUGIN_TITLE__ plugin for Dubbo Desktop Manager.",
|
|
5
|
+
"pluginNickName": "__PLUGIN_TITLE__",
|
|
6
|
+
"main": "dist/main.js",
|
|
7
|
+
"rendererMain": "dist/renderer.js",
|
|
8
|
+
"i18nMain": "dist/i18n.js",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "webpack --mode production",
|
|
11
|
+
"dev": "webpack --mode development --watch",
|
|
12
|
+
"typecheck": "tsc --noEmit"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@ddm-center/plugin-api": "^0.0.1",
|
|
17
|
+
"css-loader": "^6.11.0",
|
|
18
|
+
"ts-loader": "^9.5.1",
|
|
19
|
+
"typescript": "^5.4.5",
|
|
20
|
+
"vue": "^2.6.14",
|
|
21
|
+
"vue-loader": "^15.11.1",
|
|
22
|
+
"vue-style-loader": "^4.1.3",
|
|
23
|
+
"vue-template-compiler": "^2.6.14",
|
|
24
|
+
"webpack": "^5.92.0",
|
|
25
|
+
"webpack-cli": "^5.1.4"
|
|
26
|
+
},
|
|
27
|
+
"pluginSandbox": {
|
|
28
|
+
"permissions": {
|
|
29
|
+
"require": {
|
|
30
|
+
"allow": []
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { I18nRegistrar, PluginInstallable } from '@ddm-center/plugin-api';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* i18n 入口用于注册当前插件自己的语言包。
|
|
5
|
+
*/
|
|
6
|
+
function installI18n(registrar: I18nRegistrar): PluginInstallable {
|
|
7
|
+
return {
|
|
8
|
+
async install() {
|
|
9
|
+
registrar.addPluginLocaleMessage('zh-CN', {
|
|
10
|
+
title: '__PLUGIN_TITLE__',
|
|
11
|
+
});
|
|
12
|
+
registrar.addPluginLocaleMessage('en-US', {
|
|
13
|
+
title: '__PLUGIN_TITLE__',
|
|
14
|
+
});
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default installI18n;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import appMain from 'appMain';
|
|
2
|
+
import type { MainEntry } from '@ddm-center/plugin-api';
|
|
3
|
+
|
|
4
|
+
interface HelloResult {
|
|
5
|
+
message: string;
|
|
6
|
+
time: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 主进程入口由 DDM 宿主加载。
|
|
11
|
+
*/
|
|
12
|
+
const entry: MainEntry = () => {
|
|
13
|
+
return {
|
|
14
|
+
async install() {
|
|
15
|
+
appMain.logger.info('__PLUGIN_TITLE__ main installed');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 暴露给渲染进程调用的服务,渲染端通过 referenceService('helloService') 获取。
|
|
19
|
+
*/
|
|
20
|
+
appMain.exportPluginService('helloService', {
|
|
21
|
+
async sayHello(name?: string): Promise<HelloResult> {
|
|
22
|
+
return {
|
|
23
|
+
message: `Hello ${name || 'DDM'} from ${appMain.pluginName}`,
|
|
24
|
+
time: new Date().toISOString(),
|
|
25
|
+
};
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 插件卸载时宿主会优先调用 uninstall,可在这里释放资源。
|
|
32
|
+
*/
|
|
33
|
+
async uninstall() {
|
|
34
|
+
appMain.logger.info('__PLUGIN_TITLE__ main uninstalled');
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export default entry;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import appView from 'appView';
|
|
2
|
+
import type { RendererEntry } from '@ddm-center/plugin-api';
|
|
3
|
+
import Settings from './views/Settings.vue';
|
|
4
|
+
|
|
5
|
+
interface HelloService {
|
|
6
|
+
sayHello(name?: string): Promise<{
|
|
7
|
+
message: string;
|
|
8
|
+
time: string;
|
|
9
|
+
}>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 渲染进程入口由 DDM 宿主加载。
|
|
14
|
+
*/
|
|
15
|
+
const entry: RendererEntry = () => {
|
|
16
|
+
return {
|
|
17
|
+
async install() {
|
|
18
|
+
/**
|
|
19
|
+
* 调用主进程通过 exportPluginService 暴露的服务。
|
|
20
|
+
*/
|
|
21
|
+
const helloService = appView.referenceService<HelloService>('helloService');
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 注册一个插件设置页,Settings 组件会被宿主自动注入插件上下文。
|
|
25
|
+
*/
|
|
26
|
+
appView.addPluginSettingPage({
|
|
27
|
+
label: '__PLUGIN_TITLE__',
|
|
28
|
+
component: Settings,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 注册标题栏菜单,演示渲染进程调用主进程服务后发通知。
|
|
33
|
+
*/
|
|
34
|
+
appView.addToolbarMenu({
|
|
35
|
+
label: '__PLUGIN_TITLE__',
|
|
36
|
+
icon: 'plugin',
|
|
37
|
+
click: async () => {
|
|
38
|
+
const result = await helloService.sayHello('__PLUGIN_TITLE__');
|
|
39
|
+
appView.notify({
|
|
40
|
+
title: '__PLUGIN_TITLE__',
|
|
41
|
+
body: result.message,
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export default entry;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="ddm-plugin-settings">
|
|
3
|
+
<h3>{{ title }}</h3>
|
|
4
|
+
<p>{{ message }}</p>
|
|
5
|
+
<el-button size="mini" type="primary" @click="loadMessage">调用主进程服务</el-button>
|
|
6
|
+
</div>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script lang="ts">
|
|
10
|
+
import Vue from 'vue';
|
|
11
|
+
import appView from 'appView';
|
|
12
|
+
|
|
13
|
+
interface HelloService {
|
|
14
|
+
sayHello(name?: string): Promise<{
|
|
15
|
+
message: string;
|
|
16
|
+
time: string;
|
|
17
|
+
}>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const helloService = appView.referenceService<HelloService>('helloService');
|
|
21
|
+
|
|
22
|
+
export default Vue.extend({
|
|
23
|
+
name: 'PluginSettings',
|
|
24
|
+
data() {
|
|
25
|
+
return {
|
|
26
|
+
title: '__PLUGIN_TITLE__',
|
|
27
|
+
message: 'Ready',
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
methods: {
|
|
31
|
+
async loadMessage() {
|
|
32
|
+
const result = await helloService.sayHello(this.title);
|
|
33
|
+
this.message = result.message;
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<style scoped>
|
|
40
|
+
.ddm-plugin-settings {
|
|
41
|
+
padding: 12px;
|
|
42
|
+
}
|
|
43
|
+
</style>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2019",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"strict": true,
|
|
6
|
+
"esModuleInterop": true,
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"moduleResolution": "node",
|
|
9
|
+
"baseUrl": ".",
|
|
10
|
+
"paths": {
|
|
11
|
+
"appMain": ["node_modules/@ddm-center/plugin-api/appMain.d.ts"],
|
|
12
|
+
"appView": ["node_modules/@ddm-center/plugin-api/appView.d.ts"]
|
|
13
|
+
},
|
|
14
|
+
"types": ["@ddm-center/plugin-api"]
|
|
15
|
+
},
|
|
16
|
+
"include": ["src/**/*"]
|
|
17
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const { VueLoaderPlugin } = require('vue-loader');
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
target: 'electron-renderer',
|
|
6
|
+
entry: {
|
|
7
|
+
main: './src/main/index.ts',
|
|
8
|
+
renderer: './src/renderer/index.ts',
|
|
9
|
+
i18n: './src/i18n/index.ts',
|
|
10
|
+
},
|
|
11
|
+
output: {
|
|
12
|
+
path: path.resolve(__dirname, 'dist'),
|
|
13
|
+
filename: '[name].js',
|
|
14
|
+
library: {
|
|
15
|
+
type: 'commonjs2',
|
|
16
|
+
export: 'default',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
resolve: {
|
|
20
|
+
extensions: ['.ts', '.js', '.vue', '.json'],
|
|
21
|
+
alias: {
|
|
22
|
+
'@': path.resolve(__dirname, 'src'),
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
externals: {
|
|
26
|
+
appMain: 'commonjs appMain',
|
|
27
|
+
appView: 'commonjs appView',
|
|
28
|
+
axios: 'commonjs axios',
|
|
29
|
+
constant: 'commonjs constant',
|
|
30
|
+
logger: 'commonjs logger',
|
|
31
|
+
appConfig: 'commonjs appConfig',
|
|
32
|
+
},
|
|
33
|
+
module: {
|
|
34
|
+
rules: [
|
|
35
|
+
{
|
|
36
|
+
test: /\.vue$/,
|
|
37
|
+
loader: 'vue-loader',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
test: /\.ts$/,
|
|
41
|
+
loader: 'ts-loader',
|
|
42
|
+
options: {
|
|
43
|
+
appendTsSuffixTo: [/\.vue$/],
|
|
44
|
+
},
|
|
45
|
+
exclude: /node_modules/,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
test: /\.css$/,
|
|
49
|
+
use: ['vue-style-loader', 'css-loader'],
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
plugins: [
|
|
54
|
+
new VueLoaderPlugin(),
|
|
55
|
+
],
|
|
56
|
+
};
|