sitevision-cli 0.0.0
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/dist/app.d.ts +7 -0
- package/dist/app.js +180 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +95 -0
- package/dist/commands/build.d.ts +12 -0
- package/dist/commands/build.js +168 -0
- package/dist/commands/deploy.d.ts +17 -0
- package/dist/commands/deploy.js +162 -0
- package/dist/commands/dev.d.ts +15 -0
- package/dist/commands/dev.js +291 -0
- package/dist/commands/index.d.ts +4 -0
- package/dist/commands/index.js +20 -0
- package/dist/commands/info.d.ts +2 -0
- package/dist/commands/info.js +66 -0
- package/dist/commands/setup-signing.d.ts +2 -0
- package/dist/commands/setup-signing.js +82 -0
- package/dist/commands/sign.d.ts +14 -0
- package/dist/commands/sign.js +103 -0
- package/dist/commands/types.d.ts +18 -0
- package/dist/commands/types.js +1 -0
- package/dist/components/DevPropertiesForm.d.ts +11 -0
- package/dist/components/DevPropertiesForm.js +87 -0
- package/dist/components/InfoScreen.d.ts +8 -0
- package/dist/components/InfoScreen.js +60 -0
- package/dist/components/MainMenu.d.ts +8 -0
- package/dist/components/MainMenu.js +138 -0
- package/dist/components/PasswordInput.d.ts +8 -0
- package/dist/components/PasswordInput.js +30 -0
- package/dist/components/ProcessOutput.d.ts +7 -0
- package/dist/components/ProcessOutput.js +32 -0
- package/dist/components/SetupFlow.d.ts +8 -0
- package/dist/components/SetupFlow.js +194 -0
- package/dist/components/SigningPropertiesForm.d.ts +8 -0
- package/dist/components/SigningPropertiesForm.js +49 -0
- package/dist/components/StatusIndicator.d.ts +9 -0
- package/dist/components/StatusIndicator.js +36 -0
- package/dist/components/TextInput.d.ts +11 -0
- package/dist/components/TextInput.js +37 -0
- package/dist/types/index.d.ts +250 -0
- package/dist/types/index.js +6 -0
- package/dist/utils/password-prompt.d.ts +4 -0
- package/dist/utils/password-prompt.js +45 -0
- package/dist/utils/process-runner.d.ts +30 -0
- package/dist/utils/process-runner.js +119 -0
- package/dist/utils/project-detection.d.ts +103 -0
- package/dist/utils/project-detection.js +287 -0
- package/dist/utils/sitevision-api.d.ts +56 -0
- package/dist/utils/sitevision-api.js +393 -0
- package/dist/utils/webpack-runner.d.ts +75 -0
- package/dist/utils/webpack-runner.js +313 -0
- package/dist/utils/zip.d.ts +64 -0
- package/dist/utils/zip.js +246 -0
- package/package.json +59 -0
- package/readme.md +196 -0
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sitevision API Client
|
|
3
|
+
*
|
|
4
|
+
* Handles all API interactions with Sitevision servers:
|
|
5
|
+
* - Signing apps via developer.sitevision.se
|
|
6
|
+
* - Deploying to development environments
|
|
7
|
+
* - Deploying to production environments
|
|
8
|
+
* - Creating addons
|
|
9
|
+
* - Activating production apps
|
|
10
|
+
*/
|
|
11
|
+
import fs from 'fs';
|
|
12
|
+
import path from 'path';
|
|
13
|
+
import https from 'https';
|
|
14
|
+
import http from 'http';
|
|
15
|
+
import { buildImportEndpointUrl, buildAddonEndpointUrl, } from './project-detection.js';
|
|
16
|
+
// =============================================================================
|
|
17
|
+
// CONSTANTS
|
|
18
|
+
// =============================================================================
|
|
19
|
+
const SIGNING_API_HOST = 'developer.sitevision.se';
|
|
20
|
+
const SIGNING_API_PATH = '/rest-api/appsigner/signapp';
|
|
21
|
+
// =============================================================================
|
|
22
|
+
// UTILITY FUNCTIONS
|
|
23
|
+
// =============================================================================
|
|
24
|
+
/**
|
|
25
|
+
* Create Basic Auth header value
|
|
26
|
+
*/
|
|
27
|
+
function createBasicAuth(username, password) {
|
|
28
|
+
return `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Generate a random boundary for multipart form data
|
|
32
|
+
*/
|
|
33
|
+
function generateBoundary() {
|
|
34
|
+
return `----FormBoundary${Math.random().toString(36).substring(2)}`;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Create multipart form data for file upload
|
|
38
|
+
*/
|
|
39
|
+
function createMultipartFormData(filePath, fieldName, boundary) {
|
|
40
|
+
const filename = path.basename(filePath);
|
|
41
|
+
const fileContent = fs.readFileSync(filePath);
|
|
42
|
+
const parts = [];
|
|
43
|
+
// File part
|
|
44
|
+
parts.push(Buffer.from(`--${boundary}\r\n` +
|
|
45
|
+
`Content-Disposition: form-data; name="${fieldName}"; filename="${filename}"\r\n` +
|
|
46
|
+
`Content-Type: application/octet-stream\r\n\r\n`));
|
|
47
|
+
parts.push(fileContent);
|
|
48
|
+
parts.push(Buffer.from('\r\n'));
|
|
49
|
+
// Closing boundary
|
|
50
|
+
parts.push(Buffer.from(`--${boundary}--\r\n`));
|
|
51
|
+
return {
|
|
52
|
+
body: Buffer.concat(parts),
|
|
53
|
+
contentType: `multipart/form-data; boundary=${boundary}`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Make an HTTP/HTTPS request
|
|
58
|
+
*/
|
|
59
|
+
function makeRequest(url, options) {
|
|
60
|
+
return new Promise((resolve, reject) => {
|
|
61
|
+
const parsedUrl = new URL(url);
|
|
62
|
+
const isHttps = parsedUrl.protocol === 'https:';
|
|
63
|
+
const transport = isHttps ? https : http;
|
|
64
|
+
const headers = {
|
|
65
|
+
...options.headers,
|
|
66
|
+
};
|
|
67
|
+
if (options.auth) {
|
|
68
|
+
headers['Authorization'] = createBasicAuth(options.auth.username, options.auth.password);
|
|
69
|
+
}
|
|
70
|
+
const requestOptions = {
|
|
71
|
+
hostname: parsedUrl.hostname,
|
|
72
|
+
port: parsedUrl.port || (isHttps ? 443 : 80),
|
|
73
|
+
path: parsedUrl.pathname + parsedUrl.search,
|
|
74
|
+
method: options.method,
|
|
75
|
+
headers,
|
|
76
|
+
};
|
|
77
|
+
const req = transport.request(requestOptions, (res) => {
|
|
78
|
+
const chunks = [];
|
|
79
|
+
res.on('data', (chunk) => {
|
|
80
|
+
chunks.push(chunk);
|
|
81
|
+
});
|
|
82
|
+
res.on('end', () => {
|
|
83
|
+
resolve({
|
|
84
|
+
statusCode: res.statusCode || 0,
|
|
85
|
+
body: Buffer.concat(chunks),
|
|
86
|
+
headers: res.headers,
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
req.on('error', reject);
|
|
91
|
+
if (options.body) {
|
|
92
|
+
req.write(options.body);
|
|
93
|
+
}
|
|
94
|
+
req.end();
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
// =============================================================================
|
|
98
|
+
// SIGNING API
|
|
99
|
+
// =============================================================================
|
|
100
|
+
/**
|
|
101
|
+
* Sign an app via developer.sitevision.se
|
|
102
|
+
*
|
|
103
|
+
* @param zipPath - Path to the unsigned zip file
|
|
104
|
+
* @param credentials - Signing credentials
|
|
105
|
+
* @param outputPath - Path to write the signed zip file
|
|
106
|
+
*/
|
|
107
|
+
export async function signApp(zipPath, credentials, outputPath) {
|
|
108
|
+
// Validate zip exists
|
|
109
|
+
if (!fs.existsSync(zipPath)) {
|
|
110
|
+
return {
|
|
111
|
+
success: false,
|
|
112
|
+
error: `Zip file not found: ${zipPath}. Run build first.`,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
// Build URL with optional certificate name
|
|
116
|
+
let url = `https://${SIGNING_API_HOST}${SIGNING_API_PATH}`;
|
|
117
|
+
if (credentials.certificateName) {
|
|
118
|
+
url += `?certificateName=${encodeURIComponent(credentials.certificateName)}`;
|
|
119
|
+
}
|
|
120
|
+
// Create multipart form data
|
|
121
|
+
const boundary = generateBoundary();
|
|
122
|
+
const { body, contentType } = createMultipartFormData(zipPath, 'file', boundary);
|
|
123
|
+
try {
|
|
124
|
+
const response = await makeRequest(url, {
|
|
125
|
+
method: 'POST',
|
|
126
|
+
headers: {
|
|
127
|
+
'Content-Type': contentType,
|
|
128
|
+
'Content-Length': String(body.length),
|
|
129
|
+
},
|
|
130
|
+
body,
|
|
131
|
+
auth: {
|
|
132
|
+
username: credentials.username,
|
|
133
|
+
password: credentials.password,
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
if (response.statusCode === 200) {
|
|
137
|
+
// Write signed zip to output path
|
|
138
|
+
const outputDir = path.dirname(outputPath);
|
|
139
|
+
if (!fs.existsSync(outputDir)) {
|
|
140
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
141
|
+
}
|
|
142
|
+
fs.writeFileSync(outputPath, response.body);
|
|
143
|
+
return {
|
|
144
|
+
success: true,
|
|
145
|
+
signedFilePath: outputPath,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
if (response.statusCode === 401) {
|
|
149
|
+
return {
|
|
150
|
+
success: false,
|
|
151
|
+
error: 'Unauthorized. Check username and password.',
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
success: false,
|
|
156
|
+
error: `Signing failed with status ${response.statusCode}: ${response.body.toString()}`,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
return {
|
|
161
|
+
success: false,
|
|
162
|
+
error: `Signing request failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// =============================================================================
|
|
167
|
+
// DEPLOYMENT API
|
|
168
|
+
// =============================================================================
|
|
169
|
+
/**
|
|
170
|
+
* Deploy an app to a development environment
|
|
171
|
+
*
|
|
172
|
+
* @param zipPath - Path to the zip file (signed or unsigned)
|
|
173
|
+
* @param config - Deployment configuration
|
|
174
|
+
* @param appType - The app type (web, widget, rest)
|
|
175
|
+
* @param force - Whether to force deploy (overwrite existing)
|
|
176
|
+
*/
|
|
177
|
+
export async function deployApp(zipPath, config, appType, force = false) {
|
|
178
|
+
// Validate zip exists
|
|
179
|
+
if (!fs.existsSync(zipPath)) {
|
|
180
|
+
return {
|
|
181
|
+
success: false,
|
|
182
|
+
error: `Zip file not found: ${zipPath}`,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
// Build import URL
|
|
186
|
+
let url = buildImportEndpointUrl(config.domain, config.siteName, config.addonName, appType, config.useHTTP);
|
|
187
|
+
if (force) {
|
|
188
|
+
url += '?force=true';
|
|
189
|
+
}
|
|
190
|
+
// Create multipart form data
|
|
191
|
+
const boundary = generateBoundary();
|
|
192
|
+
const { body, contentType } = createMultipartFormData(zipPath, 'file', boundary);
|
|
193
|
+
try {
|
|
194
|
+
const response = await makeRequest(url, {
|
|
195
|
+
method: 'POST',
|
|
196
|
+
headers: {
|
|
197
|
+
'Content-Type': contentType,
|
|
198
|
+
'Content-Length': String(body.length),
|
|
199
|
+
},
|
|
200
|
+
body,
|
|
201
|
+
auth: {
|
|
202
|
+
username: config.username,
|
|
203
|
+
password: config.password,
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
if (response.statusCode === 200) {
|
|
207
|
+
// Try to parse response for executable ID
|
|
208
|
+
let executableId;
|
|
209
|
+
try {
|
|
210
|
+
const responseData = JSON.parse(response.body.toString());
|
|
211
|
+
executableId = responseData.executableId || responseData.id;
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
// Response may not be JSON
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
success: true,
|
|
218
|
+
executableId,
|
|
219
|
+
message: 'Deployment successful',
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
if (response.statusCode === 401) {
|
|
223
|
+
return {
|
|
224
|
+
success: false,
|
|
225
|
+
error: 'Unauthorized. Check username and password.',
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
if (response.statusCode === 409) {
|
|
229
|
+
return {
|
|
230
|
+
success: false,
|
|
231
|
+
error: 'Conflict. Addon already exists. Use --force to overwrite.',
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
return {
|
|
235
|
+
success: false,
|
|
236
|
+
error: `Deployment failed with status ${response.statusCode}: ${response.body.toString()}`,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
return {
|
|
241
|
+
success: false,
|
|
242
|
+
error: `Deployment request failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Deploy an app to production
|
|
248
|
+
*
|
|
249
|
+
* @param signedZipPath - Path to the SIGNED zip file (required for production)
|
|
250
|
+
* @param config - Production deployment configuration
|
|
251
|
+
* @param appType - The app type (web, widget, rest)
|
|
252
|
+
*/
|
|
253
|
+
export async function deployProduction(signedZipPath, config, appType) {
|
|
254
|
+
// Deploy the signed app
|
|
255
|
+
const deployResult = await deployApp(signedZipPath, config, appType, true);
|
|
256
|
+
if (!deployResult.success) {
|
|
257
|
+
return deployResult;
|
|
258
|
+
}
|
|
259
|
+
// If activation requested and we have an executable ID
|
|
260
|
+
if (config.activate && deployResult.executableId) {
|
|
261
|
+
const activationResult = await activateApp(deployResult.executableId, config, appType);
|
|
262
|
+
if (!activationResult.success) {
|
|
263
|
+
return {
|
|
264
|
+
success: true,
|
|
265
|
+
executableId: deployResult.executableId,
|
|
266
|
+
message: `Deployed successfully but activation failed: ${activationResult.error}`,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
return {
|
|
270
|
+
success: true,
|
|
271
|
+
executableId: deployResult.executableId,
|
|
272
|
+
message: 'Deployed and activated successfully',
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
return deployResult;
|
|
276
|
+
}
|
|
277
|
+
// =============================================================================
|
|
278
|
+
// ADDON MANAGEMENT API
|
|
279
|
+
// =============================================================================
|
|
280
|
+
/**
|
|
281
|
+
* Create a new addon on a Sitevision site
|
|
282
|
+
*
|
|
283
|
+
* @param config - Deployment configuration
|
|
284
|
+
* @param appType - The app type (web, widget, rest)
|
|
285
|
+
*/
|
|
286
|
+
export async function createAddon(config, appType) {
|
|
287
|
+
const url = buildAddonEndpointUrl(config.domain, config.siteName, appType, config.useHTTP);
|
|
288
|
+
const body = JSON.stringify({
|
|
289
|
+
name: config.addonName,
|
|
290
|
+
category: 'Other',
|
|
291
|
+
});
|
|
292
|
+
try {
|
|
293
|
+
const response = await makeRequest(url, {
|
|
294
|
+
method: 'POST',
|
|
295
|
+
headers: {
|
|
296
|
+
'Content-Type': 'application/json',
|
|
297
|
+
'Content-Length': String(Buffer.byteLength(body)),
|
|
298
|
+
},
|
|
299
|
+
body: Buffer.from(body),
|
|
300
|
+
auth: {
|
|
301
|
+
username: config.username,
|
|
302
|
+
password: config.password,
|
|
303
|
+
},
|
|
304
|
+
});
|
|
305
|
+
if (response.statusCode === 200 || response.statusCode === 201) {
|
|
306
|
+
let addonId;
|
|
307
|
+
try {
|
|
308
|
+
const responseData = JSON.parse(response.body.toString());
|
|
309
|
+
addonId = responseData.id;
|
|
310
|
+
}
|
|
311
|
+
catch {
|
|
312
|
+
// Response may not be JSON
|
|
313
|
+
}
|
|
314
|
+
return {
|
|
315
|
+
success: true,
|
|
316
|
+
addonId,
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
if (response.statusCode === 401) {
|
|
320
|
+
return {
|
|
321
|
+
success: false,
|
|
322
|
+
error: 'Unauthorized. Check username and password.',
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
if (response.statusCode === 409) {
|
|
326
|
+
return {
|
|
327
|
+
success: false,
|
|
328
|
+
error: 'Addon already exists.',
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
return {
|
|
332
|
+
success: false,
|
|
333
|
+
error: `Create addon failed with status ${response.statusCode}: ${response.body.toString()}`,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
catch (error) {
|
|
337
|
+
return {
|
|
338
|
+
success: false,
|
|
339
|
+
error: `Create addon request failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Activate a deployed production app
|
|
345
|
+
*
|
|
346
|
+
* @param executableId - The executable ID returned from deployment
|
|
347
|
+
* @param config - Deployment configuration
|
|
348
|
+
* @param appType - The app type (web, widget, rest)
|
|
349
|
+
*/
|
|
350
|
+
export async function activateApp(executableId, config, _appType) {
|
|
351
|
+
const protocol = config.useHTTP ? 'http' : 'https';
|
|
352
|
+
const url = `${protocol}://${config.domain}/rest-api/1/0/${encodeURIComponent(config.siteName)}/Addon%20Repository/${encodeURIComponent(config.addonName)}/activateCustomModuleExecutable`;
|
|
353
|
+
const body = JSON.stringify({
|
|
354
|
+
executableId,
|
|
355
|
+
});
|
|
356
|
+
try {
|
|
357
|
+
const response = await makeRequest(url, {
|
|
358
|
+
method: 'PUT',
|
|
359
|
+
headers: {
|
|
360
|
+
'Content-Type': 'application/json',
|
|
361
|
+
'Content-Length': String(Buffer.byteLength(body)),
|
|
362
|
+
},
|
|
363
|
+
body: Buffer.from(body),
|
|
364
|
+
auth: {
|
|
365
|
+
username: config.username,
|
|
366
|
+
password: config.password,
|
|
367
|
+
},
|
|
368
|
+
});
|
|
369
|
+
if (response.statusCode === 200) {
|
|
370
|
+
return { success: true };
|
|
371
|
+
}
|
|
372
|
+
if (response.statusCode === 401) {
|
|
373
|
+
return {
|
|
374
|
+
success: false,
|
|
375
|
+
error: 'Unauthorized. Check username and password.',
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
return {
|
|
379
|
+
success: false,
|
|
380
|
+
error: `Activation failed with status ${response.statusCode}: ${response.body.toString()}`,
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
catch (error) {
|
|
384
|
+
return {
|
|
385
|
+
success: false,
|
|
386
|
+
error: `Activation request failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
// =============================================================================
|
|
391
|
+
// HELPER EXPORTS
|
|
392
|
+
// =============================================================================
|
|
393
|
+
export { createBasicAuth };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Webpack Runner
|
|
3
|
+
*
|
|
4
|
+
* Handles webpack compilation for Sitevision apps.
|
|
5
|
+
* Dynamically loads webpack from the target project's node_modules.
|
|
6
|
+
*/
|
|
7
|
+
import { EventEmitter } from 'events';
|
|
8
|
+
import type { BuildOptions, BuildResult } from '../types/index.js';
|
|
9
|
+
/**
|
|
10
|
+
* Events emitted by WebpackRunner:
|
|
11
|
+
* - 'compile': Emitted when compilation starts
|
|
12
|
+
* - 'done': Emitted when compilation completes successfully
|
|
13
|
+
* - 'error': Emitted when compilation fails
|
|
14
|
+
* - 'warning': Emitted when compilation has warnings
|
|
15
|
+
*/
|
|
16
|
+
export declare class WebpackRunner extends EventEmitter {
|
|
17
|
+
private projectRoot;
|
|
18
|
+
private options;
|
|
19
|
+
private webpack;
|
|
20
|
+
private config;
|
|
21
|
+
private compiler;
|
|
22
|
+
private watcher;
|
|
23
|
+
constructor(projectRoot: string, options: BuildOptions);
|
|
24
|
+
/**
|
|
25
|
+
* Initialize webpack by loading it from the project's node_modules
|
|
26
|
+
*/
|
|
27
|
+
private initialize;
|
|
28
|
+
/**
|
|
29
|
+
* Load webpack configuration from the project
|
|
30
|
+
*/
|
|
31
|
+
private loadConfig;
|
|
32
|
+
/**
|
|
33
|
+
* Convert webpack stats to BuildResult
|
|
34
|
+
*/
|
|
35
|
+
private statsToResult;
|
|
36
|
+
/**
|
|
37
|
+
* Run a single webpack build
|
|
38
|
+
*/
|
|
39
|
+
run(): Promise<BuildResult>;
|
|
40
|
+
/**
|
|
41
|
+
* Start webpack in watch mode
|
|
42
|
+
*
|
|
43
|
+
* @param callback - Called after each compilation
|
|
44
|
+
*/
|
|
45
|
+
watch(callback?: (result: BuildResult) => void): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Stop watching and close the compiler
|
|
48
|
+
*/
|
|
49
|
+
close(): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Check if webpack is available in the project
|
|
52
|
+
*/
|
|
53
|
+
static isWebpackAvailable(projectRoot: string): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Get the webpack version from the project
|
|
56
|
+
*/
|
|
57
|
+
static getWebpackVersion(projectRoot: string): string | null;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Run a single webpack build
|
|
61
|
+
*
|
|
62
|
+
* @param projectRoot - Project root directory
|
|
63
|
+
* @param options - Build options
|
|
64
|
+
* @returns Build result
|
|
65
|
+
*/
|
|
66
|
+
export declare function runWebpackBuild(projectRoot: string, options: BuildOptions): Promise<BuildResult>;
|
|
67
|
+
/**
|
|
68
|
+
* Start webpack in watch mode
|
|
69
|
+
*
|
|
70
|
+
* @param projectRoot - Project root directory
|
|
71
|
+
* @param options - Build options
|
|
72
|
+
* @param callback - Called after each compilation
|
|
73
|
+
* @returns WebpackRunner instance (call .close() to stop)
|
|
74
|
+
*/
|
|
75
|
+
export declare function startWebpackWatch(projectRoot: string, options: BuildOptions, callback?: (result: BuildResult) => void): Promise<WebpackRunner>;
|