1 | #!/usr/bin/env node
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | const path = require('path');
|
14 |
|
15 | const chalk = require('chalk');
|
16 | const importLocal = require('import-local');
|
17 | const parse = require('yargs-parser');
|
18 | const webpack = require('webpack');
|
19 |
|
20 | const pkg = require('../package.json');
|
21 |
|
22 | const { error: stderr } = console;
|
23 | const end = () => process.exit(0);
|
24 | const configTypes = {
|
25 | function: (c, argv) => Promise.resolve(c(argv.env || {}, argv)),
|
26 | object: (c) => Promise.resolve(c)
|
27 | };
|
28 |
|
29 | const help = chalk`
|
30 | ${pkg.description}
|
31 |
|
32 | {underline Usage}
|
33 | $ wp [...options]
|
34 |
|
35 | {underline Options}
|
36 | --config A path to a webpack config file
|
37 | --config.\{name\} A path to a webpack config file, and the config name to run
|
38 | --help Displays this message
|
39 | --silent Instruct the CLI to produce no console output
|
40 | --version Displays webpack-nano and webpack versions
|
41 |
|
42 | {underline Examples}
|
43 | $ wp
|
44 | $ wp --help
|
45 | $ wp --config webpack.config.js
|
46 | $ wp --config.serve webpack.config.js
|
47 | `;
|
48 |
|
49 | const doeet = async () => {
|
50 | process.on('SIGINT', end);
|
51 | process.on('SIGTERM', end);
|
52 |
|
53 | const argv = parse(process.argv.slice(2));
|
54 | const logPrefix = { ok: chalk.blue('⬡ webpack:'), whoops: chalk.red('⬢ webpack:') };
|
55 | const log = {
|
56 | error: (...args) => {
|
57 | if (argv.silent) return;
|
58 | args.unshift(logPrefix.whoops);
|
59 | stderr(...args);
|
60 | },
|
61 | info: (...args) => {
|
62 | if (argv.silent) return;
|
63 | args.unshift(logPrefix.ok);
|
64 | stderr(...args);
|
65 | }
|
66 | };
|
67 |
|
68 | if (argv.help) {
|
69 | stderr(help);
|
70 | return;
|
71 | }
|
72 |
|
73 | if (argv.version || argv.v) {
|
74 | stderr(`
|
75 | webpack-nano v${pkg.version}
|
76 | webpack v${webpack.version}
|
77 | `);
|
78 | return;
|
79 | }
|
80 |
|
81 | let config = {};
|
82 | let watchConfig;
|
83 |
|
84 | // let's not process any config if the user hasn't specified any
|
85 | if (argv.config) {
|
86 | const configName = typeof argv.config !== 'string' ? Object.keys(argv.config)[0] : null;
|
87 | // e.g. --config.batman webpack.config.js
|
88 | const configPath = argv.config[configName] || argv.config;
|
89 | let configExport = require(path.resolve(configPath)); // eslint-disable-line global-require, import/no-dynamic-require
|
90 | const configType = typeof configExport;
|
91 |
|
92 | if (configName) {
|
93 | if (!Array.isArray(configExport)) {
|
94 | throw new TypeError(
|
95 | `A config with name was specified, but the config ${configPath} does not export an Array.`
|
96 | );
|
97 | }
|
98 |
|
99 | configExport = configExport.find((c) => c.name === configName);
|
100 |
|
101 | if (!configExport) {
|
102 | throw new RangeError(`A config with name '${configName}' was not found in ${configPath}`);
|
103 | }
|
104 | }
|
105 |
|
106 | config = await configTypes[configType](configExport, argv);
|
107 | watchConfig = [].concat(config).find((c) => !!c.watch);
|
108 | }
|
109 |
|
110 | const compiler = webpack(config);
|
111 | const done = (fatal, stats) => {
|
112 | const hasErrors = stats && stats.hasErrors();
|
113 |
|
114 | process.exitCode = Number(!!fatal || (hasErrors && !watchConfig));
|
115 |
|
116 | if (fatal) {
|
117 | log.error(fatal);
|
118 | return;
|
119 | }
|
120 |
|
121 | const defaultStatsOptions = { colors: chalk.supportsColor, exclude: ['node_modules'] };
|
122 | const { options = {} } =
|
123 | []
|
124 | .concat(compiler.compilers || compiler)
|
125 | .reduce((a, c) => c.options.stats && c.options.stats) || {};
|
126 |
|
127 | const result = stats.toString(options.stats == null ? defaultStatsOptions : options.stats);
|
128 |
|
129 | log.info(result);
|
130 | };
|
131 |
|
132 | if (watchConfig) {
|
133 | log.info('Watching Files');
|
134 | compiler.watch(watchConfig.watchOptions || {}, done);
|
135 | } else {
|
136 | compiler.hooks.done.tap('webpack-nano', () => log.info('Build Finished'));
|
137 | compiler.run(done);
|
138 | }
|
139 | };
|
140 |
|
141 | process.on('unhandledRejection', (err) => {
|
142 | stderr(err.stack);
|
143 | process.exitCode = 1;
|
144 | });
|
145 |
|
146 | // eslint-disable-next-line no-unused-expressions
|
147 | importLocal(__filename) || doeet();
|
148 |
|
\ | No newline at end of file |