@vcmap/plugin-cli 2.0.1 → 2.0.4
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 +91 -18
- package/assets/helloWorld/.gitignore +2 -0
- package/assets/helloWorld/.gitlab-ci.yml +93 -0
- package/assets/helloWorld/src/helloWorld.vue +40 -0
- package/assets/helloWorld/src/index.js +35 -0
- package/cli.js +5 -0
- package/index.js +2 -0
- package/package.json +30 -3
- package/src/build.js +43 -67
- package/src/create.js +78 -44
- package/src/hostingHelpers.js +93 -19
- package/src/preview.js +19 -6
- package/src/serve.js +38 -1
- package/src/setupMapUi.js +9 -0
package/README.md
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# @vcmap/plugin-cli
|
|
2
2
|
> Part of the [VC Map Project](https://github.com/virtualcitySYSTEMS/map-ui)
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
> **Note: This documentation is for version 2, compatible with the [VC Map](https://github.com/virtualcitySYSTEMS/map-ui) v5.
|
|
5
|
+
> For documentation on version 1 compatible with VC Map v4, see [this tag](https://github.com/virtualcitySYSTEMS/map-plugin-cli/tree/v1.1.1)
|
|
6
|
+
> and be sure to install using `npm i -g @vcmap/plugin-cli@^1.1.0`**
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
which provides documentations and a tutorial on plugin development.
|
|
8
|
+
The `vcmplugin` cli helps develop and build plugins for the **VC Map**.
|
|
8
9
|
|
|
9
10
|
## Features
|
|
10
11
|
|
|
@@ -29,6 +30,15 @@ npm i -g @vcmap/plugin-cli
|
|
|
29
30
|
```
|
|
30
31
|
|
|
31
32
|
## Usage
|
|
33
|
+
You can use the following workflow to quickly develop plugins. Note, that
|
|
34
|
+
the `@vcmap/plugin-cli` does _not_ directly depend on `@vcmap/ui` to avoid version
|
|
35
|
+
conflicts in the used API within a plugin. This means, that _all_ commands
|
|
36
|
+
(except for the `create` command) must be executed from within an installed
|
|
37
|
+
plugin cli _within the plugin itself_ using npx. When using the `create`
|
|
38
|
+
command, the `@vcmap/plugin-cli` will automatically be installed as a devDependency in
|
|
39
|
+
its current major version. You can then use either the scripts defined
|
|
40
|
+
by the template in your package.json `npm start`, `npm run pack` etc. or `npx`
|
|
41
|
+
to execute CLI commands.
|
|
32
42
|
|
|
33
43
|
### 1. Creating a new plugin
|
|
34
44
|
|
|
@@ -43,7 +53,7 @@ Be sure to check out the [peer dependecy section](#about_peer_dependencies) as w
|
|
|
43
53
|
|
|
44
54
|
To serve your plugin in dev mode, run the following within your projects root:
|
|
45
55
|
```
|
|
46
|
-
vcmplugin serve
|
|
56
|
+
npx vcmplugin serve
|
|
47
57
|
```
|
|
48
58
|
The dev mode gives you complete debug information on all integrated libraries (@vcmap/core, ol etc.)
|
|
49
59
|
By default this command will launch a dev server at localhost:8008 using
|
|
@@ -58,7 +68,7 @@ your plugin integrates with others, use the `preview` command.
|
|
|
58
68
|
|
|
59
69
|
To serve your plugin in preview mode, run the following within your projects root:
|
|
60
70
|
```
|
|
61
|
-
vcmplugin preview
|
|
71
|
+
npx vcmplugin preview
|
|
62
72
|
```
|
|
63
73
|
|
|
64
74
|
The preview mode allows you to view your plugin _in its destined environment_.
|
|
@@ -73,7 +83,7 @@ and use said application as its base instead.
|
|
|
73
83
|
|
|
74
84
|
To build your project, run the following from within your projects root:
|
|
75
85
|
```bash
|
|
76
|
-
vcmplugin build
|
|
86
|
+
npx vcmplugin build
|
|
77
87
|
```
|
|
78
88
|
This will build your application and place it in the `dist` directory.
|
|
79
89
|
|
|
@@ -81,7 +91,7 @@ This will build your application and place it in the `dist` directory.
|
|
|
81
91
|
|
|
82
92
|
To pack your project for productive use, run the following from within your projects root:
|
|
83
93
|
```bash
|
|
84
|
-
vcmplugin pack
|
|
94
|
+
npx vcmplugin pack
|
|
85
95
|
```
|
|
86
96
|
|
|
87
97
|
This will create a folder `dist` with a zip file containing your bundled code and assets.
|
|
@@ -137,19 +147,82 @@ or
|
|
|
137
147
|
import { Feature } from 'ol';
|
|
138
148
|
```
|
|
139
149
|
|
|
140
|
-
##
|
|
141
|
-
|
|
142
|
-
|
|
150
|
+
## VC Map Plugins
|
|
151
|
+
The following defines a plugin in its rough structure. If you use the `@vcmap/plugin-cli`
|
|
152
|
+
to create your project, a template already adhering to these specs will be created for you.
|
|
153
|
+
- All plugins must provide the following:
|
|
154
|
+
- `package.json` with name, description, version, author and dependencies.
|
|
155
|
+
- `config.json` with default parameters for the plugins' configuration.
|
|
156
|
+
- `README.md` describing the plugins' capabilities and usage.
|
|
157
|
+
- `src/index.js` JS entry point.
|
|
158
|
+
- Plugin names are defined by the plugins' package name and therefore must obey npm [package name guidelines](https://docs.npmjs.com/package-name-guidelines):
|
|
159
|
+
- choose a name that
|
|
160
|
+
- is unique
|
|
161
|
+
- is descriptive
|
|
162
|
+
- is lowercase
|
|
163
|
+
- is uri encode-able
|
|
164
|
+
- doesn't start with `.`, `_` or a digit
|
|
165
|
+
- doesn't contain white spaces or any special characters like `~\'!()*"`
|
|
166
|
+
- do not use scope `@vcmap`, since it is only to be used by official plugins provided
|
|
167
|
+
by virtual city systems. But you are encouraged to use your own scope.
|
|
168
|
+
- Plugin dependencies have to be defined in the `package.json`.
|
|
169
|
+
- `dependency`: all plugin specific dependencies NOT provided by the `@vcmap/ui`.
|
|
170
|
+
- `peerDependency`: dependencies provided by the `@vcmap/ui`,
|
|
171
|
+
- e.g. `@vcmap/core` or `@vcmap/ui` (see [About Peer Dependencies](#About_Peer_Dependencies) for more details)
|
|
172
|
+
- `devDependency`: all dependencies only required for development, e.g. `eslint`.
|
|
173
|
+
- Plugins can be published to NPM, but should contain both source and minified code
|
|
174
|
+
to allow seamless integration into the [VC Map UI](https://github.com/virtualcitySYSTEMS/map-ui) environment.
|
|
175
|
+
For this reason the package.json of a plugin defines two exports:
|
|
143
176
|
```json
|
|
144
177
|
{
|
|
145
|
-
"
|
|
146
|
-
"
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
178
|
+
".": "./src/index.js",
|
|
179
|
+
"./dist": "./dist/index.js"
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
### Plugin Interface:
|
|
185
|
+
Plugins must provide a function default export which returns an Object complying
|
|
186
|
+
with the VC Map Plugin Interface describe below:
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
declare interface VcsPlugin<T extends Object> {
|
|
190
|
+
readonly name: string;
|
|
191
|
+
readonly version: string;
|
|
192
|
+
initialize(app: VcsUiApp):void;
|
|
193
|
+
onVcsAppMounted(app: VcsUiApp):void;
|
|
194
|
+
toJSON():T;
|
|
195
|
+
destroy():void;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
declare function defaultExport<T extends Object>(config: T):VcsPlugin<T>;
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
A Simple JavaScript implementation of this interface can be seen below::
|
|
202
|
+
```javascript
|
|
203
|
+
// index.js
|
|
204
|
+
/**
|
|
205
|
+
* @param {PluginExampleConfig} config
|
|
206
|
+
* @returns {VcsPlugin}
|
|
207
|
+
*/
|
|
208
|
+
export default function defaultExport(config) {
|
|
209
|
+
return {
|
|
210
|
+
get name() {
|
|
211
|
+
return packageJSON.name;
|
|
212
|
+
},
|
|
213
|
+
get version() {
|
|
214
|
+
return packageJSON.version;
|
|
215
|
+
},
|
|
216
|
+
initialize(app) {},
|
|
217
|
+
onVcsAppMounted(app) {},
|
|
218
|
+
toJSON() {},
|
|
219
|
+
destroy() {},
|
|
153
220
|
}
|
|
154
221
|
}
|
|
155
222
|
```
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
## Notes on Developing
|
|
226
|
+
To develop the plugin-cli, be sure to not `npm link` into plugins, since this will
|
|
227
|
+
throw the resolver in resolving the @vcmap/ui peer dependency from the current plugin.
|
|
228
|
+
Instead run `npm pack` in the plugin cli and install the tarball in the plugin directly.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
default:
|
|
2
|
+
image: gitlab.virtualcitysystems.de:5050/vcsuite/devops/gitlabrunner/node:16-bullseye
|
|
3
|
+
|
|
4
|
+
variables:
|
|
5
|
+
GIT_CLONE_PATH: $CI_BUILDS_DIR/$CI_PROJECT_PATH_SLUG/$CI_COMMIT_REF_SLUG
|
|
6
|
+
|
|
7
|
+
stages:
|
|
8
|
+
- build
|
|
9
|
+
- test
|
|
10
|
+
- bundle
|
|
11
|
+
- version
|
|
12
|
+
- publish
|
|
13
|
+
|
|
14
|
+
.template: &job_definition
|
|
15
|
+
only:
|
|
16
|
+
- /^(feature-.*|hotfix-.*|main|release-.*)$/
|
|
17
|
+
tags:
|
|
18
|
+
- linux-2.0
|
|
19
|
+
|
|
20
|
+
build:
|
|
21
|
+
<<: *job_definition
|
|
22
|
+
script:
|
|
23
|
+
- npm set registry 'http://npmregistry:4873'
|
|
24
|
+
- npm ci
|
|
25
|
+
before_script:
|
|
26
|
+
- mkdir -p ~/.ssh
|
|
27
|
+
- chmod 700 ~/.ssh
|
|
28
|
+
- echo "$SSH_RUNNER_KEY" | tr -d '\r' > ~/.ssh/id_rsa
|
|
29
|
+
- chmod 600 ~/.ssh/id_rsa
|
|
30
|
+
- ssh-keyscan gitlab.virtualcitysystems.de >> ~/.ssh/known_hosts
|
|
31
|
+
- chmod 644 ~/.ssh/known_hosts
|
|
32
|
+
- git config user.name "Gitlab Runner"
|
|
33
|
+
- git config user.email "gitlab-runner@vc.systems"
|
|
34
|
+
stage: build
|
|
35
|
+
|
|
36
|
+
.after_build_template: &after_build_definition
|
|
37
|
+
<<: *job_definition
|
|
38
|
+
variables:
|
|
39
|
+
GIT_STRATEGY: none
|
|
40
|
+
|
|
41
|
+
lint:
|
|
42
|
+
<<: *after_build_definition
|
|
43
|
+
stage: test
|
|
44
|
+
script:
|
|
45
|
+
- npm run lint
|
|
46
|
+
|
|
47
|
+
audit:
|
|
48
|
+
<<: *after_build_definition
|
|
49
|
+
stage: test
|
|
50
|
+
script:
|
|
51
|
+
- npm audit --production --audit-level=low
|
|
52
|
+
|
|
53
|
+
bundle:
|
|
54
|
+
<<: *after_build_definition
|
|
55
|
+
stage: bundle
|
|
56
|
+
script:
|
|
57
|
+
- npm run build
|
|
58
|
+
|
|
59
|
+
version:
|
|
60
|
+
<<: *after_build_definition
|
|
61
|
+
stage: version
|
|
62
|
+
only:
|
|
63
|
+
variables:
|
|
64
|
+
- $PUBLISH
|
|
65
|
+
refs:
|
|
66
|
+
- /^(main|release-v.*)$/
|
|
67
|
+
script:
|
|
68
|
+
- npm version patch -m "%s [skip-ci]"
|
|
69
|
+
- TAG=`git describe --abbrev=0`
|
|
70
|
+
- echo git push git@gitlab:vcsuite/"$CI_PROJECT_PATH".git
|
|
71
|
+
- git push git@gitlab:vcsuite/"$CI_PROJECT_PATH".git $TAG
|
|
72
|
+
- git push git@gitlab:vcsuite/"$CI_PROJECT_PATH".git HEAD:$CI_COMMIT_REF_NAME
|
|
73
|
+
before_script:
|
|
74
|
+
- mkdir -p ~/.ssh
|
|
75
|
+
- chmod 700 ~/.ssh
|
|
76
|
+
- echo "$SSH_RUNNER_KEY" | tr -d '\r' > ~/.ssh/id_rsa
|
|
77
|
+
- chmod 600 ~/.ssh/id_rsa
|
|
78
|
+
- ssh-keyscan gitlab >> ~/.ssh/known_hosts
|
|
79
|
+
- chmod 644 ~/.ssh/known_hosts
|
|
80
|
+
- git config user.name "Gitlab Runner"
|
|
81
|
+
- git config user.email "gitlab-runner@vc.systems"
|
|
82
|
+
|
|
83
|
+
publish:
|
|
84
|
+
<<: *after_build_definition
|
|
85
|
+
stage: publish
|
|
86
|
+
only:
|
|
87
|
+
refs:
|
|
88
|
+
- /^(main|release-v.*)$/
|
|
89
|
+
variables:
|
|
90
|
+
- $PUBLISH
|
|
91
|
+
script:
|
|
92
|
+
- npm config set '//npmregistry:4873/:_authToken' "${VERDACCIO_TOKEN}"
|
|
93
|
+
- npm publish --registry http://npmregistry:4873
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-sheet>
|
|
3
|
+
<v-card class="pa-2 ma-2">
|
|
4
|
+
<v-container>
|
|
5
|
+
<v-row class="justify-center mb-4">
|
|
6
|
+
<h1>Hello World</h1>
|
|
7
|
+
</v-row>
|
|
8
|
+
<v-row class="justify-center">
|
|
9
|
+
<VcsButton
|
|
10
|
+
icon="mdi-times"
|
|
11
|
+
@click="closeSelf"
|
|
12
|
+
>
|
|
13
|
+
Close Window
|
|
14
|
+
</VcsButton>
|
|
15
|
+
</v-row>
|
|
16
|
+
</v-container>
|
|
17
|
+
</v-card>
|
|
18
|
+
</v-sheet>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<script>
|
|
22
|
+
import { inject } from '@vue/composition-api';
|
|
23
|
+
import { VcsButton } from '@vcsuite/ui-components';
|
|
24
|
+
|
|
25
|
+
export const windowId = 'hello_world_window_id';
|
|
26
|
+
|
|
27
|
+
export default {
|
|
28
|
+
name: 'HelloWorld',
|
|
29
|
+
components: { VcsButton },
|
|
30
|
+
setup() {
|
|
31
|
+
const app = inject('vcsApp');
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
closeSelf() {
|
|
35
|
+
app.windowManager.remove(windowId);
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
</script>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { WindowSlot } from '@vcmap/ui';
|
|
2
|
+
import { version, name } from '../package.json';
|
|
3
|
+
import HelloWorld, { windowId } from './helloWorld.vue';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {VcsApp} app - the app from which this plugin is loaded.
|
|
7
|
+
* @param {Object} config - the configuration of this plugin instance, passed in from the app.
|
|
8
|
+
* @returns {VcsPlugin}
|
|
9
|
+
*/
|
|
10
|
+
export default function helloWorld(app, config) {
|
|
11
|
+
return {
|
|
12
|
+
get name() { return name; },
|
|
13
|
+
get version() { return version; },
|
|
14
|
+
initialize: async (vcsUiApp) => {
|
|
15
|
+
console.log('Called before loading the rest of the current context. Passed in the containing Vcs UI App ');
|
|
16
|
+
console.log(app, config);
|
|
17
|
+
console.log(vcsUiApp);
|
|
18
|
+
},
|
|
19
|
+
onVcsAppMounted: async (vcsUiApp) => {
|
|
20
|
+
console.log('Called when the root UI component is mounted and managers are ready to accept components');
|
|
21
|
+
vcsUiApp.windowManager.add({
|
|
22
|
+
id: windowId,
|
|
23
|
+
component: HelloWorld,
|
|
24
|
+
WindowSlot: WindowSlot.DETACHED,
|
|
25
|
+
position: {
|
|
26
|
+
left: '40%',
|
|
27
|
+
right: '40%',
|
|
28
|
+
},
|
|
29
|
+
}, name);
|
|
30
|
+
},
|
|
31
|
+
toJSON: async () => {
|
|
32
|
+
console.log('Called when serializing this plugin instance');
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
package/cli.js
CHANGED
|
@@ -3,6 +3,7 @@ import program from 'commander';
|
|
|
3
3
|
import './src/defaultCommand.js';
|
|
4
4
|
import { create, serve, build, pack, preview } from './index.js';
|
|
5
5
|
import { version } from './src/create.js';
|
|
6
|
+
import setupMapUi from './src/setupMapUi.js';
|
|
6
7
|
|
|
7
8
|
program.version(version);
|
|
8
9
|
|
|
@@ -44,4 +45,8 @@ program
|
|
|
44
45
|
.option('--watch', 'watch file changes')
|
|
45
46
|
.safeAction(build);
|
|
46
47
|
|
|
48
|
+
program
|
|
49
|
+
.command('setup-map-ui')
|
|
50
|
+
.safeAction(setupMapUi);
|
|
51
|
+
|
|
47
52
|
program.parse(process.argv);
|
package/index.js
CHANGED
|
@@ -3,3 +3,5 @@ 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 setupMapUi } from './src/setupMapUi.js';
|
|
7
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vcmap/plugin-cli",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.4",
|
|
4
4
|
"description": "A CLI to help develop and build plugins for the VC Map",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -11,6 +11,10 @@
|
|
|
11
11
|
"lint": "eslint . --env node",
|
|
12
12
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
13
13
|
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/virtualcitySYSTEMS/map-plugin-cli.git"
|
|
17
|
+
},
|
|
14
18
|
"author": "Ben Kuster <bkuster@virtualcitysystems.de>",
|
|
15
19
|
"license": "MIT",
|
|
16
20
|
"files": [
|
|
@@ -32,21 +36,44 @@
|
|
|
32
36
|
"semver": "^7.3.5",
|
|
33
37
|
"unplugin-vue-components": "^0.17.21",
|
|
34
38
|
"vinyl-fs": "^3.0.3",
|
|
35
|
-
"vite": "^2.
|
|
39
|
+
"vite": "^2.9.1",
|
|
36
40
|
"vite-plugin-vue2": "^1.7.3",
|
|
37
41
|
"vue-template-compiler": "^2.6.14"
|
|
38
42
|
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"@vcmap/ui": "^5.0.0-rc.7",
|
|
45
|
+
"vue": "^2.6.14"
|
|
46
|
+
},
|
|
47
|
+
"peerDependenciesMeta": {
|
|
48
|
+
"@vcmap/ui": {
|
|
49
|
+
"optional": true
|
|
50
|
+
},
|
|
51
|
+
"vue": {
|
|
52
|
+
"optional": true
|
|
53
|
+
}
|
|
54
|
+
},
|
|
39
55
|
"devDependencies": {
|
|
40
56
|
"@vcsuite/eslint-config": "^2.1.1",
|
|
41
57
|
"eslint": "^8.9.0"
|
|
42
58
|
},
|
|
43
59
|
"eslintIgnore": [
|
|
44
|
-
"node_modules"
|
|
60
|
+
"node_modules",
|
|
61
|
+
"assets/helloWorld"
|
|
45
62
|
],
|
|
46
63
|
"eslintConfig": {
|
|
47
64
|
"extends": "@vcsuite/eslint-config/node",
|
|
48
65
|
"parserOptions": {
|
|
49
66
|
"ecmaVersion": 2020
|
|
67
|
+
},
|
|
68
|
+
"rules": {
|
|
69
|
+
"import/no-unresolved": [
|
|
70
|
+
2,
|
|
71
|
+
{
|
|
72
|
+
"ignore": [
|
|
73
|
+
"^@vcmap/ui"
|
|
74
|
+
]
|
|
75
|
+
}
|
|
76
|
+
]
|
|
50
77
|
}
|
|
51
78
|
},
|
|
52
79
|
"engines": {
|
package/src/build.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
|
-
import
|
|
2
|
+
import fs from 'fs/promises';
|
|
3
3
|
import { createVuePlugin } from 'vite-plugin-vue2';
|
|
4
4
|
import vcsOl from '@vcmap/rollup-plugin-vcs-ol';
|
|
5
5
|
import { logger } from '@vcsuite/cli-logger';
|
|
6
6
|
import { VuetifyResolver } from 'unplugin-vue-components/dist/resolvers.js';
|
|
7
7
|
import Components from 'unplugin-vue-components/dist/vite.js';
|
|
8
8
|
import { getPluginEntry, getPluginName } from './packageJsonHelpers.js';
|
|
9
|
+
import { getContext } from './context.js';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* @typedef {Object} BuildOptions
|
|
@@ -13,38 +14,45 @@ import { getPluginEntry, getPluginName } from './packageJsonHelpers.js';
|
|
|
13
14
|
* @property {boolean} [watch]
|
|
14
15
|
*/
|
|
15
16
|
|
|
17
|
+
export function getDefaultConfig() {
|
|
18
|
+
return {
|
|
19
|
+
publicDir: false,
|
|
20
|
+
plugins: [
|
|
21
|
+
createVuePlugin(),
|
|
22
|
+
Components({
|
|
23
|
+
resolvers: [
|
|
24
|
+
VuetifyResolver(),
|
|
25
|
+
],
|
|
26
|
+
dirs: ['./src'],
|
|
27
|
+
include: [],
|
|
28
|
+
exclude: [],
|
|
29
|
+
}),
|
|
30
|
+
vcsOl(),
|
|
31
|
+
],
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
16
35
|
/**
|
|
17
36
|
* @param {string} pluginName
|
|
18
37
|
* @returns {Object<string, string>}
|
|
19
38
|
*/
|
|
20
|
-
export function getLibraryPaths(pluginName) {
|
|
39
|
+
export async function getLibraryPaths(pluginName) {
|
|
40
|
+
const { libraries } = await import('@vcmap/ui/build/buildHelpers.js');
|
|
21
41
|
const pluginPath = path.join('plugins', ...pluginName.split('/'));
|
|
22
|
-
|
|
23
|
-
const libraries = {
|
|
24
|
-
vue: 'vue',
|
|
25
|
-
'@vue/composition-api': 'vue-composition-api',
|
|
26
|
-
'@vcmap/cesium': 'cesium',
|
|
27
|
-
ol: 'ol',
|
|
28
|
-
'@vcmap/core': 'core',
|
|
29
|
-
'vuetify/lib': 'vuetify',
|
|
30
|
-
'@vcsuite/ui-components': 'uicomponents',
|
|
31
|
-
'@vcmap/ui': 'ui',
|
|
32
|
-
};
|
|
33
|
-
|
|
42
|
+
const libraryPaths = {};
|
|
34
43
|
Object.entries(libraries).forEach(([library, assetName]) => {
|
|
35
44
|
const assetPath = path.join('assets', `${assetName}.js`);
|
|
36
45
|
|
|
37
|
-
|
|
46
|
+
libraryPaths[library] = path.relative(pluginPath, assetPath);
|
|
38
47
|
});
|
|
39
|
-
return
|
|
48
|
+
return libraryPaths;
|
|
40
49
|
}
|
|
41
50
|
|
|
42
51
|
/**
|
|
43
52
|
* @param {BuildOptions} options
|
|
44
|
-
* @param {boolean} [preview]
|
|
45
53
|
* @returns {Promise<void>}
|
|
46
54
|
*/
|
|
47
|
-
export default async function buildModule(options
|
|
55
|
+
export default async function buildModule(options) {
|
|
48
56
|
const entry = await getPluginEntry();
|
|
49
57
|
if (path.relative('src', entry).startsWith('.')) {
|
|
50
58
|
logger.warning(`detected irregular entry ${entry}`);
|
|
@@ -52,67 +60,35 @@ export default async function buildModule(options, preview) {
|
|
|
52
60
|
}
|
|
53
61
|
|
|
54
62
|
const pluginName = await getPluginName();
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
await
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
resolvers: [
|
|
63
|
-
VuetifyResolver(),
|
|
64
|
-
],
|
|
65
|
-
dirs: ['./src'],
|
|
66
|
-
include: [],
|
|
67
|
-
exclude: [],
|
|
68
|
-
}),
|
|
69
|
-
vcsOl(),
|
|
70
|
-
{
|
|
71
|
-
name: 'pluginCssLoaderPrefix',
|
|
72
|
-
generateBundle(opts, bundle) {
|
|
73
|
-
const indexJs = bundle['index.js'];
|
|
74
|
-
if (indexJs && indexJs.code) {
|
|
75
|
-
const resource = preview ?
|
|
76
|
-
'./dist/style.css' :
|
|
77
|
-
`./plugins/${pluginName}/style.css`;
|
|
78
|
-
|
|
79
|
-
indexJs.code = `
|
|
80
|
-
function loadCss(href) {
|
|
81
|
-
return new Promise((resolve, reject) => {
|
|
82
|
-
const elem = document.createElement('link');
|
|
83
|
-
elem.rel = 'stylesheet';
|
|
84
|
-
elem.href = href;
|
|
85
|
-
elem.defer = false;
|
|
86
|
-
elem.async = false;
|
|
87
|
-
elem.onload = resolve;
|
|
88
|
-
elem.onerror = reject;
|
|
89
|
-
document.head.appendChild(elem);
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
await loadCss('${resource}');
|
|
93
|
-
${indexJs.code}
|
|
94
|
-
`;
|
|
95
|
-
}
|
|
96
|
-
},
|
|
97
|
-
},
|
|
98
|
-
],
|
|
63
|
+
const libraryPaths = await getLibraryPaths(pluginName);
|
|
64
|
+
const distPath = path.join(getContext(), 'dist');
|
|
65
|
+
await fs.rm(distPath, { recursive: true, force: true });
|
|
66
|
+
await fs.mkdir(distPath);
|
|
67
|
+
const external = Object.keys(libraryPaths);
|
|
68
|
+
const config = {
|
|
69
|
+
...getDefaultConfig(),
|
|
99
70
|
esbuild: {
|
|
100
71
|
minify: !options.development,
|
|
101
72
|
},
|
|
102
73
|
build: {
|
|
103
|
-
|
|
74
|
+
write: false,
|
|
75
|
+
emptyOutDir: false,
|
|
104
76
|
lib: {
|
|
105
77
|
entry,
|
|
106
78
|
formats: ['es'],
|
|
107
79
|
fileName: () => 'index.js',
|
|
108
80
|
},
|
|
109
81
|
rollupOptions: {
|
|
110
|
-
external
|
|
82
|
+
external,
|
|
111
83
|
output: {
|
|
112
|
-
paths:
|
|
84
|
+
paths: libraryPaths,
|
|
113
85
|
},
|
|
114
86
|
},
|
|
115
|
-
watch: options.watch ? {
|
|
87
|
+
watch: options.watch ? {
|
|
88
|
+
skipWrite: true,
|
|
89
|
+
} : null,
|
|
116
90
|
},
|
|
117
|
-
}
|
|
91
|
+
};
|
|
92
|
+
const { buildLibrary } = await import('@vcmap/ui/build/buildHelpers.js');
|
|
93
|
+
await buildLibrary(config, '', 'index', '', true);
|
|
118
94
|
}
|
package/src/create.js
CHANGED
|
@@ -17,9 +17,10 @@ export const { version, name } = JSON.parse(fs.readFileSync(path.join(getDirname
|
|
|
17
17
|
* @property {string} description
|
|
18
18
|
* @property {Array<Object>} scripts
|
|
19
19
|
* @property {string} author
|
|
20
|
+
* @property {string} repository
|
|
20
21
|
* @property {string} license
|
|
21
|
-
* @property {string}
|
|
22
|
-
* @property {boolean}
|
|
22
|
+
* @property {string} registry
|
|
23
|
+
* @property {boolean} addCiCd
|
|
23
24
|
* @property {Array<string>} peerDeps
|
|
24
25
|
*/
|
|
25
26
|
|
|
@@ -47,16 +48,42 @@ async function createPluginTemplate(options) {
|
|
|
47
48
|
version: options.version,
|
|
48
49
|
description: options.description,
|
|
49
50
|
main: 'src/index.js',
|
|
50
|
-
scripts: Object.assign({}, ...options.scripts),
|
|
51
|
+
scripts: Object.assign({ prepublishOnly: 'vcmplugin build' }, ...options.scripts),
|
|
51
52
|
author: options.author,
|
|
52
53
|
license: options.license,
|
|
53
|
-
engines: {
|
|
54
|
-
vcm: options.mapVersion,
|
|
55
|
-
},
|
|
56
54
|
dependencies: {},
|
|
57
|
-
|
|
55
|
+
keywords: [
|
|
56
|
+
'vcmap',
|
|
57
|
+
'plugin',
|
|
58
|
+
],
|
|
59
|
+
files: [
|
|
60
|
+
'src/',
|
|
61
|
+
'dist/',
|
|
62
|
+
'plugin-assets/',
|
|
63
|
+
'LICENSE.md',
|
|
64
|
+
'README.md',
|
|
65
|
+
],
|
|
66
|
+
exports: {
|
|
67
|
+
'.': './src/index.js',
|
|
68
|
+
'./dist': './dist/index.js',
|
|
69
|
+
},
|
|
58
70
|
};
|
|
59
71
|
|
|
72
|
+
if (options.repository) {
|
|
73
|
+
packageJson.repository = {
|
|
74
|
+
url: options.repository,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const installEsLint = options.scripts.find(script => script.lint);
|
|
79
|
+
if (installEsLint) {
|
|
80
|
+
packageJson.eslintIgnore = ['node_modules'];
|
|
81
|
+
packageJson.eslintConfig = {
|
|
82
|
+
root: true,
|
|
83
|
+
extends: '@vcsuite/eslint-config/vue',
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
60
87
|
const writePackagePromise = fs.promises.writeFile(
|
|
61
88
|
path.join(pluginPath, 'package.json'),
|
|
62
89
|
JSON.stringify(packageJson, null, 2),
|
|
@@ -71,6 +98,11 @@ async function createPluginTemplate(options) {
|
|
|
71
98
|
JSON.stringify(configJson, null, 2),
|
|
72
99
|
);
|
|
73
100
|
|
|
101
|
+
const writeNpmrcPromise = fs.promises.writeFile(
|
|
102
|
+
path.join(pluginPath, '.npmrc'),
|
|
103
|
+
`registry=${options.registry}\n`,
|
|
104
|
+
);
|
|
105
|
+
|
|
74
106
|
const writeReadmePromise = fs.promises.writeFile(
|
|
75
107
|
path.join(pluginPath, 'README.md'),
|
|
76
108
|
[
|
|
@@ -79,36 +111,27 @@ async function createPluginTemplate(options) {
|
|
|
79
111
|
].join('\n'),
|
|
80
112
|
);
|
|
81
113
|
|
|
114
|
+
const writeChangesPromise = fs.promises.writeFile(
|
|
115
|
+
path.join(pluginPath, 'CHANGES.md'),
|
|
116
|
+
`# v${options.version}\nDocument features and fixes`,
|
|
117
|
+
);
|
|
118
|
+
|
|
82
119
|
await fs.promises.mkdir(path.join(pluginPath, 'src'));
|
|
83
120
|
logger.debug('created src directory');
|
|
84
121
|
|
|
85
|
-
const
|
|
86
|
-
path.join(
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
'',
|
|
90
|
-
'/**',
|
|
91
|
-
' * @param {VcsApp} app - the app from which this plugin is loaded.',
|
|
92
|
-
' * @param {Object} config - the configuration of this plugin instance, passed in from the app.',
|
|
93
|
-
' */',
|
|
94
|
-
'export default function(app, config) {',
|
|
95
|
-
' return {',
|
|
96
|
-
' get name() { return name; },',
|
|
97
|
-
' get version() { return version; },',
|
|
98
|
-
' initialize: async (vcsUiApp) => { console.log(\'Called before loading the rest of the current context. Passed in the containing Vcs UI App \'); },',
|
|
99
|
-
' onVcsAppMounted: async (vcsUiApp) => { console.log(\'Called when the root UI component is mounted and managers are ready to accept components\'); },',
|
|
100
|
-
' toJSON: async () => { console.log(\'Called when serializing this plugin instance\'); },',
|
|
101
|
-
' };',
|
|
102
|
-
'};',
|
|
103
|
-
'',
|
|
104
|
-
].join('\n'),
|
|
122
|
+
const copyTemplatePromise = fs.promises.cp(
|
|
123
|
+
path.join(getDirname(), '..', 'assets', 'helloWorld'),
|
|
124
|
+
pluginPath,
|
|
125
|
+
{ recursive: true },
|
|
105
126
|
);
|
|
106
127
|
|
|
107
128
|
await Promise.all([
|
|
108
129
|
writePackagePromise,
|
|
109
130
|
writeConfigPromise,
|
|
131
|
+
writeNpmrcPromise,
|
|
110
132
|
writeReadmePromise,
|
|
111
|
-
|
|
133
|
+
writeChangesPromise,
|
|
134
|
+
copyTemplatePromise,
|
|
112
135
|
writeLicense(options.author, options.license, pluginPath),
|
|
113
136
|
]);
|
|
114
137
|
|
|
@@ -116,13 +139,19 @@ async function createPluginTemplate(options) {
|
|
|
116
139
|
logger.spin('installing dependencies... (this may take a while)');
|
|
117
140
|
const exec = util.promisify(childProcess.exec);
|
|
118
141
|
try {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
installCmd = `${installCmd} --save-peer ${options.peerDeps.join(' ')}`;
|
|
122
|
-
}
|
|
142
|
+
options.peerDeps.push('@vcmap/ui');
|
|
143
|
+
const installCmd = `npm i --save-peer ${options.peerDeps.join(' ')}`;
|
|
123
144
|
const { stdout, stderr } = await exec(installCmd, { cwd: pluginPath });
|
|
124
145
|
logger.log(stdout);
|
|
125
146
|
logger.error(stderr);
|
|
147
|
+
const devDeps = [`${name}@${version}`];
|
|
148
|
+
if (installEsLint) {
|
|
149
|
+
devDeps.push('@vcsuite/eslint-config');
|
|
150
|
+
}
|
|
151
|
+
const installDevCmd = `npm i --save-dev ${devDeps.join(' ')}`;
|
|
152
|
+
const { stdout: stdoutDev, stderr: stderrDev } = await exec(installDevCmd, { cwd: pluginPath });
|
|
153
|
+
logger.log(stdoutDev);
|
|
154
|
+
logger.error(stderrDev);
|
|
126
155
|
logger.success('installed dependencies');
|
|
127
156
|
} catch (e) {
|
|
128
157
|
logger.error(e);
|
|
@@ -137,15 +166,14 @@ async function createPluginTemplate(options) {
|
|
|
137
166
|
*/
|
|
138
167
|
export default async function create() {
|
|
139
168
|
const scriptChoices = [
|
|
140
|
-
{ title: 'build', value: { build: 'vcmplugin build' } },
|
|
141
|
-
{ title: 'pack', value: { pack: 'vcmplugin pack' } },
|
|
142
|
-
{ title: 'start', value: { start: 'vcmplugin serve' } },
|
|
143
|
-
{ title: 'preview', value: { preview: 'vcmplugin preview' } },
|
|
144
|
-
{ title: '
|
|
169
|
+
{ title: 'build', value: { build: 'vcmplugin build' }, selected: true },
|
|
170
|
+
{ title: 'pack', value: { pack: 'vcmplugin pack' }, selected: true },
|
|
171
|
+
{ title: 'start', value: { start: 'vcmplugin serve' }, selected: true },
|
|
172
|
+
{ title: 'preview', value: { preview: 'vcmplugin preview' }, selected: true },
|
|
173
|
+
{ title: 'lint', value: { lint: 'eslint "{src,tests}/**/*.{js,vue}"' }, selected: true },
|
|
145
174
|
];
|
|
146
175
|
|
|
147
176
|
const peerDependencyChoices = [
|
|
148
|
-
{ title: '@vcmap/ui', value: '@vcmap/ui', selected: true },
|
|
149
177
|
{ title: '@vcsuite/ui-components', value: '@vcsuite/ui-components', selected: true },
|
|
150
178
|
{ title: '@vcmap/core', value: '@vcmap/core' },
|
|
151
179
|
{ title: '@vcmap/cesium', value: '@vcmap/cesium' },
|
|
@@ -195,6 +223,12 @@ export default async function create() {
|
|
|
195
223
|
message: 'Author',
|
|
196
224
|
initial: 'author <email>',
|
|
197
225
|
},
|
|
226
|
+
{
|
|
227
|
+
type: 'text',
|
|
228
|
+
name: 'repository',
|
|
229
|
+
message: 'Repository url',
|
|
230
|
+
// initial: (prev, values) => `https://github.com/virtualcitySYSTEMS/${values.name}.git`,
|
|
231
|
+
},
|
|
198
232
|
{
|
|
199
233
|
type: 'select',
|
|
200
234
|
name: 'license',
|
|
@@ -208,9 +242,9 @@ export default async function create() {
|
|
|
208
242
|
},
|
|
209
243
|
{
|
|
210
244
|
type: 'text',
|
|
211
|
-
name: '
|
|
212
|
-
message: '
|
|
213
|
-
initial: '
|
|
245
|
+
name: 'registry',
|
|
246
|
+
message: 'Set default npm registry',
|
|
247
|
+
initial: 'https://registry.npmjs.org',
|
|
214
248
|
},
|
|
215
249
|
{
|
|
216
250
|
name: 'peerDeps',
|
|
@@ -221,9 +255,9 @@ export default async function create() {
|
|
|
221
255
|
},
|
|
222
256
|
{
|
|
223
257
|
type: 'toggle',
|
|
224
|
-
name: '
|
|
225
|
-
message: 'Add
|
|
226
|
-
initial:
|
|
258
|
+
name: 'addCiCd',
|
|
259
|
+
message: 'Add default VCS gitlab ci/cd?',
|
|
260
|
+
initial: false,
|
|
227
261
|
active: 'yes',
|
|
228
262
|
inactive: 'no',
|
|
229
263
|
},
|
package/src/hostingHelpers.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { fileURLToPath, URL } from 'url';
|
|
2
|
+
import { promisify } from 'util';
|
|
3
|
+
import { exec } from 'child_process';
|
|
2
4
|
import https from 'https';
|
|
3
5
|
import http from 'http';
|
|
4
6
|
import fs from 'fs';
|
|
@@ -15,8 +17,21 @@ import { getPluginEntry, getPluginName } from './packageJsonHelpers.js';
|
|
|
15
17
|
* @property {boolean} [https]
|
|
16
18
|
*/
|
|
17
19
|
|
|
20
|
+
/**
|
|
21
|
+
* @type {(arg1: string, opt?: Object) => Promise<string>}
|
|
22
|
+
*/
|
|
23
|
+
const promiseExec = promisify(exec);
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param {...string} pathSegments
|
|
27
|
+
* @returns {string}
|
|
28
|
+
*/
|
|
29
|
+
export function resolveMapUi(...pathSegments) {
|
|
30
|
+
return path.join(getContext(), 'node_modules', '@vcmap', 'ui', ...pathSegments);
|
|
31
|
+
}
|
|
32
|
+
|
|
18
33
|
export function checkReservedDirectories() {
|
|
19
|
-
['assets', 'plugins']
|
|
34
|
+
['assets', 'plugins', 'config']
|
|
20
35
|
.forEach((dir) => {
|
|
21
36
|
if (fs.existsSync(path.join(getContext(), dir))) {
|
|
22
37
|
logger.warning(`found reserved directory ${dir}. serving my not work as exptected`);
|
|
@@ -69,13 +84,13 @@ export async function readConfigJson(fileName) {
|
|
|
69
84
|
return config;
|
|
70
85
|
}
|
|
71
86
|
|
|
72
|
-
|
|
87
|
+
const configMap = new Map();
|
|
73
88
|
|
|
74
89
|
/**
|
|
75
90
|
* @returns {Promise<string>}
|
|
76
91
|
*/
|
|
77
92
|
export async function printVcmapUiVersion() {
|
|
78
|
-
const packageJsonPath =
|
|
93
|
+
const packageJsonPath = resolveMapUi('package.json');
|
|
79
94
|
if (!fs.existsSync(packageJsonPath)) {
|
|
80
95
|
throw new Error(`Cannot find the @vcmap/ui package in ${getContext()}. Are you sure you installed it?`);
|
|
81
96
|
}
|
|
@@ -85,6 +100,24 @@ export async function printVcmapUiVersion() {
|
|
|
85
100
|
logger.info(`Using @vcmap/ui version: ${version} found in current project.`);
|
|
86
101
|
}
|
|
87
102
|
|
|
103
|
+
/**
|
|
104
|
+
* @param {Object} config
|
|
105
|
+
* @param {Object} pluginConfig
|
|
106
|
+
* @param {boolean} production
|
|
107
|
+
* @returns {Promise<void>}
|
|
108
|
+
*/
|
|
109
|
+
export async function reWriteConfig(config, pluginConfig, production) {
|
|
110
|
+
config.plugins = config.plugins ?? []; // XXX check if we have plugins in this repos dependencies?
|
|
111
|
+
pluginConfig.entry = production ? 'dist/index.js' : await getPluginEntry();
|
|
112
|
+
pluginConfig.name = await getPluginName();
|
|
113
|
+
const idx = config.plugins.findIndex(p => p.name === pluginConfig.name);
|
|
114
|
+
if (idx > -1) {
|
|
115
|
+
config.plugins.splice(idx, 1, pluginConfig);
|
|
116
|
+
} else {
|
|
117
|
+
config.plugins.push(pluginConfig);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
88
121
|
/**
|
|
89
122
|
* @param {string} [mapConfig] - fs or https to config. defaults to @vcmap/ui/map.config.json
|
|
90
123
|
* @param {string} [auth]
|
|
@@ -93,9 +126,9 @@ export async function printVcmapUiVersion() {
|
|
|
93
126
|
* @returns {Promise<unknown>}
|
|
94
127
|
*/
|
|
95
128
|
export function getConfigJson(mapConfig, auth, production, configFile) {
|
|
96
|
-
const usedConfig = mapConfig ||
|
|
97
|
-
if (
|
|
98
|
-
return Promise.resolve(
|
|
129
|
+
const usedConfig = mapConfig || resolveMapUi('map.config.json');
|
|
130
|
+
if (configMap.has('map.config.json')) {
|
|
131
|
+
return Promise.resolve(configMap.get('map.config.json'));
|
|
99
132
|
}
|
|
100
133
|
const isWebVcm = /^https?:\/\//.test(usedConfig);
|
|
101
134
|
return new Promise((resolve, reject) => {
|
|
@@ -107,17 +140,10 @@ export function getConfigJson(mapConfig, auth, production, configFile) {
|
|
|
107
140
|
|
|
108
141
|
stream.on('close', async () => {
|
|
109
142
|
try {
|
|
110
|
-
configJson = JSON.parse(data);
|
|
111
|
-
|
|
143
|
+
const configJson = JSON.parse(data);
|
|
144
|
+
configMap.set('map.config.json', configJson);
|
|
112
145
|
const pluginConfig = await readConfigJson(configFile);
|
|
113
|
-
pluginConfig
|
|
114
|
-
pluginConfig.name = await getPluginName();
|
|
115
|
-
const idx = configJson.plugins.findIndex(p => p.name === pluginConfig.name);
|
|
116
|
-
if (idx > -1) {
|
|
117
|
-
configJson.plugins.splice(idx, 1, pluginConfig);
|
|
118
|
-
} else {
|
|
119
|
-
configJson.plugins.push(pluginConfig);
|
|
120
|
-
}
|
|
146
|
+
await reWriteConfig(configJson, pluginConfig, production);
|
|
121
147
|
resolve(configJson);
|
|
122
148
|
} catch (e) {
|
|
123
149
|
reject(e);
|
|
@@ -167,7 +193,7 @@ export function createConfigJsonReloadPlugin() {
|
|
|
167
193
|
name: 'ConfigJsonReload',
|
|
168
194
|
handleHotUpdate({ file }) {
|
|
169
195
|
if (file === path.join(getContext(), 'config.json')) {
|
|
170
|
-
|
|
196
|
+
configMap.clear();
|
|
171
197
|
}
|
|
172
198
|
},
|
|
173
199
|
};
|
|
@@ -192,13 +218,52 @@ export function addMapConfigRoute(app, mapConfig, auth, configFile, production)
|
|
|
192
218
|
});
|
|
193
219
|
}
|
|
194
220
|
|
|
221
|
+
/**
|
|
222
|
+
* @param {Express} app
|
|
223
|
+
* @param {string} [auth]
|
|
224
|
+
* @param {string} [configFileName]
|
|
225
|
+
* @param {boolean} [production]
|
|
226
|
+
*/
|
|
227
|
+
export async function addConfigRoute(app, auth, configFileName, production) { // IDEA pass in available plugins and strip unavailable ones?
|
|
228
|
+
const mapUiDir = resolveMapUi();
|
|
229
|
+
const pluginConfig = await readConfigJson(configFileName);
|
|
230
|
+
|
|
231
|
+
app.get('/config*', async (req, res) => {
|
|
232
|
+
const { url } = req;
|
|
233
|
+
const fileName = path.join(mapUiDir, ...url.substring(1).split('/'));
|
|
234
|
+
let response;
|
|
235
|
+
if (configMap.has(url)) {
|
|
236
|
+
response = JSON.stringify(configMap.get(url));
|
|
237
|
+
} else if (fs.existsSync(fileName)) {
|
|
238
|
+
try {
|
|
239
|
+
const configContent = await fs.promises.readFile(fileName);
|
|
240
|
+
const config = JSON.parse(configContent);
|
|
241
|
+
configMap.set(url, config);
|
|
242
|
+
await reWriteConfig(config, pluginConfig, production);
|
|
243
|
+
response = JSON.stringify(config);
|
|
244
|
+
} catch (e) {
|
|
245
|
+
configMap.delete(url);
|
|
246
|
+
logger.warning(`Failed to parse config ${url}`);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (!response) {
|
|
251
|
+
res.statusCode = 404;
|
|
252
|
+
} else {
|
|
253
|
+
res.setHeader('Content-Type', 'application/json');
|
|
254
|
+
res.write(response);
|
|
255
|
+
}
|
|
256
|
+
res.end();
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
195
260
|
/**
|
|
196
261
|
* @param {boolean} [production]
|
|
197
262
|
* @returns {Promise<string>}
|
|
198
263
|
*/
|
|
199
264
|
export async function getMapUiIndexHtml(production) {
|
|
200
265
|
const indexHtmlFileName = production ?
|
|
201
|
-
|
|
266
|
+
resolveMapUi('dist', 'index.html') :
|
|
202
267
|
path.join(getDirname(), '..', 'assets', 'index.html');
|
|
203
268
|
const buffer = await fs.promises.readFile(indexHtmlFileName);
|
|
204
269
|
return buffer.toString();
|
|
@@ -217,10 +282,19 @@ export function addIndexRoute(app, server, production, hostedVcm, auth) {
|
|
|
217
282
|
await getIndexHtml(`${hostedVcm}/`, auth) :
|
|
218
283
|
await getMapUiIndexHtml(production); // TODO change hosted vcm index via option?
|
|
219
284
|
|
|
220
|
-
originalIndex = await server.transformIndexHtml('index.html', originalIndex);
|
|
285
|
+
originalIndex = await server.transformIndexHtml('/index.html', originalIndex);
|
|
286
|
+
|
|
221
287
|
res.status(200)
|
|
222
288
|
.set({ 'Content-Type': 'text/html' })
|
|
223
289
|
.end(originalIndex);
|
|
224
290
|
});
|
|
225
291
|
}
|
|
226
292
|
|
|
293
|
+
/**
|
|
294
|
+
* @param {string} command
|
|
295
|
+
* @returns {Promise<string>}
|
|
296
|
+
*/
|
|
297
|
+
export function executeUiNpm(command) {
|
|
298
|
+
const mapUiDir = resolveMapUi();
|
|
299
|
+
return promiseExec(`npm run ${command}`, { cwd: mapUiDir });
|
|
300
|
+
}
|
package/src/preview.js
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
|
+
import fs from 'fs';
|
|
2
3
|
import { createServer } from 'vite';
|
|
3
4
|
import express from 'express';
|
|
4
5
|
import { logger } from '@vcsuite/cli-logger';
|
|
5
6
|
import {
|
|
7
|
+
addConfigRoute,
|
|
6
8
|
addIndexRoute,
|
|
7
9
|
addMapConfigRoute,
|
|
8
10
|
checkReservedDirectories,
|
|
9
11
|
createConfigJsonReloadPlugin,
|
|
10
|
-
printVcmapUiVersion,
|
|
12
|
+
printVcmapUiVersion, resolveMapUi,
|
|
11
13
|
} from './hostingHelpers.js';
|
|
12
|
-
import build, { getLibraryPaths } from './build.js';
|
|
14
|
+
import build, { getDefaultConfig, getLibraryPaths } from './build.js';
|
|
13
15
|
import { getContext } from './context.js';
|
|
16
|
+
import setupMapUi from './setupMapUi.js';
|
|
14
17
|
|
|
15
18
|
/**
|
|
16
19
|
* @typedef {HostingOptions} PreviewOptions
|
|
@@ -34,8 +37,8 @@ function setAliases(alias, libraryPaths) {
|
|
|
34
37
|
*/
|
|
35
38
|
async function getServerOptions(hostedVcm, https) {
|
|
36
39
|
let proxy;
|
|
37
|
-
const normalLibraries = getLibraryPaths('normal');
|
|
38
|
-
const scopedLibraries = getLibraryPaths('@scoped/plugin');
|
|
40
|
+
const normalLibraries = await getLibraryPaths('normal');
|
|
41
|
+
const scopedLibraries = await getLibraryPaths('@scoped/plugin');
|
|
39
42
|
const alias = {};
|
|
40
43
|
setAliases(alias, normalLibraries);
|
|
41
44
|
setAliases(alias, scopedLibraries);
|
|
@@ -73,7 +76,7 @@ export default async function preview(options) {
|
|
|
73
76
|
await printVcmapUiVersion();
|
|
74
77
|
}
|
|
75
78
|
checkReservedDirectories();
|
|
76
|
-
build({ development: false, watch: true }
|
|
79
|
+
await build({ development: false, watch: true });
|
|
77
80
|
const app = express();
|
|
78
81
|
logger.info('Starting preview server...');
|
|
79
82
|
const server = await createServer(await getServerOptions(options.vcm, options.https));
|
|
@@ -82,8 +85,18 @@ export default async function preview(options) {
|
|
|
82
85
|
addIndexRoute(app, server, true, options.vcm, options.auth);
|
|
83
86
|
|
|
84
87
|
if (!options.vcm) {
|
|
88
|
+
logger.spin('compiling preview');
|
|
89
|
+
if (!fs.existsSync(resolveMapUi('plugins', 'node_modules'))) {
|
|
90
|
+
logger.info('Could not detect node_modules in map ui plugins. Assuming map UI not setup');
|
|
91
|
+
await setupMapUi();
|
|
92
|
+
}
|
|
93
|
+
const { buildPluginsForPreview } = await import('@vcmap/ui/build/buildHelpers.js');
|
|
94
|
+
await buildPluginsForPreview(getDefaultConfig(), true);
|
|
95
|
+
logger.stopSpinner();
|
|
96
|
+
logger.info('@vcmap/ui built for preview');
|
|
85
97
|
app.use('/assets', express.static(path.join(getContext(), 'node_modules', '@vcmap', 'ui', 'dist', 'assets')));
|
|
86
|
-
app.use('/plugins', express.static(path.join(getContext(), '
|
|
98
|
+
app.use('/plugins', express.static(path.join(getContext(), 'dist', 'plugins')));
|
|
99
|
+
await addConfigRoute(app, options.auth, options.config, true);
|
|
87
100
|
}
|
|
88
101
|
|
|
89
102
|
app.use(server.middlewares);
|
package/src/serve.js
CHANGED
|
@@ -8,18 +8,51 @@ import { VuetifyResolver } from 'unplugin-vue-components/dist/resolvers.js';
|
|
|
8
8
|
import Components from 'unplugin-vue-components/dist/vite.js';
|
|
9
9
|
import { getContext } from './context.js';
|
|
10
10
|
import {
|
|
11
|
+
addConfigRoute,
|
|
11
12
|
addIndexRoute,
|
|
12
13
|
addMapConfigRoute,
|
|
13
14
|
checkReservedDirectories,
|
|
14
15
|
createConfigJsonReloadPlugin,
|
|
15
16
|
printVcmapUiVersion,
|
|
17
|
+
resolveMapUi,
|
|
16
18
|
} from './hostingHelpers.js';
|
|
19
|
+
import { getPluginName } from './packageJsonHelpers.js';
|
|
17
20
|
|
|
18
21
|
/**
|
|
19
22
|
* @typedef {HostingOptions} ServeOptions
|
|
20
23
|
* @property {string} [mapConfig] - an filename or URL to a map config
|
|
21
24
|
*/
|
|
22
25
|
|
|
26
|
+
async function getProxy(protocol, port) {
|
|
27
|
+
const { default: getPluginProxies } = await import('@vcmap/ui/build/getPluginProxies.js');
|
|
28
|
+
const { determineHostIpFromInterfaces } = await import('@vcmap/ui/build/determineHost.js');
|
|
29
|
+
const { getInlinePlugins } = await import('@vcmap/ui/build/buildHelpers.js');
|
|
30
|
+
|
|
31
|
+
const target = `${protocol}://${determineHostIpFromInterfaces()}:${port}`;
|
|
32
|
+
const proxy = await getPluginProxies(target);
|
|
33
|
+
const mapUiPlugins = resolveMapUi('plugins');
|
|
34
|
+
const inlinePlugins = await getInlinePlugins();
|
|
35
|
+
inlinePlugins.forEach((inlinePlugin) => {
|
|
36
|
+
proxy[`^/plugins/${inlinePlugin}/.*`] = {
|
|
37
|
+
target,
|
|
38
|
+
rewrite: (route) => {
|
|
39
|
+
const rest = route.replace(new RegExp(`^/plugins/${inlinePlugin}/`), '');
|
|
40
|
+
const file = rest || 'index.js';
|
|
41
|
+
return path.posix.join(path.relative(getContext(), mapUiPlugins), inlinePlugin, file);
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const pluginRoutes = Object.keys(proxy);
|
|
47
|
+
const name = await getPluginName();
|
|
48
|
+
const hasThisPlugin = pluginRoutes.find(p => p.startsWith(`^/plugins/${name}`));
|
|
49
|
+
|
|
50
|
+
if (hasThisPlugin) {
|
|
51
|
+
delete proxy[hasThisPlugin];
|
|
52
|
+
}
|
|
53
|
+
return proxy;
|
|
54
|
+
}
|
|
55
|
+
|
|
23
56
|
/**
|
|
24
57
|
* @param {ServeOptions} options
|
|
25
58
|
* @returns {Promise<void>}
|
|
@@ -32,7 +65,10 @@ export default async function serve(options) {
|
|
|
32
65
|
await printVcmapUiVersion();
|
|
33
66
|
checkReservedDirectories();
|
|
34
67
|
const app = express();
|
|
68
|
+
const port = options.port || 8008;
|
|
69
|
+
|
|
35
70
|
logger.info('Starting development server...');
|
|
71
|
+
const proxy = await getProxy(options.https ? 'https' : 'http', port);
|
|
36
72
|
|
|
37
73
|
const server = await createServer({
|
|
38
74
|
root: getContext(),
|
|
@@ -66,15 +102,16 @@ export default async function serve(options) {
|
|
|
66
102
|
server: {
|
|
67
103
|
middlewareMode: 'html',
|
|
68
104
|
https: options.https,
|
|
105
|
+
proxy,
|
|
69
106
|
},
|
|
70
107
|
});
|
|
71
108
|
|
|
72
109
|
addMapConfigRoute(app, options.mapConfig, options.auth, options.config);
|
|
73
110
|
addIndexRoute(app, server);
|
|
111
|
+
await addConfigRoute(app, options.auth, options.config);
|
|
74
112
|
|
|
75
113
|
app.use(server.middlewares);
|
|
76
114
|
|
|
77
|
-
const port = options.port || 8008;
|
|
78
115
|
await app.listen(port);
|
|
79
116
|
logger.info(`Server running on port ${port}`);
|
|
80
117
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { logger } from '@vcsuite/cli-logger';
|
|
2
|
+
import { executeUiNpm } from './hostingHelpers.js';
|
|
3
|
+
|
|
4
|
+
export default async function setupMapUi() {
|
|
5
|
+
logger.spin('installing dev plugins in @vcmap/ui');
|
|
6
|
+
await executeUiNpm('install-plugins');
|
|
7
|
+
logger.stopSpinner();
|
|
8
|
+
logger.info('dev plugins installed');
|
|
9
|
+
}
|