@vcmap/plugin-cli 4.0.0-rc.5 → 4.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 +125 -21
- package/assets/testsTypescript/vcsPluginInterface.spec.ts +3 -5
- package/assets/vitest.config.js +1 -2
- package/package.json +7 -7
- package/src/serve.js +11 -1
- package/src/update.js +18 -4
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
> Part of the [VC Map Project](https://github.com/virtualcitySYSTEMS/map-ui)
|
|
4
4
|
|
|
5
|
-
>
|
|
6
|
-
>
|
|
7
|
-
>
|
|
5
|
+
> Note: This documentation is for version @vcmap/ui 6.0.0, compatible with the [VC Map](https://github.com/virtualcitySYSTEMS/map-ui).
|
|
6
|
+
>
|
|
7
|
+
> [Migration Guide](https://github.com/virtualcitySYSTEMS/map-ui/blob/release-v6.0/MIGRATION_V6.md) for Plugins from @vcmap/ui 5.0.0
|
|
8
8
|
|
|
9
9
|
The `@vcmap/plugin-cli` helps develop and build plugins for the **VC Map**.
|
|
10
10
|
|
|
@@ -18,7 +18,7 @@ The `@vcmap/plugin-cli` helps develop and build plugins for the **VC Map**.
|
|
|
18
18
|
|
|
19
19
|
## Prerequisite
|
|
20
20
|
|
|
21
|
-
You need [nodejs](https://nodejs.org/en/)
|
|
21
|
+
You need [nodejs](https://nodejs.org/en/) 20 and npm installed on your system
|
|
22
22
|
to use this tool.
|
|
23
23
|
|
|
24
24
|
## Installation
|
|
@@ -161,21 +161,25 @@ To build your project, run the following from within your projects root:
|
|
|
161
161
|
npx vcmplugin build
|
|
162
162
|
```
|
|
163
163
|
|
|
164
|
-
This will build your
|
|
164
|
+
This will build your plugin and place it in the `dist` directory.
|
|
165
165
|
|
|
166
166
|
### 6. Integrating a plugin in a productive VC MAP
|
|
167
167
|
|
|
168
|
-
To
|
|
168
|
+
To bundle your project for productive use, run the following from within your projects root:
|
|
169
169
|
|
|
170
170
|
```bash
|
|
171
|
-
npx vcmplugin
|
|
171
|
+
npx vcmplugin bundle
|
|
172
172
|
```
|
|
173
173
|
|
|
174
|
-
This will create a
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
174
|
+
This will create a `dist` folder with your bundled code and assets.
|
|
175
|
+
|
|
176
|
+
Using the VC Publisher you can simply upload the `tar.gz` file from the dist folder within your administration "Map Plugins" tab.
|
|
177
|
+
Afterward you can add the plugin to your app using the app-configurator.
|
|
178
|
+
|
|
179
|
+
Without using the VC Publisher you can also deploy a plugin manually:
|
|
180
|
+
|
|
181
|
+
- Unzip the `tar.gz` on a server
|
|
182
|
+
- Add the plugin to a module configuration plugins section, specifying a `name` and `entry` property (path to the plugin location)
|
|
179
183
|
|
|
180
184
|
## vcm config js
|
|
181
185
|
|
|
@@ -339,22 +343,33 @@ configuration of the plugin as its first argument and the base URL (without the
|
|
|
339
343
|
from which the plugin was loaded as its second argument.
|
|
340
344
|
|
|
341
345
|
```typescript
|
|
342
|
-
declare type
|
|
343
|
-
|
|
346
|
+
declare type PluginConfigEditorComponent<C extends Object> = VueComponent<{
|
|
347
|
+
getConfig(): C;
|
|
348
|
+
setConfig(config?: C): void;
|
|
349
|
+
}>;
|
|
350
|
+
|
|
351
|
+
declare type PluginConfigEditor<C extends Object> = {
|
|
352
|
+
component: PluginConfigEditorComponent<C>;
|
|
353
|
+
title?: string;
|
|
344
354
|
collectionName?: string;
|
|
345
355
|
itemName?: string;
|
|
356
|
+
infoUrlCallback?: () => string;
|
|
346
357
|
};
|
|
347
358
|
|
|
348
359
|
declare interface VcsPlugin<T extends Object, S extends Object> {
|
|
349
360
|
readonly name: string;
|
|
350
361
|
readonly version: string;
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
362
|
+
readonly mapVersion: string;
|
|
363
|
+
i18n?: {
|
|
364
|
+
[x: string]: unknown;
|
|
365
|
+
};
|
|
366
|
+
initialize?: (app: VcsUiApp, state?: S) => Promise<void>;
|
|
367
|
+
onVcsAppMounted?: (app: VcsUiApp) => Promise<void>;
|
|
368
|
+
toJSON?: () => T;
|
|
369
|
+
getDefaultOptions?: () => T;
|
|
370
|
+
getState?: () => S | Promise<S>;
|
|
371
|
+
getConfigEditors?: () => Array<PluginConfigEditor<object>>;
|
|
372
|
+
destroy?: () => void;
|
|
358
373
|
}
|
|
359
374
|
|
|
360
375
|
declare function defaultExport<T extends Object, S extends Object>(
|
|
@@ -402,6 +417,95 @@ export default function defaultExport(config, baseUrl) {
|
|
|
402
417
|
}
|
|
403
418
|
```
|
|
404
419
|
|
|
420
|
+
### Plugin Config Editor
|
|
421
|
+
|
|
422
|
+
Part of the [plugin interface](#plugin-interface) is the option to provide one or more custom config editors.
|
|
423
|
+
These config editors will be used in the VC Publisher to define the configuration of a plugin or a plugin custom class, like a custom layer or feature info.
|
|
424
|
+
If a plugin does not provide a config editor, the JsonEditor is always used as fallback.
|
|
425
|
+
|
|
426
|
+
To provide a custom editor, the plugin has to implement a `getConfigEditors` method returning one or more editors.
|
|
427
|
+
A plugin config editor definition consists of
|
|
428
|
+
|
|
429
|
+
- component: The vue component providing the ui of the editor. This vue component has to extend the `AbstractConfigEditor.vue`, which can be imported from `@vcmap/ui`. The component has to provide two props: `getConfig` for getting the serialized configuration and `setConfig` to update the changed configuration.
|
|
430
|
+
- title: An optional title displayed in the window header of the editor and on action buttons (e.g. tooltip)
|
|
431
|
+
- collectionName: The collection the item belongs to. Default is `plugins` collection. For a layer config editor you would provide `layers`.
|
|
432
|
+
- itemName: The item the editor can be used for. Can be a name or className. Default is the plugin's name. For a layer you would provide `MyNewLayer.className`.
|
|
433
|
+
- infoUrlCallback: An optional function returning an url referencing help or further information regarding the config editor.
|
|
434
|
+
|
|
435
|
+
An example of plugin config editor can look like this:
|
|
436
|
+
|
|
437
|
+
```vue
|
|
438
|
+
<template>
|
|
439
|
+
<AbstractConfigEditor @submit="apply" v-bind="{ ...$attrs, ...$props }">
|
|
440
|
+
<VcsFormSection heading="general" expandable :start-open="true">
|
|
441
|
+
<v-container class="py-0 px-1">
|
|
442
|
+
<v-row no-gutters>
|
|
443
|
+
<v-col>
|
|
444
|
+
<VcsLabel html-for="someProp">
|
|
445
|
+
{{ $t('myPlugin.someProp') }}
|
|
446
|
+
</VcsLabel>
|
|
447
|
+
</v-col>
|
|
448
|
+
<v-col>
|
|
449
|
+
<VcsTextField id="someProp" v-model="localConfig.someProp" />
|
|
450
|
+
</v-col>
|
|
451
|
+
</v-row>
|
|
452
|
+
</v-container>
|
|
453
|
+
</VcsFormSection>
|
|
454
|
+
</AbstractConfigEditor>
|
|
455
|
+
</template>
|
|
456
|
+
|
|
457
|
+
<script>
|
|
458
|
+
import { VContainer, VRow, VCol } from 'vuetify/components';
|
|
459
|
+
import {
|
|
460
|
+
AbstractConfigEditor,
|
|
461
|
+
VcsFormSection,
|
|
462
|
+
VcsLabel,
|
|
463
|
+
VcsTextField,
|
|
464
|
+
} from '@vcmap/ui';
|
|
465
|
+
import { ref } from 'vue';
|
|
466
|
+
import { getDefaultOptions } from '../defaultOptions.js';
|
|
467
|
+
|
|
468
|
+
export default {
|
|
469
|
+
name: 'MyPluginConfigEditor',
|
|
470
|
+
components: {
|
|
471
|
+
VContainer,
|
|
472
|
+
VRow,
|
|
473
|
+
VCol,
|
|
474
|
+
AbstractConfigEditor,
|
|
475
|
+
VcsFormSection,
|
|
476
|
+
VcsLabel,
|
|
477
|
+
VcsTextField,
|
|
478
|
+
},
|
|
479
|
+
props: {
|
|
480
|
+
getConfig: {
|
|
481
|
+
type: Function,
|
|
482
|
+
required: true,
|
|
483
|
+
},
|
|
484
|
+
setConfig: {
|
|
485
|
+
type: Function,
|
|
486
|
+
required: true,
|
|
487
|
+
},
|
|
488
|
+
},
|
|
489
|
+
setup(props) {
|
|
490
|
+
const defaultOptions = getDefaultOptions();
|
|
491
|
+
const config = props.getConfig();
|
|
492
|
+
const localConfig = ref({ ...defaultOptions, ...config });
|
|
493
|
+
|
|
494
|
+
const apply = () => {
|
|
495
|
+
props.setConfig(localConfig.value);
|
|
496
|
+
};
|
|
497
|
+
|
|
498
|
+
return {
|
|
499
|
+
localConfig,
|
|
500
|
+
apply,
|
|
501
|
+
};
|
|
502
|
+
},
|
|
503
|
+
};
|
|
504
|
+
</script>
|
|
505
|
+
|
|
506
|
+
<style scoped></style>
|
|
507
|
+
```
|
|
508
|
+
|
|
405
509
|
### About Plugin Assets
|
|
406
510
|
|
|
407
511
|
Plugin assets are considered to be static files, such as images, fonts etc. which shall be
|
|
@@ -9,18 +9,16 @@ function sleep(ms = 0): Promise<void> {
|
|
|
9
9
|
});
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
type TestPluginInstance = VcsPlugin<
|
|
12
|
+
type TestPluginInstance = VcsPlugin<object, object>;
|
|
13
13
|
|
|
14
|
-
//
|
|
15
|
-
// @ts-ignore
|
|
14
|
+
// @ts-expect-error: not defined on global
|
|
16
15
|
window.VcsPluginLoaderFunction = (
|
|
17
16
|
name: string,
|
|
18
17
|
module: string,
|
|
19
18
|
): {
|
|
20
19
|
default: () => TestPluginInstance;
|
|
21
20
|
} => ({
|
|
22
|
-
//
|
|
23
|
-
// @ts-ignore
|
|
21
|
+
// @ts-expect-error: interface may not use this
|
|
24
22
|
default: () => plugin({ name }, module),
|
|
25
23
|
});
|
|
26
24
|
|
package/assets/vitest.config.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vcmap/plugin-cli",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"description": "A CLI to help develop and build plugins for the VC Map",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -31,19 +31,19 @@
|
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@vcmap/rollup-plugin-vcs-ol": "^1.0.2",
|
|
33
33
|
"@vcsuite/cli-logger": "^1.0.0",
|
|
34
|
-
"@vitejs/plugin-vue": "^5.1.
|
|
34
|
+
"@vitejs/plugin-vue": "^5.1.4",
|
|
35
35
|
"commander": "^10.0.1",
|
|
36
|
-
"express": "^4.21.
|
|
36
|
+
"express": "^4.21.1",
|
|
37
37
|
"prompts": "^2.4.2",
|
|
38
|
-
"sass": "^1.
|
|
38
|
+
"sass": "^1.80.2",
|
|
39
39
|
"semver": "^7.5.4",
|
|
40
40
|
"tar": "^7.4.3",
|
|
41
|
-
"vite": "^5.4.
|
|
41
|
+
"vite": "^5.4.9",
|
|
42
42
|
"vite-plugin-vuetify": "^2.0.4"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
|
-
"@vcmap/ui": "^6.0.0
|
|
46
|
-
"vue": "~3.4.
|
|
45
|
+
"@vcmap/ui": "^6.0.0",
|
|
46
|
+
"vue": "~3.4.38"
|
|
47
47
|
},
|
|
48
48
|
"peerDependenciesMeta": {
|
|
49
49
|
"@vcmap/ui": {
|
package/src/serve.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
-
import { readFile } from 'fs/promises';
|
|
2
|
+
import { lstat, readFile } from 'fs/promises';
|
|
3
3
|
import { createServer } from 'vite';
|
|
4
4
|
import vue from '@vitejs/plugin-vue';
|
|
5
5
|
import express from 'express';
|
|
@@ -101,6 +101,8 @@ export default async function serve(options) {
|
|
|
101
101
|
const mergedOptions = { ...vcmConfigJs, ...options };
|
|
102
102
|
|
|
103
103
|
await printVcmapUiVersion();
|
|
104
|
+
const uiLStat = await lstat(resolveMapUi());
|
|
105
|
+
|
|
104
106
|
/*
|
|
105
107
|
// In case @vcmap/ui is linked via git+ssh, dist folder is not available and must be built first
|
|
106
108
|
// Currently not needed, keep it here if the same problem happens again
|
|
@@ -147,6 +149,7 @@ export default async function serve(options) {
|
|
|
147
149
|
tinyqueue: 'tinyqueue/tinyqueue.js',
|
|
148
150
|
},
|
|
149
151
|
dedupe: Object.keys(peerDependencies),
|
|
152
|
+
preserveSymlinks: uiLStat.isSymbolicLink(),
|
|
150
153
|
},
|
|
151
154
|
optimizeDeps: {
|
|
152
155
|
exclude: [
|
|
@@ -158,6 +161,13 @@ export default async function serve(options) {
|
|
|
158
161
|
],
|
|
159
162
|
include: optimizationIncludes,
|
|
160
163
|
},
|
|
164
|
+
css: {
|
|
165
|
+
preprocessorOptions: {
|
|
166
|
+
scss: {
|
|
167
|
+
api: 'modern-compiler', // or "modern", "legacy"
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
},
|
|
161
171
|
plugins: [vue(), createConfigJsonReloadPlugin()],
|
|
162
172
|
server: {
|
|
163
173
|
middlewareMode: true,
|
package/src/update.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { logger } from '@vcsuite/cli-logger';
|
|
2
|
-
import { validRange, prerelease } from 'semver';
|
|
2
|
+
import { validRange, maxSatisfying, prerelease } from 'semver';
|
|
3
3
|
import {
|
|
4
4
|
checkVcMapVersion,
|
|
5
5
|
DepType,
|
|
@@ -36,17 +36,31 @@ export async function updatePeerDependencies(
|
|
|
36
36
|
);
|
|
37
37
|
options.mapVersion = 'latest';
|
|
38
38
|
}
|
|
39
|
-
let viewCmd =
|
|
39
|
+
let viewCmd =
|
|
40
|
+
'npm view @vcmap/ui --json peerDependencies devDependencies version name';
|
|
40
41
|
if (options.mapVersion) {
|
|
41
|
-
viewCmd = `npm view @vcmap/ui@${options.mapVersion} --json`;
|
|
42
|
+
viewCmd = `npm view @vcmap/ui@${options.mapVersion} --json peerDependencies devDependencies version name`;
|
|
42
43
|
}
|
|
43
44
|
const { stdout, stderr } = await promiseExec(viewCmd);
|
|
44
45
|
logger.error(stderr);
|
|
46
|
+
const npmVersions = JSON.parse(stdout);
|
|
47
|
+
let npmVersion = null;
|
|
48
|
+
if (Array.isArray(npmVersions)) {
|
|
49
|
+
const versions = npmVersions.map((v) => v.version);
|
|
50
|
+
const versionToUse = maxSatisfying(versions, options.mapVersion);
|
|
51
|
+
npmVersion = npmVersions.find((v) => v.version === versionToUse);
|
|
52
|
+
} else {
|
|
53
|
+
npmVersion = npmVersions;
|
|
54
|
+
}
|
|
55
|
+
if (!npmVersion) {
|
|
56
|
+
console.log(`could not find @vcmap/ui version for ${options.mapVersion}`);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
45
59
|
const {
|
|
46
60
|
name: mapName,
|
|
47
61
|
peerDependencies: mapPeer,
|
|
48
62
|
devDependencies: mapDev,
|
|
49
|
-
} =
|
|
63
|
+
} = npmVersion;
|
|
50
64
|
const peerDeps = [`${mapName}@${options.mapVersion || 'latest'}`]; // @vcmap/ui is a required peer dep and will be updated in any case
|
|
51
65
|
if (pluginPeer) {
|
|
52
66
|
const pluginPeerDeps = Object.keys(pluginPeer)
|