@vcmap/plugin-cli 2.0.10 → 2.0.12
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 +70 -14
- package/assets/{helloWorld/.gitlab-ci.yml → .gitlab-ci.yml} +10 -0
- package/assets/gitignore +30 -0
- package/assets/index.html +29 -33
- package/assets/index.js +62 -0
- package/cli.js +7 -9
- package/index.js +1 -0
- package/package.json +8 -8
- package/src/build.js +0 -10
- package/src/buildStagingApp.js +12 -1
- package/src/create.js +198 -87
- package/src/hostingHelpers.js +9 -18
- package/src/packageJsonHelpers.js +34 -1
- package/src/pluginCliHelper.js +41 -0
- package/src/preview.js +13 -9
- package/src/serve.js +18 -17
- package/src/update.js +50 -0
- package/assets/helloWorld/build/staging/Dockerfile +0 -2
- package/assets/helloWorld/plugin-assets/vcs_logo.png +0 -0
- package/assets/helloWorld/src/helloWorld.vue +0 -54
- package/assets/helloWorld/src/index.js +0 -72
package/src/create.js
CHANGED
|
@@ -2,14 +2,12 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import prompts from 'prompts';
|
|
4
4
|
import semver from 'semver';
|
|
5
|
-
import
|
|
6
|
-
import childProcess from 'child_process';
|
|
5
|
+
import tar from 'tar';
|
|
7
6
|
import { logger } from '@vcsuite/cli-logger';
|
|
8
7
|
import { LicenseType, writeLicense } from './licenses.js';
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const exec = util.promisify(childProcess.exec);
|
|
8
|
+
import { DepType, installDeps } from './packageJsonHelpers.js';
|
|
9
|
+
import { updatePeerDependencies } from './update.js';
|
|
10
|
+
import { name, version, promiseExec, getDirname } from './pluginCliHelper.js';
|
|
13
11
|
|
|
14
12
|
/**
|
|
15
13
|
* @typedef {Object} PluginTemplateOptions
|
|
@@ -20,77 +18,120 @@ const exec = util.promisify(childProcess.exec);
|
|
|
20
18
|
* @property {string} author
|
|
21
19
|
* @property {string} repository
|
|
22
20
|
* @property {string} license
|
|
21
|
+
* @property {string} template
|
|
23
22
|
* @property {Array<string>} peerDeps
|
|
23
|
+
* @property {boolean} gitlabCi
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
* @
|
|
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
|
|
27
|
+
* @param {string} pluginName
|
|
38
28
|
* @param {string} pluginPath
|
|
39
|
-
* @
|
|
29
|
+
* @param {string[]} filter - files or dirs to be extracted
|
|
40
30
|
*/
|
|
41
|
-
async function
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
31
|
+
async function downloadAndExtractPluginTar(pluginName, pluginPath, filter = undefined) {
|
|
32
|
+
const logMsg = filter ? filter.join(', ') : pluginName;
|
|
33
|
+
logger.spin(`Downloading and extracting ${logMsg}`);
|
|
34
|
+
const { stdout: packOut, stderr: packErr } = await promiseExec(`npm pack ${pluginName} --quiet`, { cwd: pluginPath });
|
|
35
|
+
logger.error(packErr);
|
|
36
|
+
|
|
37
|
+
const tarName = packOut.trim();
|
|
38
|
+
const tarPath = path.join(pluginPath, tarName);
|
|
39
|
+
const extractOptions = {
|
|
40
|
+
file: tarPath,
|
|
41
|
+
cwd: pluginPath,
|
|
42
|
+
strip: 1,
|
|
43
|
+
};
|
|
44
|
+
if (filter) {
|
|
45
|
+
extractOptions.filter = entryPath => filter.some(f => entryPath.includes(f));
|
|
47
46
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
logger.
|
|
51
|
-
logger.
|
|
47
|
+
await tar.x(extractOptions);
|
|
48
|
+
await fs.promises.rm(tarPath);
|
|
49
|
+
logger.success(`Downloaded and extracted template ${logMsg}`);
|
|
50
|
+
logger.stopSpinner();
|
|
52
51
|
}
|
|
53
52
|
|
|
54
53
|
/**
|
|
55
|
-
*
|
|
54
|
+
* Copies an existing plugin as template and edits package.json
|
|
55
|
+
* @param {PluginTemplateOptions} options
|
|
56
56
|
* @param {string} pluginPath
|
|
57
57
|
* @returns {Promise<void>}
|
|
58
58
|
*/
|
|
59
|
-
async function
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
async function copyPluginTemplate(options, pluginPath) {
|
|
60
|
+
await downloadAndExtractPluginTar(options.template, pluginPath);
|
|
61
|
+
|
|
62
|
+
const pluginPackageJson = JSON.parse((await fs.promises.readFile(path.join(pluginPath, 'package.json'))).toString());
|
|
63
|
+
const userPackageJson = {
|
|
64
|
+
name: options.name,
|
|
65
|
+
version: options.version,
|
|
66
|
+
description: options.description,
|
|
67
|
+
author: options.author,
|
|
68
|
+
license: options.license,
|
|
69
|
+
};
|
|
70
|
+
const packageJson = { ...pluginPackageJson, ...userPackageJson };
|
|
71
|
+
if (options.repository) {
|
|
72
|
+
packageJson.repository = {
|
|
73
|
+
url: options.repository,
|
|
74
|
+
};
|
|
75
|
+
} else {
|
|
76
|
+
delete options.repository;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const writePackagePromise = fs.promises.writeFile(
|
|
80
|
+
path.join(pluginPath, 'package.json'),
|
|
81
|
+
JSON.stringify(packageJson, null, 2),
|
|
62
82
|
);
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
83
|
+
|
|
84
|
+
const configJson = JSON.parse((await fs.promises.readFile(path.join(pluginPath, 'config.json'))).toString());
|
|
85
|
+
configJson.name = options.name;
|
|
86
|
+
|
|
87
|
+
const writeConfigPromise = fs.promises.writeFile(
|
|
88
|
+
path.join(pluginPath, 'config.json'),
|
|
89
|
+
JSON.stringify(configJson, null, 2),
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
await Promise.all([
|
|
93
|
+
writePackagePromise,
|
|
94
|
+
writeConfigPromise,
|
|
95
|
+
]);
|
|
96
|
+
logger.debug('created plugin template');
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
await updatePeerDependencies(packageJson.peerDependencies, pluginPath);
|
|
100
|
+
logger.spin('installing dependencies... (this may take a while)');
|
|
101
|
+
if (packageJson.dependencies) {
|
|
102
|
+
const deps = Object.entries(packageJson.dependencies)
|
|
103
|
+
.map(([depName, depVersion]) => `${depName}@${depVersion}`);
|
|
104
|
+
await installDeps(deps, DepType.DEP, pluginPath);
|
|
67
105
|
}
|
|
68
|
-
|
|
106
|
+
await installDeps([`${name}@${version}`], DepType.DEV, pluginPath);
|
|
107
|
+
logger.success('Installed dependencies');
|
|
108
|
+
} catch (e) {
|
|
109
|
+
logger.error(e);
|
|
110
|
+
logger.failure('Failed installing dependencies');
|
|
111
|
+
}
|
|
112
|
+
logger.stopSpinner();
|
|
69
113
|
}
|
|
70
114
|
|
|
71
115
|
/**
|
|
116
|
+
* Creates a plugin from scratch
|
|
72
117
|
* @param {PluginTemplateOptions} options
|
|
118
|
+
* @param {string} pluginPath
|
|
73
119
|
*/
|
|
74
|
-
async function createPluginTemplate(options) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
120
|
+
async function createPluginTemplate(options, pluginPath) {
|
|
121
|
+
const installVitest = options.scripts && options.scripts.find(script => script.test);
|
|
122
|
+
if (!installVitest) {
|
|
123
|
+
options.scripts.push({ test: 'echo "Error: no test specified" && exit 1' });
|
|
124
|
+
} else {
|
|
125
|
+
options.scripts.push(
|
|
126
|
+
{ coverage: 'vitest run --coverage' },
|
|
127
|
+
);
|
|
78
128
|
}
|
|
79
|
-
logger.info(`creating new plugin: ${options.name}`);
|
|
80
129
|
|
|
81
|
-
const pluginPath = path.join(process.cwd(), options.name);
|
|
82
|
-
if (fs.existsSync(pluginPath)) {
|
|
83
|
-
logger.error('plugin with the provided name already exists');
|
|
84
|
-
process.exit(1);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
await fs.promises.mkdir(pluginPath);
|
|
88
|
-
await fs.promises.mkdir(path.join(pluginPath, 'plugin-assets'));
|
|
89
|
-
logger.debug('created plugin directory');
|
|
90
130
|
const packageJson = {
|
|
91
131
|
name: options.name,
|
|
92
132
|
version: options.version,
|
|
93
133
|
description: options.description,
|
|
134
|
+
type: 'module',
|
|
94
135
|
main: 'src/index.js',
|
|
95
136
|
scripts: Object.assign({ prepublishOnly: 'vcmplugin build' }, ...options.scripts),
|
|
96
137
|
author: options.author,
|
|
@@ -142,6 +183,66 @@ async function createPluginTemplate(options) {
|
|
|
142
183
|
JSON.stringify(configJson, null, 2),
|
|
143
184
|
);
|
|
144
185
|
|
|
186
|
+
await fs.promises.mkdir(path.join(pluginPath, 'src'));
|
|
187
|
+
logger.debug('created src directory');
|
|
188
|
+
|
|
189
|
+
const copyIndexPromise = fs.promises.copyFile(
|
|
190
|
+
path.join(getDirname(), '..', 'assets', 'index.js'),
|
|
191
|
+
path.join(pluginPath, 'src', 'index.js'),
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
await Promise.all([
|
|
195
|
+
writePackagePromise,
|
|
196
|
+
writeConfigPromise,
|
|
197
|
+
copyIndexPromise,
|
|
198
|
+
]);
|
|
199
|
+
|
|
200
|
+
if (installVitest) {
|
|
201
|
+
logger.debug('setting up test environment');
|
|
202
|
+
await downloadAndExtractPluginTar('@vcmap/hello-world', pluginPath, ['tests', 'vitest.config.js']);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
try {
|
|
206
|
+
const peerDependencies = options.peerDeps.reduce((obj, key) => ({ ...obj, [key]: 'latest' }), {});
|
|
207
|
+
await updatePeerDependencies(peerDependencies, pluginPath);
|
|
208
|
+
logger.spin('installing dependencies... (this may take a while)');
|
|
209
|
+
const devDeps = [`${name}@${version}`];
|
|
210
|
+
if (installEsLint) {
|
|
211
|
+
devDeps.push('@vcsuite/eslint-config');
|
|
212
|
+
}
|
|
213
|
+
if (installVitest) {
|
|
214
|
+
devDeps.push('vite', 'vitest', '@vitest/coverage-c8', 'jest-canvas-mock', 'jsdom');
|
|
215
|
+
}
|
|
216
|
+
await installDeps(devDeps, DepType.DEV, pluginPath);
|
|
217
|
+
logger.success('Installed dependencies');
|
|
218
|
+
} catch (e) {
|
|
219
|
+
logger.error(e);
|
|
220
|
+
logger.failure('Failed installing dependencies');
|
|
221
|
+
}
|
|
222
|
+
logger.stopSpinner();
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Creates a new plugin either by copying a template or from scratch
|
|
227
|
+
* @param {PluginTemplateOptions} options
|
|
228
|
+
*/
|
|
229
|
+
async function createPlugin(options) {
|
|
230
|
+
if (!options.name) {
|
|
231
|
+
logger.error('please provide a plugin name as input parameter');
|
|
232
|
+
process.exit(1);
|
|
233
|
+
}
|
|
234
|
+
logger.debug(`creating new plugin: ${options.name}`);
|
|
235
|
+
|
|
236
|
+
const pluginPath = path.join(process.cwd(), options.name);
|
|
237
|
+
if (fs.existsSync(pluginPath)) {
|
|
238
|
+
logger.error('plugin with the provided name already exists');
|
|
239
|
+
process.exit(1);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
await fs.promises.mkdir(pluginPath);
|
|
243
|
+
await fs.promises.mkdir(path.join(pluginPath, 'plugin-assets'));
|
|
244
|
+
logger.debug('created plugin directory');
|
|
245
|
+
|
|
145
246
|
const writeNpmrcPromise = fs.promises.writeFile(
|
|
146
247
|
path.join(pluginPath, '.npmrc'),
|
|
147
248
|
'registry=https://registry.npmjs.org\n',
|
|
@@ -160,49 +261,44 @@ async function createPluginTemplate(options) {
|
|
|
160
261
|
`# v${options.version}\nDocument features and fixes`,
|
|
161
262
|
);
|
|
162
263
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
const copyTemplatePromise = fs.promises.cp(
|
|
167
|
-
path.join(getDirname(), '..', 'assets', 'helloWorld'),
|
|
168
|
-
pluginPath,
|
|
169
|
-
{ recursive: true },
|
|
264
|
+
const copyGitIgnorePromise = fs.promises.copyFile(
|
|
265
|
+
path.join(getDirname(), '..', 'assets', 'gitignore'),
|
|
266
|
+
path.join(pluginPath, '.gitignore'),
|
|
170
267
|
);
|
|
171
268
|
|
|
172
269
|
await Promise.all([
|
|
173
|
-
writePackagePromise,
|
|
174
|
-
writeConfigPromise,
|
|
175
270
|
writeNpmrcPromise,
|
|
176
271
|
writeReadmePromise,
|
|
177
272
|
writeChangesPromise,
|
|
178
|
-
copyTemplatePromise,
|
|
179
273
|
writeLicense(options.author, options.license, pluginPath),
|
|
274
|
+
copyGitIgnorePromise,
|
|
180
275
|
]);
|
|
181
276
|
|
|
277
|
+
if (options.gitlabCi) {
|
|
278
|
+
await fs.promises.copyFile(
|
|
279
|
+
path.join(getDirname(), '..', 'assets', '.gitlab-ci.yml'),
|
|
280
|
+
path.join(pluginPath, '.gitlab-ci.yml'),
|
|
281
|
+
);
|
|
282
|
+
}
|
|
182
283
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
await
|
|
187
|
-
await installDeps(options.peerDeps, DepType.PEER, pluginPath);
|
|
188
|
-
const devDeps = [`${name}@${version}`];
|
|
189
|
-
if (installEsLint) {
|
|
190
|
-
devDeps.push('@vcsuite/eslint-config');
|
|
191
|
-
}
|
|
192
|
-
await installDeps(devDeps, DepType.DEV, pluginPath);
|
|
193
|
-
logger.success('installed dependencies');
|
|
194
|
-
} catch (e) {
|
|
195
|
-
logger.error(e);
|
|
196
|
-
logger.failure('installed dependencies');
|
|
284
|
+
if (options.template) {
|
|
285
|
+
await copyPluginTemplate(options, pluginPath);
|
|
286
|
+
} else {
|
|
287
|
+
await createPluginTemplate(options, pluginPath);
|
|
197
288
|
}
|
|
198
|
-
logger.
|
|
199
|
-
logger.success('created plugin');
|
|
289
|
+
logger.success(`Created plugin ${options.name}`);
|
|
200
290
|
}
|
|
201
291
|
|
|
202
292
|
/**
|
|
203
293
|
* @returns {Promise<void>}
|
|
204
294
|
*/
|
|
205
295
|
export default async function create() {
|
|
296
|
+
const templateChoices = [
|
|
297
|
+
{ title: 'no template (basic structure)', value: null },
|
|
298
|
+
{ title: 'hello-world', value: '@vcmap/hello-world' },
|
|
299
|
+
// to add further templates add a choice here
|
|
300
|
+
];
|
|
301
|
+
|
|
206
302
|
const scriptChoices = [
|
|
207
303
|
{ title: 'build', value: { build: 'vcmplugin build' }, selected: true },
|
|
208
304
|
{ title: 'pack', value: { pack: 'vcmplugin pack' }, selected: true },
|
|
@@ -210,6 +306,7 @@ export default async function create() {
|
|
|
210
306
|
{ title: 'preview', value: { preview: 'vcmplugin preview' }, selected: true },
|
|
211
307
|
{ title: 'buildStagingApp', value: { buildStagingApp: 'vcmplugin buildStagingApp' }, selected: true },
|
|
212
308
|
{ title: 'lint', value: { lint: 'eslint "{src,tests}/**/*.{js,vue}"' }, selected: true },
|
|
309
|
+
{ title: 'test', value: { test: 'vitest' }, selected: true },
|
|
213
310
|
];
|
|
214
311
|
|
|
215
312
|
const peerDependencyChoices = [
|
|
@@ -229,7 +326,6 @@ export default async function create() {
|
|
|
229
326
|
if (!value) {
|
|
230
327
|
return false;
|
|
231
328
|
}
|
|
232
|
-
|
|
233
329
|
if (fs.existsSync(path.join(process.cwd(), value))) {
|
|
234
330
|
return `Directory ${value} already exists`;
|
|
235
331
|
}
|
|
@@ -249,13 +345,6 @@ export default async function create() {
|
|
|
249
345
|
message: 'Description',
|
|
250
346
|
initial: '',
|
|
251
347
|
},
|
|
252
|
-
{
|
|
253
|
-
type: 'multiselect',
|
|
254
|
-
message: 'Add the following scripts to the package.json.',
|
|
255
|
-
name: 'scripts',
|
|
256
|
-
choices: scriptChoices,
|
|
257
|
-
hint: '- Space to select. Enter to submit',
|
|
258
|
-
},
|
|
259
348
|
{
|
|
260
349
|
type: 'text',
|
|
261
350
|
name: 'author',
|
|
@@ -280,15 +369,37 @@ export default async function create() {
|
|
|
280
369
|
})),
|
|
281
370
|
},
|
|
282
371
|
{
|
|
372
|
+
type: 'select',
|
|
373
|
+
name: 'template',
|
|
374
|
+
message: 'Choose an existing plugin as template',
|
|
375
|
+
initial: 0,
|
|
376
|
+
choices: templateChoices,
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
type: (prev, values) => (!values.template ? 'multiselect' : null),
|
|
380
|
+
message: 'Add the following scripts to the package.json.',
|
|
381
|
+
name: 'scripts',
|
|
382
|
+
choices: scriptChoices,
|
|
383
|
+
hint: '- Space to select. Enter to submit',
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
type: (prev, values) => (!values.template ? 'multiselect' : null),
|
|
283
387
|
name: 'peerDeps',
|
|
284
|
-
type: 'multiselect',
|
|
285
388
|
message: 'Add the following peer dependencies to the package.json.',
|
|
286
389
|
choices: peerDependencyChoices,
|
|
287
390
|
hint: '- Space to select. Enter to submit',
|
|
288
391
|
},
|
|
392
|
+
{
|
|
393
|
+
type: 'toggle',
|
|
394
|
+
name: 'gitlabCi',
|
|
395
|
+
message: 'Add gitlab-ci.yml?',
|
|
396
|
+
initial: false,
|
|
397
|
+
active: 'yes',
|
|
398
|
+
inactive: 'no',
|
|
399
|
+
},
|
|
289
400
|
];
|
|
290
401
|
|
|
291
402
|
const answers = await prompts(questions, { onCancel() { process.exit(0); } });
|
|
292
403
|
|
|
293
|
-
await
|
|
404
|
+
await createPlugin(answers);
|
|
294
405
|
}
|
package/src/hostingHelpers.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { promisify } from 'util';
|
|
3
|
-
import { exec } from 'child_process';
|
|
1
|
+
import { URL } from 'url';
|
|
4
2
|
import https from 'https';
|
|
5
3
|
import http from 'http';
|
|
6
4
|
import fs from 'fs';
|
|
@@ -8,6 +6,7 @@ import path from 'path';
|
|
|
8
6
|
import { logger } from '@vcsuite/cli-logger';
|
|
9
7
|
import { getContext, resolveContext } from './context.js';
|
|
10
8
|
import { getPluginEntry, getPluginName } from './packageJsonHelpers.js';
|
|
9
|
+
import { promiseExec, getDirname } from './pluginCliHelper.js';
|
|
11
10
|
|
|
12
11
|
/**
|
|
13
12
|
* @typedef {Object} HostingOptions
|
|
@@ -17,11 +16,6 @@ import { getPluginEntry, getPluginName } from './packageJsonHelpers.js';
|
|
|
17
16
|
* @property {boolean} [https]
|
|
18
17
|
*/
|
|
19
18
|
|
|
20
|
-
/**
|
|
21
|
-
* @type {(arg1: string, opt?: Object) => Promise<string>}
|
|
22
|
-
*/
|
|
23
|
-
const promiseExec = promisify(exec);
|
|
24
|
-
|
|
25
19
|
/**
|
|
26
20
|
* @param {...string} pathSegments
|
|
27
21
|
* @returns {string}
|
|
@@ -39,13 +33,6 @@ export function checkReservedDirectories() {
|
|
|
39
33
|
});
|
|
40
34
|
}
|
|
41
35
|
|
|
42
|
-
/**
|
|
43
|
-
* @returns {string}
|
|
44
|
-
*/
|
|
45
|
-
export function getDirname() {
|
|
46
|
-
return path.dirname(fileURLToPath(import.meta.url));
|
|
47
|
-
}
|
|
48
|
-
|
|
49
36
|
/**
|
|
50
37
|
* @param {string} stringUrl
|
|
51
38
|
* @param {string} auth
|
|
@@ -301,10 +288,14 @@ export function addIndexRoute(app, server, production, hostedVcm, auth) {
|
|
|
301
288
|
}
|
|
302
289
|
|
|
303
290
|
/**
|
|
304
|
-
* @param {string}
|
|
291
|
+
* @param {string|null} args
|
|
292
|
+
* @param {string} [command='run']
|
|
305
293
|
* @returns {Promise<string>}
|
|
306
294
|
*/
|
|
307
|
-
export function executeUiNpm(command) {
|
|
295
|
+
export function executeUiNpm(args, command = 'run') {
|
|
308
296
|
const mapUiDir = resolveMapUi();
|
|
309
|
-
|
|
297
|
+
if (args) {
|
|
298
|
+
return promiseExec(`npm ${command} ${args}`, { cwd: mapUiDir });
|
|
299
|
+
}
|
|
300
|
+
return promiseExec(`npm ${command}`, { cwd: mapUiDir });
|
|
310
301
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
+
import { logger } from '@vcsuite/cli-logger';
|
|
2
3
|
import { resolveContext } from './context.js';
|
|
4
|
+
import { promiseExec } from './pluginCliHelper.js';
|
|
3
5
|
|
|
4
6
|
/** @type {Object|null} */
|
|
5
7
|
let packageJson = null;
|
|
@@ -7,7 +9,7 @@ let packageJson = null;
|
|
|
7
9
|
/**
|
|
8
10
|
* @returns {Promise<Object>}
|
|
9
11
|
*/
|
|
10
|
-
async function getPackageJson() {
|
|
12
|
+
export async function getPackageJson() {
|
|
11
13
|
if (!packageJson) {
|
|
12
14
|
const packageJsonFileName = resolveContext('package.json');
|
|
13
15
|
if (!fs.existsSync(packageJsonFileName)) {
|
|
@@ -46,3 +48,34 @@ export async function getPluginEntry() {
|
|
|
46
48
|
return entry;
|
|
47
49
|
}
|
|
48
50
|
|
|
51
|
+
/**
|
|
52
|
+
* @enum {number}
|
|
53
|
+
*/
|
|
54
|
+
export const DepType = {
|
|
55
|
+
DEP: 1,
|
|
56
|
+
PEER: 2,
|
|
57
|
+
DEV: 3,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @param {Array<string>} deps
|
|
62
|
+
* @param {DepType} type
|
|
63
|
+
* @param {string} pluginPath
|
|
64
|
+
* @returns {Promise<void>}
|
|
65
|
+
*/
|
|
66
|
+
export async function installDeps(deps, type, pluginPath) {
|
|
67
|
+
if (deps.length < 1) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
let save = '--save';
|
|
71
|
+
if (type === DepType.PEER) {
|
|
72
|
+
save = '--save-peer';
|
|
73
|
+
} else if (type === DepType.DEV) {
|
|
74
|
+
save = '--save-dev';
|
|
75
|
+
}
|
|
76
|
+
const installCmd = `npm i ${save} ${deps.join(' ')}`;
|
|
77
|
+
logger.debug(installCmd);
|
|
78
|
+
const { stdout, stderr } = await promiseExec(installCmd, { cwd: pluginPath });
|
|
79
|
+
logger.log(stdout);
|
|
80
|
+
logger.error(stderr);
|
|
81
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import util from 'util';
|
|
4
|
+
import childProcess from 'child_process';
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
6
|
+
import { logger } from '@vcsuite/cli-logger';
|
|
7
|
+
import { getContext } from './context.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @returns {string}
|
|
11
|
+
*/
|
|
12
|
+
export function getDirname() {
|
|
13
|
+
return path.dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @type {string} version
|
|
18
|
+
* @type {string} name
|
|
19
|
+
*/
|
|
20
|
+
export const { version, name } = JSON.parse(fs.readFileSync(path.join(getDirname(), '..', 'package.json')).toString());
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @type {(arg1: string) => Promise<string>}
|
|
24
|
+
*/
|
|
25
|
+
export const promiseExec = util.promisify(childProcess.exec);
|
|
26
|
+
|
|
27
|
+
export async function getVcmConfigJs() {
|
|
28
|
+
let vcmConfigJs = {};
|
|
29
|
+
const vcmConfigJsPath = path.resolve(getContext(), 'vcm.config.js');
|
|
30
|
+
if (!fs.existsSync(vcmConfigJsPath)) {
|
|
31
|
+
logger.debug(`${vcmConfigJsPath} not existing!`);
|
|
32
|
+
return vcmConfigJs;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
vcmConfigJs = await import(pathToFileURL(vcmConfigJsPath));
|
|
36
|
+
logger.info('Using vcm.config.js found in current project.');
|
|
37
|
+
} catch (err) {
|
|
38
|
+
logger.error(err);
|
|
39
|
+
}
|
|
40
|
+
return vcmConfigJs;
|
|
41
|
+
}
|
package/src/preview.js
CHANGED
|
@@ -10,11 +10,13 @@ import {
|
|
|
10
10
|
addPluginAssets,
|
|
11
11
|
checkReservedDirectories,
|
|
12
12
|
createConfigJsonReloadPlugin,
|
|
13
|
-
printVcmapUiVersion,
|
|
13
|
+
printVcmapUiVersion,
|
|
14
|
+
resolveMapUi,
|
|
14
15
|
} from './hostingHelpers.js';
|
|
15
16
|
import build, { getDefaultConfig, getLibraryPaths } from './build.js';
|
|
16
17
|
import { getContext } from './context.js';
|
|
17
18
|
import setupMapUi from './setupMapUi.js';
|
|
19
|
+
import { getVcmConfigJs } from './pluginCliHelper.js';
|
|
18
20
|
|
|
19
21
|
/**
|
|
20
22
|
* @typedef {HostingOptions} PreviewOptions
|
|
@@ -61,7 +63,7 @@ async function getServerOptions(hostedVcm, https) {
|
|
|
61
63
|
alias,
|
|
62
64
|
},
|
|
63
65
|
server: {
|
|
64
|
-
middlewareMode:
|
|
66
|
+
middlewareMode: true,
|
|
65
67
|
proxy,
|
|
66
68
|
https,
|
|
67
69
|
},
|
|
@@ -73,20 +75,22 @@ async function getServerOptions(hostedVcm, https) {
|
|
|
73
75
|
* @returns {Promise<void>}
|
|
74
76
|
*/
|
|
75
77
|
export default async function preview(options) {
|
|
76
|
-
|
|
78
|
+
const { default: vcmConfigJs } = await getVcmConfigJs();
|
|
79
|
+
const mergedOptions = { ...vcmConfigJs, ...options };
|
|
80
|
+
if (!mergedOptions.vcm) {
|
|
77
81
|
await printVcmapUiVersion();
|
|
78
82
|
}
|
|
79
83
|
checkReservedDirectories();
|
|
80
84
|
await build({ development: false, watch: true });
|
|
81
85
|
const app = express();
|
|
82
86
|
logger.info('Starting preview server...');
|
|
83
|
-
const server = await createServer(await getServerOptions(
|
|
87
|
+
const server = await createServer(await getServerOptions(mergedOptions.vcm, mergedOptions.https));
|
|
84
88
|
|
|
85
|
-
addMapConfigRoute(app,
|
|
86
|
-
addIndexRoute(app, server, true,
|
|
89
|
+
addMapConfigRoute(app, mergedOptions.vcm ? `${mergedOptions.vcm}/map.config.json` : null, mergedOptions.auth, mergedOptions.config, true);
|
|
90
|
+
addIndexRoute(app, server, true, mergedOptions.vcm, mergedOptions.auth);
|
|
87
91
|
addPluginAssets(app, 'dist');
|
|
88
92
|
|
|
89
|
-
if (!
|
|
93
|
+
if (!mergedOptions.vcm) {
|
|
90
94
|
logger.spin('compiling preview');
|
|
91
95
|
if (!fs.existsSync(resolveMapUi('plugins', 'node_modules'))) {
|
|
92
96
|
logger.info('Could not detect node_modules in map ui plugins. Assuming map UI not setup');
|
|
@@ -98,12 +102,12 @@ export default async function preview(options) {
|
|
|
98
102
|
logger.info('@vcmap/ui built for preview');
|
|
99
103
|
app.use('/assets', express.static(path.join(getContext(), 'node_modules', '@vcmap', 'ui', 'dist', 'assets')));
|
|
100
104
|
app.use('/plugins', express.static(path.join(getContext(), 'dist', 'plugins')));
|
|
101
|
-
await addConfigRoute(app,
|
|
105
|
+
await addConfigRoute(app, mergedOptions.auth, mergedOptions.config, true);
|
|
102
106
|
}
|
|
103
107
|
|
|
104
108
|
app.use(server.middlewares);
|
|
105
109
|
|
|
106
|
-
const port =
|
|
110
|
+
const port = mergedOptions.port || 5005;
|
|
107
111
|
await app.listen(port);
|
|
108
112
|
logger.info(`Server running on port ${port}`);
|
|
109
113
|
}
|