@vcmap/plugin-cli 2.0.7 → 2.0.10
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/LICENSE.md +1 -1
- package/README.md +99 -15
- package/assets/helloWorld/.gitlab-ci.yml +72 -3
- package/assets/helloWorld/build/staging/Dockerfile +2 -0
- package/assets/helloWorld/plugin-assets/vcs_logo.png +0 -0
- package/assets/helloWorld/src/helloWorld.vue +19 -5
- package/assets/helloWorld/src/index.js +15 -4
- package/cli.js +9 -1
- package/index.js +1 -0
- package/package.json +6 -7
- package/src/build.js +7 -3
- package/src/buildStagingApp.js +58 -0
- package/src/create.js +55 -29
- package/src/hostingHelpers.js +10 -0
- package/src/pack.js +1 -34
- package/src/preview.js +2 -0
- package/src/serve.js +2 -1
- package/assets/helloWorld/.gitignore +0 -2
package/LICENSE.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Copyright
|
|
1
|
+
Copyright 2022 virtualcitySYSTEMS GmbH
|
|
2
2
|
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
4
|
|
package/README.md
CHANGED
|
@@ -79,7 +79,32 @@ By default, this will launch a dev server at localhost:5005 using the @vcmap/ui
|
|
|
79
79
|
as its base. Alternatively you can provide a URL to a hosted VC Map application
|
|
80
80
|
and use said application as its base instead.
|
|
81
81
|
|
|
82
|
-
### 4. Building a plugin
|
|
82
|
+
### 4. Building a plugin staging application
|
|
83
|
+
|
|
84
|
+
A staging application creates a full deployable VC Map in the `dist` folder with the following components.
|
|
85
|
+
- compiled @vcmap/ui library and all dependencies
|
|
86
|
+
- default @vcmap/ui configurations
|
|
87
|
+
- default @vcmap/ui plugins
|
|
88
|
+
- compiled plugin which is in development.
|
|
89
|
+
|
|
90
|
+
Building the staging application will collect all parts and will inject the plugin in development in the default
|
|
91
|
+
map configuration. The staging application can for example be used to deploy the App in an Apache in a postCommit
|
|
92
|
+
Pipeline. (See .gitlab-ci.yml for an example).
|
|
93
|
+
```bash
|
|
94
|
+
npx vcmplugin buildStagingApp
|
|
95
|
+
```
|
|
96
|
+
To start a webserver to serve the content of the `dist` folder call `npx vite preview`; This will start a static webserver
|
|
97
|
+
on the port 4173.
|
|
98
|
+
|
|
99
|
+
The Dockerfile in `build/staging/Dockerfile` can be used to create a Docker Container which serves the content of the dist folder.
|
|
100
|
+
```bash
|
|
101
|
+
npx vcmplugin buildStagingApp
|
|
102
|
+
cd dist
|
|
103
|
+
docker build -f ../build/staging/Dockerfile -t vcmap:staging .
|
|
104
|
+
docker run --rm -p 5000:80 vcmap:staging
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### 5. Building a plugin
|
|
83
108
|
|
|
84
109
|
To build your project, run the following from within your projects root:
|
|
85
110
|
```bash
|
|
@@ -87,7 +112,7 @@ npx vcmplugin build
|
|
|
87
112
|
```
|
|
88
113
|
This will build your application and place it in the `dist` directory.
|
|
89
114
|
|
|
90
|
-
###
|
|
115
|
+
### 6. Integrating a plugin in a productive VC MAP
|
|
91
116
|
|
|
92
117
|
To pack your project for productive use, run the following from within your projects root:
|
|
93
118
|
```bash
|
|
@@ -114,7 +139,6 @@ as peer dependencies if you use them in your plugin:
|
|
|
114
139
|
- @vcmap/cesium
|
|
115
140
|
- ol
|
|
116
141
|
- vue
|
|
117
|
-
- @vue/composition-api
|
|
118
142
|
- vuetify
|
|
119
143
|
|
|
120
144
|
During the build step, these libraries are automatically externalized by the vcmplugin-cli and in
|
|
@@ -154,6 +178,7 @@ to create your project, a template already adhering to these specs will be creat
|
|
|
154
178
|
- `config.json` with default parameters for the plugins' configuration.
|
|
155
179
|
- `README.md` describing the plugins' capabilities and usage.
|
|
156
180
|
- `src/index.js` JS entry point.
|
|
181
|
+
- A plugin _may_ provide static plugin assets in a `plugin-assets` directory. (See [About Plugin Assets](#About-Plugin-Assets)
|
|
157
182
|
- Plugin names are defined by the plugins' package name and therefore must obey npm [package name guidelines](https://docs.npmjs.com/package-name-guidelines):
|
|
158
183
|
- choose a name that
|
|
159
184
|
- is unique
|
|
@@ -167,7 +192,7 @@ to create your project, a template already adhering to these specs will be creat
|
|
|
167
192
|
- Plugin dependencies have to be defined in the `package.json`.
|
|
168
193
|
- `dependency`: all plugin specific dependencies NOT provided by the `@vcmap/ui`.
|
|
169
194
|
- `peerDependency`: dependencies provided by the `@vcmap/ui`,
|
|
170
|
-
- e.g. `@vcmap/core` or `@vcmap/ui` (see [About Peer Dependencies](#
|
|
195
|
+
- e.g. `@vcmap/core` or `@vcmap/ui` (see [About Peer Dependencies](#About-Peer-Dependencies) for more details)
|
|
171
196
|
- `devDependency`: all dependencies only required for development, e.g. `eslint`.
|
|
172
197
|
- Plugins can be published to NPM, but should contain both source and minified code
|
|
173
198
|
to allow seamless integration into the [VC Map UI](https://github.com/virtualcitySYSTEMS/map-ui) environment.
|
|
@@ -179,22 +204,24 @@ For this reason the package.json of a plugin defines two exports:
|
|
|
179
204
|
}
|
|
180
205
|
```
|
|
181
206
|
|
|
182
|
-
|
|
183
207
|
### Plugin Interface:
|
|
184
208
|
Plugins must provide a function default export which returns an Object complying
|
|
185
|
-
with the VC Map Plugin Interface describe below
|
|
209
|
+
with the VC Map Plugin Interface describe below. This function is passed the current
|
|
210
|
+
configuration of the plugin as its first argument and the base URL (without the filename)
|
|
211
|
+
from which the plugin was loaded as its second argument.
|
|
186
212
|
|
|
187
213
|
```typescript
|
|
188
|
-
declare interface VcsPlugin<T extends Object> {
|
|
214
|
+
declare interface VcsPlugin<T extends Object, S extends Object> {
|
|
189
215
|
readonly name: string;
|
|
190
216
|
readonly version: string;
|
|
191
|
-
initialize(app: VcsUiApp):void
|
|
192
|
-
onVcsAppMounted(app: VcsUiApp):void
|
|
193
|
-
|
|
217
|
+
initialize(app: VcsUiApp, state?: S):Promise<void>;
|
|
218
|
+
onVcsAppMounted(app: VcsUiApp):Promise<void>;
|
|
219
|
+
getState():Promise<S>;
|
|
220
|
+
toJSON():Promise<T>;
|
|
194
221
|
destroy():void;
|
|
195
222
|
}
|
|
196
223
|
|
|
197
|
-
declare function defaultExport<T extends Object>(config: T):VcsPlugin<T>;
|
|
224
|
+
declare function defaultExport<T extends Object, S extends Object>(config: T, baseUrl: string):VcsPlugin<T, S>;
|
|
198
225
|
```
|
|
199
226
|
|
|
200
227
|
A Simple JavaScript implementation of this interface can be seen below::
|
|
@@ -204,22 +231,79 @@ A Simple JavaScript implementation of this interface can be seen below::
|
|
|
204
231
|
* @param {PluginExampleConfig} config
|
|
205
232
|
* @returns {VcsPlugin}
|
|
206
233
|
*/
|
|
207
|
-
export default function defaultExport(config) {
|
|
234
|
+
export default function defaultExport(config, baseUrl) {
|
|
208
235
|
return {
|
|
209
236
|
get name() {
|
|
210
237
|
return packageJSON.name;
|
|
211
238
|
},
|
|
212
239
|
get version() {
|
|
213
240
|
return packageJSON.version;
|
|
241
|
+
},
|
|
242
|
+
async initialize (app, state) {
|
|
243
|
+
console.log('I was loaded from ', baseUrl);
|
|
214
244
|
},
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
toJSON() {},
|
|
245
|
+
async onVcsAppMounted(app) {},
|
|
246
|
+
async getState() { return {}; },
|
|
247
|
+
async toJSON() { return {}; },
|
|
218
248
|
destroy() {},
|
|
219
249
|
}
|
|
220
250
|
}
|
|
221
251
|
```
|
|
222
252
|
|
|
253
|
+
### About Plugin Assets
|
|
254
|
+
Plugin assets are considered to be static files, such as images, fonts etc. which shall be
|
|
255
|
+
access from within the plugin. Since plugins have no knowledge of _where_ they will
|
|
256
|
+
be deployed, the `@vcmap/ui` provides the `getPluginAssetUrl` helper function
|
|
257
|
+
which allows you to generate an asset URL at runtime.
|
|
258
|
+
|
|
259
|
+
Place all your assets into the `plugin-assets` directory in your plugin (top level). Your
|
|
260
|
+
plugin structure should look something like this:
|
|
261
|
+
```
|
|
262
|
+
-| my-plugin/
|
|
263
|
+
---| src/
|
|
264
|
+
-----| index.js
|
|
265
|
+
---| plugin-assets/
|
|
266
|
+
-----| icon.png
|
|
267
|
+
---| package.json
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
To access the `icon.png` from within your code, you would do the following:
|
|
271
|
+
```vue
|
|
272
|
+
<template>
|
|
273
|
+
<v-img
|
|
274
|
+
:src="icon"
|
|
275
|
+
alt="plugin-icon"
|
|
276
|
+
max-width="200"
|
|
277
|
+
/>
|
|
278
|
+
</template>
|
|
279
|
+
|
|
280
|
+
<script>
|
|
281
|
+
import { inject } from 'vue';
|
|
282
|
+
import { getPluginAssetUrl } from '@vcmap/ui';
|
|
283
|
+
import { name } from '../package.json';
|
|
284
|
+
|
|
285
|
+
export const windowId = 'hello_world_window_id_plugin-cli';
|
|
286
|
+
|
|
287
|
+
export default {
|
|
288
|
+
name: 'HelloWorld',
|
|
289
|
+
components: { VcsButton },
|
|
290
|
+
setup() {
|
|
291
|
+
const app = inject('vcsApp');
|
|
292
|
+
|
|
293
|
+
return {
|
|
294
|
+
icon: getPluginAssetUrl(app, name, 'plugin-assets/icon.png'),
|
|
295
|
+
};
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
</script>
|
|
299
|
+
```
|
|
300
|
+
You can of course, use `fetch` to retrieve assets in the same fashion. Should you
|
|
301
|
+
wish to use assets (such as images) in your _css_ make sure that they are embedded or
|
|
302
|
+
you will have to use an inline style & a bound vue property, since the helper
|
|
303
|
+
cannot handle css resources.
|
|
304
|
+
|
|
305
|
+
If you have to access assets _before_ your plugin is created (in the exported function of
|
|
306
|
+
your plugin code), you will have to use the `baseUrl` provided to you to generate the URL yourself.
|
|
223
307
|
|
|
224
308
|
## Notes on Developing
|
|
225
309
|
To develop the plugin-cli, be sure to not `npm link` into plugins, since this will
|
|
@@ -8,8 +8,10 @@ stages:
|
|
|
8
8
|
- build
|
|
9
9
|
- test
|
|
10
10
|
- bundle
|
|
11
|
+
- deploy
|
|
11
12
|
- version
|
|
12
13
|
- publish
|
|
14
|
+
- deployCluster
|
|
13
15
|
|
|
14
16
|
.template: &job_definition
|
|
15
17
|
only:
|
|
@@ -20,7 +22,6 @@ stages:
|
|
|
20
22
|
build:
|
|
21
23
|
<<: *job_definition
|
|
22
24
|
script:
|
|
23
|
-
- npm set registry 'http://npmregistry:4873'
|
|
24
25
|
- npm ci
|
|
25
26
|
before_script:
|
|
26
27
|
- mkdir -p ~/.ssh
|
|
@@ -38,6 +39,12 @@ build:
|
|
|
38
39
|
variables:
|
|
39
40
|
GIT_STRATEGY: none
|
|
40
41
|
|
|
42
|
+
.staging_build_template: &staging_build_template
|
|
43
|
+
<<: *after_build_definition
|
|
44
|
+
except:
|
|
45
|
+
variables:
|
|
46
|
+
- $PUBLISH
|
|
47
|
+
|
|
41
48
|
lint:
|
|
42
49
|
<<: *after_build_definition
|
|
43
50
|
stage: test
|
|
@@ -50,12 +57,74 @@ audit:
|
|
|
50
57
|
script:
|
|
51
58
|
- npm audit --production --audit-level=low
|
|
52
59
|
|
|
60
|
+
buildPreview:
|
|
61
|
+
<<: *staging_build_template
|
|
62
|
+
stage: bundle
|
|
63
|
+
script:
|
|
64
|
+
- npm run buildStagingApp
|
|
65
|
+
|
|
53
66
|
bundle:
|
|
54
67
|
<<: *after_build_definition
|
|
55
68
|
stage: bundle
|
|
69
|
+
only:
|
|
70
|
+
variables:
|
|
71
|
+
- $PUBLISH
|
|
72
|
+
refs:
|
|
73
|
+
- /^(main|release-v.*)$/
|
|
56
74
|
script:
|
|
57
75
|
- npm run build
|
|
58
76
|
|
|
77
|
+
deployStaging:
|
|
78
|
+
<<: *staging_build_template
|
|
79
|
+
stage: deploy
|
|
80
|
+
environment:
|
|
81
|
+
name: staging/$CI_COMMIT_REF_SLUG
|
|
82
|
+
url: http://$CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG.stagingcluster.intern.virtualcitysystems.de
|
|
83
|
+
on_stop: stopEnvironment
|
|
84
|
+
image:
|
|
85
|
+
name: gcr.io/kaniko-project/executor:debug
|
|
86
|
+
entrypoint: [ "" ]
|
|
87
|
+
script:
|
|
88
|
+
- /kaniko/executor --context dist/ --dockerfile build/staging/Dockerfile --destination $CI_REGISTRY_IMAGE/staging:$CI_COMMIT_REF_SLUG
|
|
89
|
+
before_script:
|
|
90
|
+
- mkdir -p /kaniko/.docker
|
|
91
|
+
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
|
|
92
|
+
|
|
93
|
+
stopEnvironment:
|
|
94
|
+
stage: deploy
|
|
95
|
+
variables:
|
|
96
|
+
GIT_STRATEGY: none
|
|
97
|
+
image:
|
|
98
|
+
name: bitnami/kubectl:latest
|
|
99
|
+
entrypoint: [""]
|
|
100
|
+
tags:
|
|
101
|
+
- linux-2.0
|
|
102
|
+
script:
|
|
103
|
+
- echo "Stop environment staging/$CI_COMMIT_REF_NAME"
|
|
104
|
+
- echo "Delete namespace on k9s $CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG"
|
|
105
|
+
- kubectl config use-context vcsuite/cluster-management:agent
|
|
106
|
+
- kubectl delete namespace $CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG
|
|
107
|
+
when: manual
|
|
108
|
+
environment:
|
|
109
|
+
name: staging/$CI_COMMIT_REF_SLUG
|
|
110
|
+
action: stop
|
|
111
|
+
|
|
112
|
+
deployStagingCluster:
|
|
113
|
+
stage: deployCluster
|
|
114
|
+
except:
|
|
115
|
+
variables:
|
|
116
|
+
- $PUBLISH
|
|
117
|
+
inherit:
|
|
118
|
+
variables: false
|
|
119
|
+
variables:
|
|
120
|
+
STAGE_BRANCH: $CI_COMMIT_REF_SLUG
|
|
121
|
+
STAGE_PROJECT_NAME: $CI_PROJECT_PATH_SLUG
|
|
122
|
+
STAGE_REGISTRY_IMAGE: $CI_REGISTRY_IMAGE
|
|
123
|
+
STAGE_NAMESPACE: $CI_PROJECT_PATH_SLUG-$CI_COMMIT_REF_SLUG
|
|
124
|
+
trigger:
|
|
125
|
+
project: vcsuite/devops/manifests
|
|
126
|
+
branch: main
|
|
127
|
+
|
|
59
128
|
version:
|
|
60
129
|
<<: *after_build_definition
|
|
61
130
|
stage: version
|
|
@@ -89,5 +158,5 @@ publish:
|
|
|
89
158
|
variables:
|
|
90
159
|
- $PUBLISH
|
|
91
160
|
script:
|
|
92
|
-
- npm config set '//
|
|
93
|
-
- npm publish --registry
|
|
161
|
+
- npm config set '//registry.npmjs.org/:_authToken' "${NPM_TOKEN}"
|
|
162
|
+
- npm publish --registry https://registry.npmjs.org --access public
|
|
Binary file
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<v-sheet>
|
|
2
|
+
<v-sheet class="hello-world">
|
|
3
3
|
<v-card class="pa-2 ma-2">
|
|
4
4
|
<v-container>
|
|
5
5
|
<v-row class="justify-center mb-4">
|
|
6
|
-
<h1>{{ $t('helloWorld.helloWorld')}}</h1>
|
|
6
|
+
<h1>{{ $t('helloWorld.helloWorld') }}</h1>
|
|
7
|
+
</v-row>
|
|
8
|
+
<v-row class="justify-center mb-4">
|
|
9
|
+
<v-img
|
|
10
|
+
:src="logoUrl"
|
|
11
|
+
alt="plugin-assets example"
|
|
12
|
+
max-width="200"
|
|
13
|
+
/>
|
|
7
14
|
</v-row>
|
|
8
15
|
<v-row class="justify-center">
|
|
9
16
|
<VcsButton
|
|
@@ -18,11 +25,17 @@
|
|
|
18
25
|
</v-sheet>
|
|
19
26
|
</template>
|
|
20
27
|
|
|
28
|
+
<style>
|
|
29
|
+
.hello-world {
|
|
30
|
+
background-color: aqua;
|
|
31
|
+
}
|
|
32
|
+
</style>
|
|
21
33
|
<script>
|
|
22
|
-
import { inject } from '
|
|
23
|
-
import { VcsButton } from '@vcmap/ui';
|
|
34
|
+
import { inject } from 'vue';
|
|
35
|
+
import { VcsButton, getPluginAssetUrl } from '@vcmap/ui';
|
|
36
|
+
import { name } from '../package.json';
|
|
24
37
|
|
|
25
|
-
export const windowId = '
|
|
38
|
+
export const windowId = 'hello_world_window_id_plugin-cli';
|
|
26
39
|
|
|
27
40
|
export default {
|
|
28
41
|
name: 'HelloWorld',
|
|
@@ -34,6 +47,7 @@
|
|
|
34
47
|
closeSelf() {
|
|
35
48
|
app.windowManager.remove(windowId);
|
|
36
49
|
},
|
|
50
|
+
logoUrl: getPluginAssetUrl(app, name, 'plugin-assets/vcs_logo.png'),
|
|
37
51
|
};
|
|
38
52
|
},
|
|
39
53
|
};
|
|
@@ -4,18 +4,21 @@ import HelloWorld, { windowId } from './helloWorld.vue';
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @param {T} config - the configuration of this plugin instance, passed in from the app.
|
|
7
|
+
* @param {string} baseUrl - the absolute URL from which the plugin was loaded (without filename, ending on /)
|
|
7
8
|
* @returns {import("@vcmap/ui/src/vcsUiApp").VcsPlugin<T>}
|
|
8
9
|
* @template {Object} T
|
|
10
|
+
* @template {Object} S
|
|
9
11
|
*/
|
|
10
|
-
export default function(config) {
|
|
12
|
+
export default function(config, baseUrl) {
|
|
11
13
|
return {
|
|
12
14
|
get name() { return name; },
|
|
13
15
|
get version() { return version; },
|
|
14
16
|
/**
|
|
15
17
|
* @param {import("@vcmap/ui").VcsUiApp} vcsUiApp
|
|
18
|
+
* @param {S=} state
|
|
16
19
|
* @returns {Promise<void>}
|
|
17
20
|
*/
|
|
18
|
-
initialize: async (vcsUiApp) => {
|
|
21
|
+
initialize: async (vcsUiApp, state) => {
|
|
19
22
|
console.log('Called before loading the rest of the current context. Passed in the containing Vcs UI App ');
|
|
20
23
|
},
|
|
21
24
|
/**
|
|
@@ -34,22 +37,30 @@ export default function(config) {
|
|
|
34
37
|
},
|
|
35
38
|
}, name);
|
|
36
39
|
},
|
|
40
|
+
/**
|
|
41
|
+
* @returns {Promise<S>}
|
|
42
|
+
*/
|
|
43
|
+
getState: async () => {
|
|
44
|
+
console.log('Called when serializing this plugin instance');
|
|
45
|
+
return {};
|
|
46
|
+
},
|
|
37
47
|
/**
|
|
38
48
|
* @returns {Promise<T>}
|
|
39
49
|
*/
|
|
40
50
|
toJSON: async () => {
|
|
41
51
|
console.log('Called when serializing this plugin instance');
|
|
52
|
+
return {};
|
|
42
53
|
},
|
|
43
54
|
i18n: {
|
|
44
55
|
en: {
|
|
45
56
|
helloWorld: {
|
|
46
|
-
helloWorld: 'Hello World',
|
|
57
|
+
helloWorld: '@vcmap/plugin-cli - Hello World',
|
|
47
58
|
close: 'Close',
|
|
48
59
|
},
|
|
49
60
|
},
|
|
50
61
|
de: {
|
|
51
62
|
helloWorld: {
|
|
52
|
-
helloWorld: 'Hallo Welt',
|
|
63
|
+
helloWorld: '@vcmap/plugin-cli - Hallo Welt',
|
|
53
64
|
close: 'Schließen',
|
|
54
65
|
},
|
|
55
66
|
},
|
package/cli.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import program from 'commander';
|
|
3
3
|
import './src/defaultCommand.js';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
create, serve, build, pack, preview,
|
|
6
|
+
} from './index.js';
|
|
5
7
|
import { version } from './src/create.js';
|
|
6
8
|
import setupMapUi from './src/setupMapUi.js';
|
|
9
|
+
import buildStagingApp from './src/buildStagingApp.js';
|
|
7
10
|
|
|
8
11
|
program.version(version);
|
|
9
12
|
|
|
@@ -45,6 +48,11 @@ program
|
|
|
45
48
|
.option('--watch', 'watch file changes')
|
|
46
49
|
.safeAction(build);
|
|
47
50
|
|
|
51
|
+
program
|
|
52
|
+
.command('buildStagingApp')
|
|
53
|
+
.defaultOptions()
|
|
54
|
+
.safeAction(buildStagingApp);
|
|
55
|
+
|
|
48
56
|
program
|
|
49
57
|
.command('setup-map-ui')
|
|
50
58
|
.safeAction(setupMapUi);
|
package/index.js
CHANGED
|
@@ -3,5 +3,6 @@ export { default as serve } from './src/serve.js';
|
|
|
3
3
|
export { default as build } from './src/build.js';
|
|
4
4
|
export { default as pack } from './src/pack.js';
|
|
5
5
|
export { default as preview } from './src/preview.js';
|
|
6
|
+
export { default as buildStagingApp } from './src/buildStagingApp.js';
|
|
6
7
|
export { default as setupMapUi } from './src/setupMapUi.js';
|
|
7
8
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vcmap/plugin-cli",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.10",
|
|
4
4
|
"description": "A CLI to help develop and build plugins for the VC Map",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -34,15 +34,14 @@
|
|
|
34
34
|
"prompts": "^2.4.1",
|
|
35
35
|
"sass": "1.32.13",
|
|
36
36
|
"semver": "^7.3.5",
|
|
37
|
-
"unplugin-vue-components": "^0.
|
|
38
|
-
"
|
|
39
|
-
"vite": "^2.9.12",
|
|
37
|
+
"unplugin-vue-components": "^0.21.1",
|
|
38
|
+
"vite": "^2.9.14",
|
|
40
39
|
"vite-plugin-vue2": "^2.0.1",
|
|
41
|
-
"vue-template-compiler": "~2.
|
|
40
|
+
"vue-template-compiler": "~2.7.3"
|
|
42
41
|
},
|
|
43
42
|
"peerDependencies": {
|
|
44
|
-
"@vcmap/ui": "^5.0.0-rc.
|
|
45
|
-
"vue": "~2.
|
|
43
|
+
"@vcmap/ui": "^5.0.0-rc.11",
|
|
44
|
+
"vue": "~2.7.3"
|
|
46
45
|
},
|
|
47
46
|
"peerDependenciesMeta": {
|
|
48
47
|
"@vcmap/ui": {
|
package/src/build.js
CHANGED
|
@@ -12,6 +12,8 @@ import { getContext } from './context.js';
|
|
|
12
12
|
* @typedef {Object} BuildOptions
|
|
13
13
|
* @property {boolean} [development]
|
|
14
14
|
* @property {boolean} [watch]
|
|
15
|
+
* @property {string} [outputPath] path where the plugin should be written, relative to the dist folder, default ''
|
|
16
|
+
* @property {boolean} [keepDistFolder] will not clear the dist folder if set to true
|
|
15
17
|
*/
|
|
16
18
|
|
|
17
19
|
export function getDefaultConfig() {
|
|
@@ -62,8 +64,10 @@ export default async function buildModule(options) {
|
|
|
62
64
|
const pluginName = await getPluginName();
|
|
63
65
|
const libraryPaths = await getLibraryPaths(pluginName);
|
|
64
66
|
const distPath = path.join(getContext(), 'dist');
|
|
65
|
-
|
|
66
|
-
|
|
67
|
+
if (!options.keepDistFolder) {
|
|
68
|
+
await fs.rm(distPath, { recursive: true, force: true });
|
|
69
|
+
await fs.mkdir(distPath);
|
|
70
|
+
}
|
|
67
71
|
const external = Object.keys(libraryPaths);
|
|
68
72
|
const config = {
|
|
69
73
|
...getDefaultConfig(),
|
|
@@ -93,5 +97,5 @@ export default async function buildModule(options) {
|
|
|
93
97
|
},
|
|
94
98
|
};
|
|
95
99
|
const { buildLibrary } = await import('@vcmap/ui/build/buildHelpers.js');
|
|
96
|
-
await buildLibrary(config, '', 'index', '', true);
|
|
100
|
+
await buildLibrary(config, options.outputPath ?? '', 'index', '', true);
|
|
97
101
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { cp, copyFile, writeFile, rm, mkdir } from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import { getContext, resolveContext } from './context.js';
|
|
5
|
+
import { getConfigJson } from './hostingHelpers.js';
|
|
6
|
+
import { getPluginName } from './packageJsonHelpers.js';
|
|
7
|
+
import buildModule, { getDefaultConfig } from './build.js';
|
|
8
|
+
import setupMapUi from './setupMapUi.js';
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* creates production preview application in the dist folder based on the @vcmap/ui default map configuration.
|
|
13
|
+
* @returns {Promise<void>}
|
|
14
|
+
*/
|
|
15
|
+
export default async function buildStagingApp() {
|
|
16
|
+
const pluginName = await getPluginName();
|
|
17
|
+
const distPath = path.join(getContext(), 'dist');
|
|
18
|
+
// Clear dist folder
|
|
19
|
+
await rm(distPath, { recursive: true, force: true });
|
|
20
|
+
await mkdir(distPath);
|
|
21
|
+
await setupMapUi();
|
|
22
|
+
const { buildPluginsForPreview } = await import('@vcmap/ui/build/buildHelpers.js');
|
|
23
|
+
await buildPluginsForPreview(getDefaultConfig(), true);
|
|
24
|
+
await mkdir(path.join(distPath, 'plugins', pluginName), { recursive: true });
|
|
25
|
+
|
|
26
|
+
await buildModule({ outputPath: `plugins/${pluginName}`, keepDistFolder: true });
|
|
27
|
+
|
|
28
|
+
// copy assets folder if exists
|
|
29
|
+
if (fs.existsSync(resolveContext('plugin-assets'))) {
|
|
30
|
+
await cp(
|
|
31
|
+
resolveContext('plugin-assets'),
|
|
32
|
+
path.join(distPath, 'plugins', pluginName, 'plugin-assets'),
|
|
33
|
+
{ recursive: true },
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
await copyFile(
|
|
38
|
+
path.join(getContext(), 'node_modules', '@vcmap', 'ui', 'dist', 'index.html'),
|
|
39
|
+
path.join(distPath, 'index.html'),
|
|
40
|
+
);
|
|
41
|
+
const config = await getConfigJson();
|
|
42
|
+
// update Entry
|
|
43
|
+
const pluginConfig = config.plugins.find(p => p.name === pluginName);
|
|
44
|
+
if (pluginConfig) {
|
|
45
|
+
pluginConfig.entry = `plugins/${pluginName}/index.js`;
|
|
46
|
+
}
|
|
47
|
+
await writeFile(path.join(distPath, 'map.config.json'), JSON.stringify(config, null, 2));
|
|
48
|
+
await cp(
|
|
49
|
+
path.join(getContext(), 'node_modules', '@vcmap', 'ui', 'dist', 'assets'),
|
|
50
|
+
path.join(distPath, 'assets'),
|
|
51
|
+
{ recursive: true },
|
|
52
|
+
);
|
|
53
|
+
await cp(
|
|
54
|
+
path.join(getContext(), 'node_modules', '@vcmap', 'ui', 'config'),
|
|
55
|
+
path.join(distPath, 'config'),
|
|
56
|
+
{ recursive: true },
|
|
57
|
+
);
|
|
58
|
+
}
|
package/src/create.js
CHANGED
|
@@ -9,6 +9,7 @@ import { LicenseType, writeLicense } from './licenses.js';
|
|
|
9
9
|
import { getDirname } from './hostingHelpers.js';
|
|
10
10
|
|
|
11
11
|
export const { version, name } = JSON.parse(fs.readFileSync(path.join(getDirname(), '..', 'package.json')).toString());
|
|
12
|
+
const exec = util.promisify(childProcess.exec);
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* @typedef {Object} PluginTemplateOptions
|
|
@@ -19,11 +20,54 @@ export const { version, name } = JSON.parse(fs.readFileSync(path.join(getDirname
|
|
|
19
20
|
* @property {string} author
|
|
20
21
|
* @property {string} repository
|
|
21
22
|
* @property {string} license
|
|
22
|
-
* @property {string} registry
|
|
23
|
-
* @property {boolean} addCiCd
|
|
24
23
|
* @property {Array<string>} peerDeps
|
|
25
24
|
*/
|
|
26
25
|
|
|
26
|
+
/**
|
|
27
|
+
* @enum {number}
|
|
28
|
+
*/
|
|
29
|
+
const DepType = {
|
|
30
|
+
DEP: 1,
|
|
31
|
+
PEER: 2,
|
|
32
|
+
DEV: 3,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @param {Array<string>} deps
|
|
37
|
+
* @param {DepType} type
|
|
38
|
+
* @param {string} pluginPath
|
|
39
|
+
* @returns {Promise<void>}
|
|
40
|
+
*/
|
|
41
|
+
async function installDeps(deps, type, pluginPath) {
|
|
42
|
+
let save = '--save';
|
|
43
|
+
if (type === DepType.PEER) {
|
|
44
|
+
save = '--save-peer';
|
|
45
|
+
} else if (type === DepType.DEV) {
|
|
46
|
+
save = '--save-dev';
|
|
47
|
+
}
|
|
48
|
+
const installCmd = `npm i ${save} ${deps.join(' ')}`;
|
|
49
|
+
const { stdout, stderr } = await exec(installCmd, { cwd: pluginPath });
|
|
50
|
+
logger.log(stdout);
|
|
51
|
+
logger.error(stderr);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @param {Array<string>} deps
|
|
56
|
+
* @param {string} pluginPath
|
|
57
|
+
* @returns {Promise<void>}
|
|
58
|
+
*/
|
|
59
|
+
async function setUiPeerDepVersions(deps, pluginPath) {
|
|
60
|
+
const uiPackageJsonContent = await fs.promises.readFile(
|
|
61
|
+
path.join(pluginPath, 'node_modules', '@vcmap', 'ui', 'package.json'),
|
|
62
|
+
);
|
|
63
|
+
const uiPackageJson = JSON.parse(uiPackageJsonContent);
|
|
64
|
+
deps.forEach((dep, index) => {
|
|
65
|
+
if (uiPackageJson.peerDependencies[dep]) {
|
|
66
|
+
deps[index] = `${dep}@${uiPackageJson.peerDependencies[dep]}`;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
27
71
|
/**
|
|
28
72
|
* @param {PluginTemplateOptions} options
|
|
29
73
|
*/
|
|
@@ -100,7 +144,7 @@ async function createPluginTemplate(options) {
|
|
|
100
144
|
|
|
101
145
|
const writeNpmrcPromise = fs.promises.writeFile(
|
|
102
146
|
path.join(pluginPath, '.npmrc'),
|
|
103
|
-
|
|
147
|
+
'registry=https://registry.npmjs.org\n',
|
|
104
148
|
);
|
|
105
149
|
|
|
106
150
|
const writeReadmePromise = fs.promises.writeFile(
|
|
@@ -137,21 +181,15 @@ async function createPluginTemplate(options) {
|
|
|
137
181
|
|
|
138
182
|
|
|
139
183
|
logger.spin('installing dependencies... (this may take a while)');
|
|
140
|
-
const exec = util.promisify(childProcess.exec);
|
|
141
184
|
try {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
logger.log(stdout);
|
|
146
|
-
logger.error(stderr);
|
|
185
|
+
await installDeps(['@vcmap/ui'], DepType.PEER, pluginPath);
|
|
186
|
+
await setUiPeerDepVersions(options.peerDeps, pluginPath);
|
|
187
|
+
await installDeps(options.peerDeps, DepType.PEER, pluginPath);
|
|
147
188
|
const devDeps = [`${name}@${version}`];
|
|
148
189
|
if (installEsLint) {
|
|
149
190
|
devDeps.push('@vcsuite/eslint-config');
|
|
150
191
|
}
|
|
151
|
-
|
|
152
|
-
const { stdout: stdoutDev, stderr: stderrDev } = await exec(installDevCmd, { cwd: pluginPath });
|
|
153
|
-
logger.log(stdoutDev);
|
|
154
|
-
logger.error(stderrDev);
|
|
192
|
+
await installDeps(devDeps, DepType.DEV, pluginPath);
|
|
155
193
|
logger.success('installed dependencies');
|
|
156
194
|
} catch (e) {
|
|
157
195
|
logger.error(e);
|
|
@@ -170,14 +208,16 @@ export default async function create() {
|
|
|
170
208
|
{ title: 'pack', value: { pack: 'vcmplugin pack' }, selected: true },
|
|
171
209
|
{ title: 'start', value: { start: 'vcmplugin serve' }, selected: true },
|
|
172
210
|
{ title: 'preview', value: { preview: 'vcmplugin preview' }, selected: true },
|
|
211
|
+
{ title: 'buildStagingApp', value: { buildStagingApp: 'vcmplugin buildStagingApp' }, selected: true },
|
|
173
212
|
{ title: 'lint', value: { lint: 'eslint "{src,tests}/**/*.{js,vue}"' }, selected: true },
|
|
174
213
|
];
|
|
175
214
|
|
|
176
215
|
const peerDependencyChoices = [
|
|
177
216
|
{ title: '@vcmap/core', value: '@vcmap/core' },
|
|
178
217
|
{ title: '@vcmap/cesium', value: '@vcmap/cesium' },
|
|
179
|
-
{ title: 'ol', value: 'ol
|
|
180
|
-
{ title: '
|
|
218
|
+
{ title: 'ol', value: 'ol' },
|
|
219
|
+
{ title: 'vue', value: 'vue' },
|
|
220
|
+
{ title: 'vuetify', value: 'vuetify' },
|
|
181
221
|
];
|
|
182
222
|
|
|
183
223
|
const questions = [
|
|
@@ -239,12 +279,6 @@ export default async function create() {
|
|
|
239
279
|
value: type,
|
|
240
280
|
})),
|
|
241
281
|
},
|
|
242
|
-
{
|
|
243
|
-
type: 'text',
|
|
244
|
-
name: 'registry',
|
|
245
|
-
message: 'Set default npm registry',
|
|
246
|
-
initial: 'https://registry.npmjs.org',
|
|
247
|
-
},
|
|
248
282
|
{
|
|
249
283
|
name: 'peerDeps',
|
|
250
284
|
type: 'multiselect',
|
|
@@ -252,14 +286,6 @@ export default async function create() {
|
|
|
252
286
|
choices: peerDependencyChoices,
|
|
253
287
|
hint: '- Space to select. Enter to submit',
|
|
254
288
|
},
|
|
255
|
-
{
|
|
256
|
-
type: 'toggle',
|
|
257
|
-
name: 'addCiCd',
|
|
258
|
-
message: 'Add default VCS gitlab ci/cd?',
|
|
259
|
-
initial: false,
|
|
260
|
-
active: 'yes',
|
|
261
|
-
inactive: 'no',
|
|
262
|
-
},
|
|
263
289
|
];
|
|
264
290
|
|
|
265
291
|
const answers = await prompts(questions, { onCancel() { process.exit(0); } });
|
package/src/hostingHelpers.js
CHANGED
|
@@ -269,6 +269,16 @@ export async function getMapUiIndexHtml(production) {
|
|
|
269
269
|
return buffer.toString();
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
+
/**
|
|
273
|
+
* @param {Express} app
|
|
274
|
+
* @param {string} base
|
|
275
|
+
*/
|
|
276
|
+
export function addPluginAssets(app, base) {
|
|
277
|
+
app.use(`/${base}/plugin-assets*`, (req, res) => {
|
|
278
|
+
res.redirect(308, req.originalUrl.replace(`/${base}`, ''));
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
272
282
|
/**
|
|
273
283
|
* @param {Express} app
|
|
274
284
|
* @param {import("vite").ViteDevServer} server
|
package/src/pack.js
CHANGED
|
@@ -1,40 +1,10 @@
|
|
|
1
|
-
import { Transform } from 'stream';
|
|
2
1
|
import fs from 'fs';
|
|
3
|
-
import vinylFs from 'vinyl-fs';
|
|
4
2
|
import archiver from 'archiver';
|
|
5
3
|
import { logger } from '@vcsuite/cli-logger';
|
|
6
4
|
import { getPluginName } from './packageJsonHelpers.js';
|
|
7
|
-
import { resolveContext
|
|
5
|
+
import { resolveContext } from './context.js';
|
|
8
6
|
import build from './build.js';
|
|
9
7
|
|
|
10
|
-
/**
|
|
11
|
-
* @param {string} name
|
|
12
|
-
* @returns {Promise<void>}
|
|
13
|
-
*/
|
|
14
|
-
function replaceAssets(name) {
|
|
15
|
-
const replaceTransform = new Transform({
|
|
16
|
-
objectMode: true,
|
|
17
|
-
transform(data, encoding, callback) {
|
|
18
|
-
data.contents = Buffer.from(String(data.contents)
|
|
19
|
-
.replace(/\.?\/?(plugin-assets)\//g, `plugins/${name}/$1/`));
|
|
20
|
-
|
|
21
|
-
callback(null, data);
|
|
22
|
-
},
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
const context = getContext();
|
|
26
|
-
const stream = vinylFs.src([resolveContext('dist', '*')], {
|
|
27
|
-
cwd: context,
|
|
28
|
-
allowEmpty: false,
|
|
29
|
-
})
|
|
30
|
-
.pipe(replaceTransform)
|
|
31
|
-
.pipe(vinylFs.dest(resolveContext('dist')));
|
|
32
|
-
|
|
33
|
-
return new Promise((resolve, reject) => {
|
|
34
|
-
stream.on('finish', () => { resolve(); });
|
|
35
|
-
stream.on('error', reject);
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
8
|
|
|
39
9
|
/**
|
|
40
10
|
* @returns {Promise<void>}
|
|
@@ -89,7 +59,6 @@ function zip(name) {
|
|
|
89
59
|
['README.md'],
|
|
90
60
|
['config.json'],
|
|
91
61
|
['dist', 'index.js'],
|
|
92
|
-
['dist', 'style.css'],
|
|
93
62
|
].forEach((fileArray) => {
|
|
94
63
|
const file = resolveContext(...fileArray);
|
|
95
64
|
if (fs.existsSync(file)) {
|
|
@@ -114,8 +83,6 @@ export default async function pack() {
|
|
|
114
83
|
const pluginName = await getPluginName();
|
|
115
84
|
logger.spin(`building plugin: ${pluginName}`);
|
|
116
85
|
await build({});
|
|
117
|
-
await replaceAssets(pluginName);
|
|
118
|
-
logger.debug('fixed asset paths');
|
|
119
86
|
await ensureConfigJson();
|
|
120
87
|
logger.debug('ensuring config.json');
|
|
121
88
|
await zip(pluginName);
|
package/src/preview.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
addConfigRoute,
|
|
8
8
|
addIndexRoute,
|
|
9
9
|
addMapConfigRoute,
|
|
10
|
+
addPluginAssets,
|
|
10
11
|
checkReservedDirectories,
|
|
11
12
|
createConfigJsonReloadPlugin,
|
|
12
13
|
printVcmapUiVersion, resolveMapUi,
|
|
@@ -83,6 +84,7 @@ export default async function preview(options) {
|
|
|
83
84
|
|
|
84
85
|
addMapConfigRoute(app, options.vcm ? `${options.vcm}/map.config.json` : null, options.auth, options.config, true);
|
|
85
86
|
addIndexRoute(app, server, true, options.vcm, options.auth);
|
|
87
|
+
addPluginAssets(app, 'dist');
|
|
86
88
|
|
|
87
89
|
if (!options.vcm) {
|
|
88
90
|
logger.spin('compiling preview');
|
package/src/serve.js
CHANGED
|
@@ -10,7 +10,7 @@ import { getContext } from './context.js';
|
|
|
10
10
|
import {
|
|
11
11
|
addConfigRoute,
|
|
12
12
|
addIndexRoute,
|
|
13
|
-
addMapConfigRoute,
|
|
13
|
+
addMapConfigRoute, addPluginAssets,
|
|
14
14
|
checkReservedDirectories,
|
|
15
15
|
createConfigJsonReloadPlugin,
|
|
16
16
|
printVcmapUiVersion,
|
|
@@ -114,6 +114,7 @@ export default async function serve(options) {
|
|
|
114
114
|
|
|
115
115
|
addMapConfigRoute(app, options.mapConfig, options.auth, options.config);
|
|
116
116
|
addIndexRoute(app, server);
|
|
117
|
+
addPluginAssets(app, 'src');
|
|
117
118
|
await addConfigRoute(app, options.auth, options.config);
|
|
118
119
|
|
|
119
120
|
app.use(server.middlewares);
|