parcel 2.0.0-nightly.95 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/cli.js CHANGED
@@ -1,50 +1,70 @@
1
1
  // @flow
2
2
 
3
- import type {ParcelConfigFile, InitialParcelOptions} from '@parcel/types';
3
+ import type {InitialParcelOptions} from '@parcel/types';
4
4
  import {BuildError} from '@parcel/core';
5
- import {NodePackageManager} from '@parcel/package-manager';
6
5
  import {NodeFS} from '@parcel/fs';
7
6
  import ThrowableDiagnostic from '@parcel/diagnostic';
8
- import {prettyDiagnostic} from '@parcel/utils';
7
+ import {prettyDiagnostic, openInBrowser} from '@parcel/utils';
8
+ import {Disposable} from '@parcel/events';
9
+ import {INTERNAL_ORIGINAL_CONSOLE} from '@parcel/logger';
10
+ import chalk from 'chalk';
11
+ import commander from 'commander';
12
+ import path from 'path';
13
+ import getPort from 'get-port';
14
+ import {version} from '../package.json';
9
15
 
10
16
  require('v8-compile-cache');
11
17
 
12
- function logUncaughtError(e: mixed) {
18
+ const program = new commander.Command();
19
+
20
+ // Exit codes in response to signals are traditionally
21
+ // 128 + signal value
22
+ // https://tldp.org/LDP/abs/html/exitcodes.html
23
+ const SIGINT_EXIT_CODE = 130;
24
+
25
+ async function logUncaughtError(e: mixed) {
13
26
  if (e instanceof ThrowableDiagnostic) {
14
27
  for (let diagnostic of e.diagnostics) {
15
- let out = prettyDiagnostic(diagnostic);
16
- console.error(out.message);
17
- console.error(out.codeframe || out.stack);
18
- for (let h of out.hints) {
19
- console.error(h);
28
+ let {message, codeframe, stack, hints, documentation} =
29
+ await prettyDiagnostic(diagnostic);
30
+ INTERNAL_ORIGINAL_CONSOLE.error(chalk.red(message));
31
+ if (codeframe || stack) {
32
+ INTERNAL_ORIGINAL_CONSOLE.error('');
33
+ }
34
+ INTERNAL_ORIGINAL_CONSOLE.error(codeframe);
35
+ INTERNAL_ORIGINAL_CONSOLE.error(stack);
36
+ if ((stack || codeframe) && hints.length > 0) {
37
+ INTERNAL_ORIGINAL_CONSOLE.error('');
38
+ }
39
+ for (let h of hints) {
40
+ INTERNAL_ORIGINAL_CONSOLE.error(chalk.blue(h));
41
+ }
42
+ if (documentation) {
43
+ INTERNAL_ORIGINAL_CONSOLE.error(chalk.magenta.bold(documentation));
20
44
  }
21
45
  }
22
46
  } else {
23
- console.error(e);
47
+ INTERNAL_ORIGINAL_CONSOLE.error(e);
24
48
  }
49
+
50
+ // A hack to definitely ensure we logged the uncaught exception
51
+ await new Promise(resolve => setTimeout(resolve, 100));
25
52
  }
26
53
 
27
- process.on('unhandledRejection', (reason: mixed) => {
28
- logUncaughtError(reason);
54
+ const handleUncaughtException = async exception => {
55
+ try {
56
+ await logUncaughtError(exception);
57
+ } catch (err) {
58
+ console.error(exception);
59
+ console.error(err);
60
+ }
61
+
29
62
  process.exit(1);
30
- });
63
+ };
31
64
 
32
- const chalk = require('chalk');
33
- const program = require('commander');
34
- const path = require('path');
35
- const getPort = require('get-port');
36
- const version = require('../package.json').version;
37
-
38
- // Capture the NODE_ENV this process was launched with, so that it can be
39
- // used in Parcel (such as in process.env inlining).
40
- const initialNodeEnv = process.env.NODE_ENV;
41
- // Then, override NODE_ENV to be PARCEL_BUILD_ENV (replaced with `production` in builds)
42
- // so that dependencies of Parcel like React (which renders the cli through `ink`)
43
- // run in the appropriate mode.
44
- if (typeof process.env.PARCEL_BUILD_ENV === 'string') {
45
- process.env.NODE_ENV = process.env.PARCEL_BUILD_ENV;
46
- }
65
+ process.on('unhandledRejection', handleUncaughtException);
47
66
 
67
+ program.storeOptionsAsProperties();
48
68
  program.version(version);
49
69
 
50
70
  // --no-cache, --cache-dir, --no-source-maps, --no-autoinstall, --global?, --public-url, --log-level
@@ -52,57 +72,77 @@ program.version(version);
52
72
 
53
73
  const commonOptions = {
54
74
  '--no-cache': 'disable the filesystem cache',
75
+ '--config <path>':
76
+ 'specify which config to use. can be a path or a package name',
55
77
  '--cache-dir <path>': 'set the cache directory. defaults to ".parcel-cache"',
56
78
  '--no-source-maps': 'disable sourcemaps',
57
- '--no-autoinstall': 'disable autoinstall',
58
79
  '--target [name]': [
59
80
  'only build given target(s)',
60
81
  (val, list) => list.concat([val]),
61
82
  [],
62
83
  ],
63
- '--log-level <level>': [
64
- 'set the log level, either "none", "error", "warn", "info", or "verbose".',
65
- /^(none|error|warn|info|verbose)$/,
66
- ],
84
+ '--log-level <level>': new commander.Option(
85
+ '--log-level <level>',
86
+ 'set the log level',
87
+ ).choices(['none', 'error', 'warn', 'info', 'verbose']),
88
+ '--dist-dir <dir>':
89
+ 'output directory to write to when unspecified by targets',
90
+ '--no-autoinstall': 'disable autoinstall',
67
91
  '--profile': 'enable build profiling',
68
92
  '-V, --version': 'output the version number',
93
+ '--detailed-report [count]': [
94
+ 'print the asset timings and sizes in the build report',
95
+ parseOptionInt,
96
+ ],
97
+ '--reporter <name>': [
98
+ 'additional reporters to run',
99
+ (val, acc) => {
100
+ acc.push(val);
101
+ return acc;
102
+ },
103
+ [],
104
+ ],
69
105
  };
70
106
 
71
107
  var hmrOptions = {
72
108
  '--no-hmr': 'disable hot module replacement',
109
+ '-p, --port <port>': [
110
+ 'set the port to serve on. defaults to $PORT or 1234',
111
+ process.env.PORT,
112
+ ],
113
+ '--host <host>':
114
+ 'set the host to listen on, defaults to listening on all interfaces',
73
115
  '--https': 'serves files over HTTPS',
74
116
  '--cert <path>': 'path to certificate to use with HTTPS',
75
117
  '--key <path>': 'path to private key to use with HTTPS',
118
+ '--hmr-port <port>': ['hot module replacement port', process.env.HMR_PORT],
76
119
  };
77
120
 
78
121
  function applyOptions(cmd, options) {
79
122
  for (let opt in options) {
80
- cmd.option(
81
- opt,
82
- ...(Array.isArray(options[opt]) ? options[opt] : [options[opt]]),
83
- );
123
+ const option = options[opt];
124
+ if (option instanceof commander.Option) {
125
+ cmd.addOption(option);
126
+ } else {
127
+ cmd.option(opt, ...(Array.isArray(option) ? option : [option]));
128
+ }
84
129
  }
85
130
  }
86
131
 
87
132
  let serve = program
88
133
  .command('serve [input...]')
89
134
  .description('starts a development server')
90
- .option(
91
- '-p, --port <port>',
92
- 'set the port to serve on. defaults to 1234',
93
- parseInt,
94
- )
95
- .option('--public-url <url>', 'set the path prefix to use in serve mode')
96
- .option(
97
- '--host <host>',
98
- 'set the host to listen on, defaults to listening on all interfaces',
99
- )
135
+ .option('--public-url <url>', 'the path prefix for absolute urls')
100
136
  .option(
101
137
  '--open [browser]',
102
138
  'automatically open in specified browser, defaults to default browser',
103
139
  )
104
140
  .option('--watch-for-stdin', 'exit when stdin closes')
105
- .action(run);
141
+ .option(
142
+ '--lazy',
143
+ 'Build async bundles on demand, when requested in the browser',
144
+ )
145
+ .action(runCommand);
106
146
 
107
147
  applyOptions(serve, hmrOptions);
108
148
  applyOptions(serve, commonOptions);
@@ -110,8 +150,10 @@ applyOptions(serve, commonOptions);
110
150
  let watch = program
111
151
  .command('watch [input...]')
112
152
  .description('starts the bundler in watch mode')
153
+ .option('--public-url <url>', 'the path prefix for absolute urls')
154
+ .option('--no-content-hash', 'disable content hashing')
113
155
  .option('--watch-for-stdin', 'exit when stdin closes')
114
- .action(run);
156
+ .action(runCommand);
115
157
 
116
158
  applyOptions(watch, hmrOptions);
117
159
  applyOptions(watch, commonOptions);
@@ -119,138 +161,237 @@ applyOptions(watch, commonOptions);
119
161
  let build = program
120
162
  .command('build [input...]')
121
163
  .description('bundles for production')
122
- .option('--no-minify', 'disable minification')
164
+ .option('--no-optimize', 'disable minification')
123
165
  .option('--no-scope-hoist', 'disable scope-hoisting')
124
- .action(run);
166
+ .option('--public-url <url>', 'the path prefix for absolute urls')
167
+ .option('--no-content-hash', 'disable content hashing')
168
+ .action(runCommand);
125
169
 
126
170
  applyOptions(build, commonOptions);
127
171
 
128
172
  program
129
173
  .command('help [command]')
130
174
  .description('display help information for a command')
131
- .action(function(command) {
175
+ .action(function (command) {
132
176
  let cmd = program.commands.find(c => c.name() === command) || program;
133
177
  cmd.help();
134
178
  });
135
179
 
136
- program.on('--help', function() {
137
- console.log('');
138
- console.log(
180
+ program.on('--help', function () {
181
+ INTERNAL_ORIGINAL_CONSOLE.log('');
182
+ INTERNAL_ORIGINAL_CONSOLE.log(
139
183
  ' Run `' +
140
184
  chalk.bold('parcel help <command>') +
141
185
  '` for more information on specific commands',
142
186
  );
143
- console.log('');
187
+ INTERNAL_ORIGINAL_CONSOLE.log('');
144
188
  });
145
189
 
190
+ // Override to output option description if argument was missing
191
+ commander.Command.prototype.optionMissingArgument = function (option) {
192
+ INTERNAL_ORIGINAL_CONSOLE.error(
193
+ "error: option `%s' argument missing",
194
+ option.flags,
195
+ );
196
+ INTERNAL_ORIGINAL_CONSOLE.log(program.createHelp().optionDescription(option));
197
+ process.exit(1);
198
+ };
199
+
146
200
  // Make serve the default command except for --help
147
201
  var args = process.argv;
148
202
  if (args[2] === '--help' || args[2] === '-h') args[2] = 'help';
203
+
149
204
  if (!args[2] || !program.commands.some(c => c.name() === args[2])) {
150
205
  args.splice(2, 0, 'serve');
151
206
  }
152
207
 
153
208
  program.parse(args);
154
209
 
155
- async function run(entries: Array<string>, command: any) {
156
- entries = entries.map(entry => path.resolve(entry));
210
+ function runCommand(...args) {
211
+ run(...args).catch(handleUncaughtException);
212
+ }
157
213
 
214
+ async function run(
215
+ entries: Array<string>,
216
+ _opts: any, // using pre v7 Commander options as properties
217
+ command: any,
218
+ ) {
158
219
  if (entries.length === 0) {
159
- console.log('No entries found');
160
- return;
220
+ entries = ['.'];
161
221
  }
222
+
223
+ entries = entries.map(entry => path.resolve(entry));
224
+
162
225
  let Parcel = require('@parcel/core').default;
163
- let packageManager = new NodePackageManager(new NodeFS());
164
- let defaultConfig: ParcelConfigFile = await packageManager.require(
165
- '@parcel/config-default',
166
- __filename,
167
- );
226
+ let fs = new NodeFS();
227
+ let options = await normalizeOptions(command, fs);
168
228
  let parcel = new Parcel({
169
229
  entries,
170
- packageManager,
171
- defaultConfig: {
172
- ...defaultConfig,
173
- filePath: (
174
- await packageManager.resolve('@parcel/config-default', __filename)
175
- ).resolved,
176
- },
177
- patchConsole: true,
178
- ...(await normalizeOptions(command)),
230
+ // $FlowFixMe[extra-arg] - flow doesn't know about the `paths` option (added in Node v8.9.0)
231
+ defaultConfig: require.resolve('@parcel/config-default', {
232
+ paths: [fs.cwd(), __dirname],
233
+ }),
234
+ shouldPatchConsole: true,
235
+ ...options,
179
236
  });
180
237
 
181
- if (command.name() === 'watch' || command.name() === 'serve') {
182
- let {unsubscribe} = await parcel.watch(err => {
183
- if (err) {
184
- throw err;
185
- }
186
- });
238
+ let disposable = new Disposable();
239
+ let unsubscribe: () => Promise<mixed>;
240
+ let isExiting;
241
+ async function exit(exitCode: number = 0) {
242
+ if (isExiting) {
243
+ return;
244
+ }
245
+
246
+ isExiting = true;
247
+ if (unsubscribe != null) {
248
+ await unsubscribe();
249
+ } else if (parcel.isProfiling) {
250
+ await parcel.stopProfiling();
251
+ }
187
252
 
188
- let isExiting;
189
- const exit = async () => {
190
- if (isExiting) {
253
+ if (process.stdin.isTTY && process.stdin.isRaw) {
254
+ // $FlowFixMe
255
+ process.stdin.setRawMode(false);
256
+ }
257
+
258
+ disposable.dispose();
259
+ process.exit(exitCode);
260
+ }
261
+
262
+ const isWatching = command.name() === 'watch' || command.name() === 'serve';
263
+ if (process.stdin.isTTY) {
264
+ // $FlowFixMe
265
+ process.stdin.setRawMode(true);
266
+ require('readline').emitKeypressEvents(process.stdin);
267
+
268
+ let stream = process.stdin.on('keypress', async (char, key) => {
269
+ if (!key.ctrl) {
191
270
  return;
192
271
  }
193
272
 
194
- isExiting = true;
195
- await unsubscribe();
196
- process.exit();
197
- };
273
+ switch (key.name) {
274
+ case 'c':
275
+ // Detect the ctrl+c key, and gracefully exit after writing the asset graph to the cache.
276
+ // This is mostly for tools that wrap Parcel as a child process like yarn and npm.
277
+ //
278
+ // Setting raw mode prevents SIGINT from being sent in response to ctrl-c:
279
+ // https://nodejs.org/api/tty.html#tty_readstream_setrawmode_mode
280
+ //
281
+ // We don't use the SIGINT event for this because when run inside yarn, the parent
282
+ // yarn process ends before Parcel and it appears that Parcel has ended while it may still
283
+ // be cleaning up. Handling events from stdin prevents this impression.
284
+
285
+ // Enqueue a busy message to be shown if Parcel doesn't shut down
286
+ // within the timeout.
287
+ setTimeout(
288
+ () =>
289
+ INTERNAL_ORIGINAL_CONSOLE.log(
290
+ chalk.bold.yellowBright('Parcel is shutting down...'),
291
+ ),
292
+ 500,
293
+ );
294
+ // When watching, a 0 success code is acceptable when Parcel is interrupted with ctrl-c.
295
+ // When building, fail with a code as if we received a SIGINT.
296
+ await exit(isWatching ? 0 : SIGINT_EXIT_CODE);
297
+ break;
298
+ case 'e':
299
+ await (parcel.isProfiling
300
+ ? parcel.stopProfiling()
301
+ : parcel.startProfiling());
302
+ break;
303
+ case 'y':
304
+ await parcel.takeHeapSnapshot();
305
+ break;
306
+ }
307
+ });
308
+
309
+ disposable.add(() => {
310
+ stream.destroy();
311
+ });
312
+ }
313
+
314
+ if (isWatching) {
315
+ ({unsubscribe} = await parcel.watch(err => {
316
+ if (err) {
317
+ throw err;
318
+ }
319
+ }));
320
+
321
+ if (command.open && options.serveOptions) {
322
+ await openInBrowser(
323
+ `${options.serveOptions.https ? 'https' : 'http'}://${
324
+ options.serveOptions.host || 'localhost'
325
+ }:${options.serveOptions.port}`,
326
+ command.open,
327
+ );
328
+ }
198
329
 
199
330
  if (command.watchForStdin) {
200
331
  process.stdin.on('end', async () => {
201
- console.log('STDIN closed, ending');
332
+ INTERNAL_ORIGINAL_CONSOLE.log('STDIN closed, ending');
202
333
 
203
334
  await exit();
204
335
  });
205
336
  process.stdin.resume();
206
337
  }
207
338
 
208
- // Detect the ctrl+c key, and gracefully exit after writing the asset graph to the cache.
209
- // This is mostly for tools that wrap Parcel as a child process like yarn and npm.
210
- //
211
- // Setting raw mode prevents SIGINT from being sent in response to ctrl-c:
212
- // https://nodejs.org/api/tty.html#tty_readstream_setrawmode_mode
213
- //
214
- // We don't use the SIGINT event for this because when run inside yarn, the parent
215
- // yarn process ends before Parcel and it appears that Parcel has ended while it may still
216
- // be cleaning up. Handling events from stdin prevents this impression.
217
- if (process.stdin.isTTY) {
218
- // $FlowFixMe
219
- process.stdin.setRawMode(true);
220
- require('readline').emitKeypressEvents(process.stdin);
221
-
222
- process.stdin.on('keypress', async (char, key) => {
223
- if (key.ctrl && key.name === 'c') {
224
- await exit();
225
- }
226
- });
227
- }
228
-
229
- // In non-tty cases, respond to SIGINT by cleaning up.
339
+ // In non-tty cases, respond to SIGINT by cleaning up. Since we're watching,
340
+ // a 0 success code is acceptable.
230
341
  process.on('SIGINT', exit);
231
342
  process.on('SIGTERM', exit);
232
343
  } else {
233
344
  try {
234
345
  await parcel.run();
235
- } catch (e) {
346
+ } catch (err) {
236
347
  // If an exception is thrown during Parcel.build, it is given to reporters in a
237
348
  // buildFailure event, and has been shown to the user.
238
- if (!(e instanceof BuildError)) {
239
- logUncaughtError(e);
349
+ if (!(err instanceof BuildError)) {
350
+ await logUncaughtError(err);
240
351
  }
241
- process.exit(1);
352
+ await exit(1);
242
353
  }
354
+
355
+ await exit();
243
356
  }
244
357
  }
245
358
 
246
- async function normalizeOptions(command): Promise<InitialParcelOptions> {
359
+ function parsePort(portValue: string): number {
360
+ let parsedPort = Number(portValue);
361
+
362
+ // Throw an error if port value is invalid...
363
+ if (!Number.isInteger(parsedPort)) {
364
+ throw new Error(`Port ${portValue} is not a valid integer.`);
365
+ }
366
+
367
+ return parsedPort;
368
+ }
369
+
370
+ function parseOptionInt(value) {
371
+ const parsedValue = parseInt(value, 10);
372
+ if (isNaN(parsedValue)) {
373
+ throw new commander.InvalidOptionArgumentError('Must be an integer.');
374
+ }
375
+ return parsedValue;
376
+ }
377
+
378
+ async function normalizeOptions(
379
+ command,
380
+ inputFS,
381
+ ): Promise<InitialParcelOptions> {
247
382
  let nodeEnv;
248
383
  if (command.name() === 'build') {
249
- nodeEnv = initialNodeEnv || 'production';
384
+ nodeEnv = process.env.NODE_ENV || 'production';
385
+ // Autoinstall unless explicitly disabled or we detect a CI environment.
386
+ command.autoinstall = !(command.autoinstall === false || process.env.CI);
250
387
  } else {
251
- nodeEnv = initialNodeEnv || 'development';
388
+ nodeEnv = process.env.NODE_ENV || 'development';
252
389
  }
253
390
 
391
+ // Set process.env.NODE_ENV to a default if undefined so that it is
392
+ // available in JS configs and plugins.
393
+ process.env.NODE_ENV = nodeEnv;
394
+
254
395
  let https = !!command.https;
255
396
  if (command.cert && command.key) {
256
397
  https = {
@@ -259,19 +400,41 @@ async function normalizeOptions(command): Promise<InitialParcelOptions> {
259
400
  };
260
401
  }
261
402
 
262
- let serve = false;
263
- if (command.name() === 'serve') {
264
- let {port = 1234, host, publicUrl} = command;
265
- port = await getPort({port, host});
403
+ let serveOptions = false;
404
+ let {host} = command;
266
405
 
267
- if (command.port && port !== command.port) {
268
- // Parcel logger is not set up at this point, so just use native console.
269
- console.warn(
270
- chalk.bold.yellowBright(`⚠️ Port ${command.port} could not be used.`),
271
- );
406
+ // Ensure port is valid and available
407
+ let port = parsePort(command.port || '1234');
408
+ let originalPort = port;
409
+ if (command.name() === 'serve' || command.hmr) {
410
+ try {
411
+ port = await getPort({port, host});
412
+ } catch (err) {
413
+ throw new ThrowableDiagnostic({
414
+ diagnostic: {
415
+ message: `Could not get available port: ${err.message}`,
416
+ origin: 'parcel',
417
+ stack: err.stack,
418
+ },
419
+ });
420
+ }
421
+
422
+ if (port !== originalPort) {
423
+ let errorMessage = `Port "${originalPort}" could not be used`;
424
+ if (command.port != null) {
425
+ // Throw the error if the user defined a custom port
426
+ throw new Error(errorMessage);
427
+ } else {
428
+ // Parcel logger is not set up at this point, so just use native INTERNAL_ORIGINAL_CONSOLE
429
+ INTERNAL_ORIGINAL_CONSOLE.warn(errorMessage);
430
+ }
272
431
  }
432
+ }
433
+
434
+ if (command.name() === 'serve') {
435
+ let {publicUrl} = command;
273
436
 
274
- serve = {
437
+ serveOptions = {
275
438
  https,
276
439
  port,
277
440
  host,
@@ -279,27 +442,56 @@ async function normalizeOptions(command): Promise<InitialParcelOptions> {
279
442
  };
280
443
  }
281
444
 
282
- let hmr = false;
445
+ let hmrOptions = null;
283
446
  if (command.name() !== 'build' && command.hmr !== false) {
284
- hmr = true;
447
+ let hmrport = command.hmrPort ? parsePort(command.hmrPort) : port;
448
+
449
+ hmrOptions = {port: hmrport, host};
450
+ }
451
+
452
+ if (command.detailedReport === true) {
453
+ command.detailedReport = '10';
285
454
  }
286
455
 
456
+ let additionalReporters = [
457
+ {packageName: '@parcel/reporter-cli', resolveFrom: __filename},
458
+ ...(command.reporter: Array<string>).map(packageName => ({
459
+ packageName,
460
+ resolveFrom: path.join(inputFS.cwd(), 'index'),
461
+ })),
462
+ ];
463
+
287
464
  let mode = command.name() === 'build' ? 'production' : 'development';
288
465
  return {
289
- disableCache: command.cache === false,
466
+ shouldDisableCache: command.cache === false,
290
467
  cacheDir: command.cacheDir,
468
+ config: command.config,
291
469
  mode,
292
- minify: command.minify != null ? command.minify : mode === 'production',
293
- sourceMaps: command.sourceMaps ?? true,
294
- scopeHoist: command.scopeHoist,
295
- hot: hmr,
296
- serve,
470
+ hmrOptions,
471
+ shouldContentHash: hmrOptions ? false : command.contentHash,
472
+ serveOptions,
297
473
  targets: command.target.length > 0 ? command.target : null,
298
- autoinstall: command.autoinstall ?? true,
474
+ shouldAutoInstall: command.autoinstall ?? true,
299
475
  logLevel: command.logLevel,
300
- profile: command.profile,
476
+ shouldProfile: command.profile,
477
+ shouldBuildLazily: command.lazy,
478
+ detailedReport:
479
+ command.detailedReport != null
480
+ ? {
481
+ assetsPerBundle: parseInt(command.detailedReport, 10),
482
+ }
483
+ : null,
301
484
  env: {
302
485
  NODE_ENV: nodeEnv,
303
486
  },
487
+ additionalReporters,
488
+ defaultTargetOptions: {
489
+ shouldOptimize:
490
+ command.optimize != null ? command.optimize : mode === 'production',
491
+ sourceMaps: command.sourceMaps ?? true,
492
+ shouldScopeHoist: command.scopeHoist,
493
+ publicUrl: command.publicUrl,
494
+ distDir: command.distDir,
495
+ },
304
496
  };
305
497
  }