@easyv/react-component-builder 0.19.3 → 0.19.5-beta.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/config/paths.js +24 -24
- package/config/webpack.config.build.js +70 -70
- package/config/webpack.config.common.js +126 -126
- package/config/webpack.config.js +126 -126
- package/launcher/build.js +122 -120
- package/launcher/generate.js +99 -99
- package/launcher/start.js +238 -238
- package/loaders/react-entry-loader.js +470 -430
- package/package.json +76 -76
- package/public/component.ejs +51 -51
- package/public/home.ejs +21 -21
- package/templates/basic/assets/logo.png +0 -0
- package/templates/basic/config/main.data.json +14 -14
- package/templates/basic/config/main.json +6 -6
- package/templates/basic/index.jsx +26 -26
- package/templates/basic/styles/index.module.css +3 -3
- package/templates/basic/utils/bind-children.js +10 -10
- package/templates/basic/utils/reduce-config.js +20 -20
- package/templates/three-component/config/main.data.json +14 -14
- package/templates/three-component/config/main.json +76 -76
- package/templates/three-component/index.jsx +122 -122
- package/templates/three-component/utils/Component.js +274 -274
- package/templates/three-component/utils/OrbitControls.js +1051 -1051
- package/templates/three-component/utils/reduce-config.js +20 -20
- package/utils/auto-assign-port.js +11 -11
- package/utils/index.js +91 -91
- package/utils/openBrowser.js +153 -153
- package/utils/openChrome.applescript +94 -94
package/launcher/generate.js
CHANGED
|
@@ -1,99 +1,99 @@
|
|
|
1
|
-
var inquirer = require('inquirer');
|
|
2
|
-
var path = require('path');
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const fse = require('fs-extra');
|
|
5
|
-
const chalk = require('chalk');
|
|
6
|
-
const { appComponents, appPackage, templates } = require('../config/paths');
|
|
7
|
-
|
|
8
|
-
const defaultValues = {
|
|
9
|
-
module_name: 'text',
|
|
10
|
-
name: '文本',
|
|
11
|
-
};
|
|
12
|
-
let templateValues = [
|
|
13
|
-
{
|
|
14
|
-
name: 'React演示',
|
|
15
|
-
value: 'basic',
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
name: 'Three Component',
|
|
19
|
-
value: 'three-component',
|
|
20
|
-
},
|
|
21
|
-
];
|
|
22
|
-
|
|
23
|
-
module.exports = (cb, addCustom, generateCustom, add) => {
|
|
24
|
-
if (!add) {
|
|
25
|
-
const custom = addCustom();
|
|
26
|
-
templateValues = [...templateValues, ...custom];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
inquirer
|
|
30
|
-
.prompt([
|
|
31
|
-
{
|
|
32
|
-
type: 'input',
|
|
33
|
-
name: 'moduleName',
|
|
34
|
-
message: '你的组件名称是什么?',
|
|
35
|
-
validate: function (value) {
|
|
36
|
-
return /^[a-zA-Z][\w-]+$/.test(value)
|
|
37
|
-
? true
|
|
38
|
-
: '名称只能是 英文开头 包含 英文、数字、_- 的字符串';
|
|
39
|
-
},
|
|
40
|
-
default: defaultValues.module_name,
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
type: 'input',
|
|
44
|
-
name: 'name',
|
|
45
|
-
message: '中文别名是什么?',
|
|
46
|
-
default: defaultValues.name,
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
type: 'list',
|
|
50
|
-
name: 'template',
|
|
51
|
-
message: '要添加哪种模版?',
|
|
52
|
-
choices: templateValues,
|
|
53
|
-
},
|
|
54
|
-
])
|
|
55
|
-
.then((answers) => {
|
|
56
|
-
let { moduleName, name, template } = answers;
|
|
57
|
-
const base = {
|
|
58
|
-
name: !add ? name : '##name##',
|
|
59
|
-
module_name: !add ? moduleName : '##module_name##',
|
|
60
|
-
version: '1.0.0',
|
|
61
|
-
show: 1,
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
const copyPath = path.join(appComponents, moduleName);
|
|
65
|
-
// 检查重名
|
|
66
|
-
if (fs.existsSync(copyPath)) {
|
|
67
|
-
console.log(chalk.red(`组件名称已存在`));
|
|
68
|
-
process.exit();
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (template.includes('custom-')) {
|
|
72
|
-
generateCustom(name, moduleName, template.substring(7));
|
|
73
|
-
} else {
|
|
74
|
-
// 重写配置
|
|
75
|
-
const templatePath = path.join(templates, template);
|
|
76
|
-
const configPath = 'config/main.json';
|
|
77
|
-
|
|
78
|
-
fse.copySync(templatePath, copyPath, {
|
|
79
|
-
filter: (src, dest) => {
|
|
80
|
-
if (src === path.join(templatePath, configPath)) {
|
|
81
|
-
const config = require(src);
|
|
82
|
-
config.base = base;
|
|
83
|
-
fs.writeFileSync(
|
|
84
|
-
path.join(copyPath, configPath),
|
|
85
|
-
JSON.stringify(config, null, 2),
|
|
86
|
-
);
|
|
87
|
-
return 0;
|
|
88
|
-
}
|
|
89
|
-
return 1;
|
|
90
|
-
},
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
console.log();
|
|
95
|
-
console.log(chalk.green(`模版添加成功`));
|
|
96
|
-
cb && cb();
|
|
97
|
-
})
|
|
98
|
-
.catch((error) => cb && cb(error));
|
|
99
|
-
};
|
|
1
|
+
var inquirer = require('inquirer');
|
|
2
|
+
var path = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const fse = require('fs-extra');
|
|
5
|
+
const chalk = require('chalk');
|
|
6
|
+
const { appComponents, appPackage, templates } = require('../config/paths');
|
|
7
|
+
|
|
8
|
+
const defaultValues = {
|
|
9
|
+
module_name: 'text',
|
|
10
|
+
name: '文本',
|
|
11
|
+
};
|
|
12
|
+
let templateValues = [
|
|
13
|
+
{
|
|
14
|
+
name: 'React演示',
|
|
15
|
+
value: 'basic',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
name: 'Three Component',
|
|
19
|
+
value: 'three-component',
|
|
20
|
+
},
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
module.exports = (cb, addCustom, generateCustom, add) => {
|
|
24
|
+
if (!add) {
|
|
25
|
+
const custom = addCustom();
|
|
26
|
+
templateValues = [...templateValues, ...custom];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
inquirer
|
|
30
|
+
.prompt([
|
|
31
|
+
{
|
|
32
|
+
type: 'input',
|
|
33
|
+
name: 'moduleName',
|
|
34
|
+
message: '你的组件名称是什么?',
|
|
35
|
+
validate: function (value) {
|
|
36
|
+
return /^[a-zA-Z][\w-]+$/.test(value)
|
|
37
|
+
? true
|
|
38
|
+
: '名称只能是 英文开头 包含 英文、数字、_- 的字符串';
|
|
39
|
+
},
|
|
40
|
+
default: defaultValues.module_name,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
type: 'input',
|
|
44
|
+
name: 'name',
|
|
45
|
+
message: '中文别名是什么?',
|
|
46
|
+
default: defaultValues.name,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
type: 'list',
|
|
50
|
+
name: 'template',
|
|
51
|
+
message: '要添加哪种模版?',
|
|
52
|
+
choices: templateValues,
|
|
53
|
+
},
|
|
54
|
+
])
|
|
55
|
+
.then((answers) => {
|
|
56
|
+
let { moduleName, name, template } = answers;
|
|
57
|
+
const base = {
|
|
58
|
+
name: !add ? name : '##name##',
|
|
59
|
+
module_name: !add ? moduleName : '##module_name##',
|
|
60
|
+
version: '1.0.0',
|
|
61
|
+
show: 1,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const copyPath = path.join(appComponents, moduleName);
|
|
65
|
+
// 检查重名
|
|
66
|
+
if (fs.existsSync(copyPath)) {
|
|
67
|
+
console.log(chalk.red(`组件名称已存在`));
|
|
68
|
+
process.exit();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (template.includes('custom-')) {
|
|
72
|
+
generateCustom(name, moduleName, template.substring(7));
|
|
73
|
+
} else {
|
|
74
|
+
// 重写配置
|
|
75
|
+
const templatePath = path.join(templates, template);
|
|
76
|
+
const configPath = 'config/main.json';
|
|
77
|
+
|
|
78
|
+
fse.copySync(templatePath, copyPath, {
|
|
79
|
+
filter: (src, dest) => {
|
|
80
|
+
if (src === path.join(templatePath, configPath)) {
|
|
81
|
+
const config = require(src);
|
|
82
|
+
config.base = base;
|
|
83
|
+
fs.writeFileSync(
|
|
84
|
+
path.join(copyPath, configPath),
|
|
85
|
+
JSON.stringify(config, null, 2),
|
|
86
|
+
);
|
|
87
|
+
return 0;
|
|
88
|
+
}
|
|
89
|
+
return 1;
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
console.log();
|
|
95
|
+
console.log(chalk.green(`模版添加成功`));
|
|
96
|
+
cb && cb();
|
|
97
|
+
})
|
|
98
|
+
.catch((error) => cb && cb(error));
|
|
99
|
+
};
|
package/launcher/start.js
CHANGED
|
@@ -1,238 +1,238 @@
|
|
|
1
|
-
const webpack = require('webpack');
|
|
2
|
-
const WebpackDevServer = require('webpack-dev-server');
|
|
3
|
-
const getWebpackConfig = require('../config/webpack.config');
|
|
4
|
-
const chalk = require('chalk');
|
|
5
|
-
const glob = require('glob');
|
|
6
|
-
const { appComponents, appPackage } = require('../config/paths');
|
|
7
|
-
const { checkComponentFiles } = require('../utils');
|
|
8
|
-
const autoAssignPort = require('../utils/auto-assign-port');
|
|
9
|
-
const path = require('path');
|
|
10
|
-
const openBrowser = require('../utils/openBrowser');
|
|
11
|
-
|
|
12
|
-
const isInteractive = process.stdout.isTTY;
|
|
13
|
-
const DEFAULT_PORT = 3005;
|
|
14
|
-
const HOST = process.env.HOST || '0.0.0.0';
|
|
15
|
-
let isFirstCompile = true;
|
|
16
|
-
|
|
17
|
-
function clearConsole() {
|
|
18
|
-
process.stdout.write(
|
|
19
|
-
process.platform === 'win32' ? '\x1B[2J\x1B[0f' : '\x1B[2J\x1B[3J\x1B[H',
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function printInstructions(appName, urls) {
|
|
24
|
-
console.log();
|
|
25
|
-
console.log(`You can now view ${chalk.bold(appName)} in the browser.`);
|
|
26
|
-
console.log();
|
|
27
|
-
|
|
28
|
-
if (urls.lanUrlForTerminal) {
|
|
29
|
-
console.log(
|
|
30
|
-
` ${chalk.bold('Local:')} ${urls.localUrlForTerminal}`,
|
|
31
|
-
);
|
|
32
|
-
// console.log(
|
|
33
|
-
// ` ${chalk.bold('On Your Network:')} ${urls.lanUrlForTerminal}`
|
|
34
|
-
// );
|
|
35
|
-
} else {
|
|
36
|
-
console.log(` ${urls.localUrlForTerminal}`);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function createCompiler({ appName, config, urls }) {
|
|
41
|
-
let compiler;
|
|
42
|
-
try {
|
|
43
|
-
compiler = webpack(config);
|
|
44
|
-
} catch (err) {
|
|
45
|
-
console.log(chalk.red('Failed to compile.'));
|
|
46
|
-
console.log();
|
|
47
|
-
console.log(err.message || err);
|
|
48
|
-
console.log();
|
|
49
|
-
process.exit(1);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// "invalid" event fires when you have changed a file, and webpack is
|
|
53
|
-
// recompiling a bundle. WebpackDevServer takes care to pause serving the
|
|
54
|
-
// bundle, so if you refresh, it'll wait instead of serving the old one.
|
|
55
|
-
// "invalid" is short for "bundle invalidated", it doesn't imply any errors.
|
|
56
|
-
compiler.hooks.invalid.tap('invalid', () => {
|
|
57
|
-
if (isInteractive) {
|
|
58
|
-
clearConsole();
|
|
59
|
-
}
|
|
60
|
-
console.log('Compiling...');
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
// "done" event fires when webpack has finished recompiling the bundle.
|
|
64
|
-
// Whether or not you have warnings or errors, you will get this event.
|
|
65
|
-
compiler.hooks.done.tap('done', async (stats) => {
|
|
66
|
-
if (isInteractive) {
|
|
67
|
-
clearConsole();
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const statsData = stats.toJson({
|
|
71
|
-
all: false,
|
|
72
|
-
warnings: true,
|
|
73
|
-
errors: true,
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
const messages = statsData;
|
|
77
|
-
const isSuccessful = !messages.errors.length && !messages.warnings.length;
|
|
78
|
-
if (isSuccessful) {
|
|
79
|
-
console.log(chalk.green('Compiled successfully!'));
|
|
80
|
-
}
|
|
81
|
-
if (isSuccessful && (isInteractive || isFirstCompile)) {
|
|
82
|
-
printInstructions(appName, urls);
|
|
83
|
-
}
|
|
84
|
-
isFirstCompile = false;
|
|
85
|
-
|
|
86
|
-
if (messages.errors.length) {
|
|
87
|
-
if (messages.errors.length > 1) {
|
|
88
|
-
messages.errors.length = 1;
|
|
89
|
-
}
|
|
90
|
-
console.log(chalk.red('Failed to compile.\n'));
|
|
91
|
-
console.log(messages.errors.join('\n\n'));
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (messages.warnings.length) {
|
|
96
|
-
console.log(chalk.yellow('Compiled with warnings.\n'));
|
|
97
|
-
console.log(messages.warnings.join('\n\n'));
|
|
98
|
-
|
|
99
|
-
console.log(
|
|
100
|
-
'\nSearch for the ' +
|
|
101
|
-
chalk.underline(chalk.yellow('keywords')) +
|
|
102
|
-
' to learn more about each warning.',
|
|
103
|
-
);
|
|
104
|
-
console.log(
|
|
105
|
-
'To ignore, add ' +
|
|
106
|
-
chalk.cyan('// eslint-disable-next-line') +
|
|
107
|
-
' to the line before.\n',
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
return compiler;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function start({ port, modules }) {
|
|
116
|
-
const url = `http://localhost:${port}`;
|
|
117
|
-
|
|
118
|
-
const config = getWebpackConfig({ port, modules });
|
|
119
|
-
const compiler = createCompiler({
|
|
120
|
-
appName: appPackage.name,
|
|
121
|
-
config,
|
|
122
|
-
urls: {
|
|
123
|
-
localUrlForTerminal: url,
|
|
124
|
-
},
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
const server = new WebpackDevServer(compiler, config.devServer);
|
|
128
|
-
|
|
129
|
-
server.listen(port, HOST, (err) => {
|
|
130
|
-
if (err) {
|
|
131
|
-
return console.log(err);
|
|
132
|
-
}
|
|
133
|
-
if (isInteractive) {
|
|
134
|
-
clearConsole();
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
console.log(chalk.cyan('Starting the development server...\n'));
|
|
138
|
-
openBrowser(url);
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
['SIGINT', 'SIGTERM'].forEach(function (sig) {
|
|
142
|
-
process.on(sig, function () {
|
|
143
|
-
server.close();
|
|
144
|
-
process.exit();
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function getBuildEntrys(modules = []) {
|
|
150
|
-
// 优先级
|
|
151
|
-
const suffix = ['jsx', 'tsx', 'js', 'ts'];
|
|
152
|
-
|
|
153
|
-
return new Promise((resolve) => {
|
|
154
|
-
// 两种获取方式配置方式
|
|
155
|
-
// new configs: ['config/main.(json|js)', 'config/main.data.(json|js)']
|
|
156
|
-
// old configs: ['config/base.js', 'config/config.js', 'mock/data.js']
|
|
157
|
-
|
|
158
|
-
glob(
|
|
159
|
-
`*/index.+(${suffix.join('|')})`,
|
|
160
|
-
{
|
|
161
|
-
cwd: appComponents,
|
|
162
|
-
},
|
|
163
|
-
function (err, matches) {
|
|
164
|
-
if (err) {
|
|
165
|
-
console.error(err);
|
|
166
|
-
process.exit();
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (!matches.length) process.exit();
|
|
170
|
-
|
|
171
|
-
const dir = matches.reduce((acc, path) => {
|
|
172
|
-
const name = path.slice(0, path.indexOf('/'));
|
|
173
|
-
if (modules.length && modules.indexOf(name) === -1) {
|
|
174
|
-
// 排除不打包的 如果目录是空的则忽略
|
|
175
|
-
return acc;
|
|
176
|
-
}
|
|
177
|
-
if (!acc[name]) {
|
|
178
|
-
acc[name] = [path];
|
|
179
|
-
} else {
|
|
180
|
-
acc[name].push(path);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return acc;
|
|
184
|
-
}, {});
|
|
185
|
-
|
|
186
|
-
const moduleNames = new Set();
|
|
187
|
-
|
|
188
|
-
// {a: [a.js, a.jsx, ...], ...}
|
|
189
|
-
const components = Object.keys(dir).map((dirname) => {
|
|
190
|
-
let indexPath;
|
|
191
|
-
suffix.every((ext) => {
|
|
192
|
-
const i = dir[dirname].findIndex((path) =>
|
|
193
|
-
path.endsWith('.' + ext),
|
|
194
|
-
);
|
|
195
|
-
return i > -1
|
|
196
|
-
? ((indexPath = path.join(appComponents, dir[dirname][i])), false)
|
|
197
|
-
: true;
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
const { base } = checkComponentFiles(
|
|
201
|
-
path.join(appComponents, dirname),
|
|
202
|
-
);
|
|
203
|
-
|
|
204
|
-
// 组件名称重复检查
|
|
205
|
-
let name = base.module_name;
|
|
206
|
-
if (moduleNames.has(moduleNames)) {
|
|
207
|
-
console.error(chalk.red`component name ${name} is duplicate.`);
|
|
208
|
-
process.exit();
|
|
209
|
-
}
|
|
210
|
-
moduleNames.add(name);
|
|
211
|
-
|
|
212
|
-
return {
|
|
213
|
-
dirname,
|
|
214
|
-
name,
|
|
215
|
-
base,
|
|
216
|
-
path: indexPath,
|
|
217
|
-
};
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
if (components.length) {
|
|
221
|
-
resolve(components);
|
|
222
|
-
} else {
|
|
223
|
-
process.exit();
|
|
224
|
-
}
|
|
225
|
-
},
|
|
226
|
-
);
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
module.exports = (modules) => {
|
|
231
|
-
getBuildEntrys(modules).then((modules) => {
|
|
232
|
-
autoAssignPort(DEFAULT_PORT, (port) => {
|
|
233
|
-
start({ port, modules });
|
|
234
|
-
});
|
|
235
|
-
});
|
|
236
|
-
};
|
|
237
|
-
|
|
238
|
-
module.exports.getBuildEntrys = getBuildEntrys;
|
|
1
|
+
const webpack = require('webpack');
|
|
2
|
+
const WebpackDevServer = require('webpack-dev-server');
|
|
3
|
+
const getWebpackConfig = require('../config/webpack.config');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const glob = require('glob');
|
|
6
|
+
const { appComponents, appPackage } = require('../config/paths');
|
|
7
|
+
const { checkComponentFiles } = require('../utils');
|
|
8
|
+
const autoAssignPort = require('../utils/auto-assign-port');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const openBrowser = require('../utils/openBrowser');
|
|
11
|
+
|
|
12
|
+
const isInteractive = process.stdout.isTTY;
|
|
13
|
+
const DEFAULT_PORT = 3005;
|
|
14
|
+
const HOST = process.env.HOST || '0.0.0.0';
|
|
15
|
+
let isFirstCompile = true;
|
|
16
|
+
|
|
17
|
+
function clearConsole() {
|
|
18
|
+
process.stdout.write(
|
|
19
|
+
process.platform === 'win32' ? '\x1B[2J\x1B[0f' : '\x1B[2J\x1B[3J\x1B[H',
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function printInstructions(appName, urls) {
|
|
24
|
+
console.log();
|
|
25
|
+
console.log(`You can now view ${chalk.bold(appName)} in the browser.`);
|
|
26
|
+
console.log();
|
|
27
|
+
|
|
28
|
+
if (urls.lanUrlForTerminal) {
|
|
29
|
+
console.log(
|
|
30
|
+
` ${chalk.bold('Local:')} ${urls.localUrlForTerminal}`,
|
|
31
|
+
);
|
|
32
|
+
// console.log(
|
|
33
|
+
// ` ${chalk.bold('On Your Network:')} ${urls.lanUrlForTerminal}`
|
|
34
|
+
// );
|
|
35
|
+
} else {
|
|
36
|
+
console.log(` ${urls.localUrlForTerminal}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function createCompiler({ appName, config, urls }) {
|
|
41
|
+
let compiler;
|
|
42
|
+
try {
|
|
43
|
+
compiler = webpack(config);
|
|
44
|
+
} catch (err) {
|
|
45
|
+
console.log(chalk.red('Failed to compile.'));
|
|
46
|
+
console.log();
|
|
47
|
+
console.log(err.message || err);
|
|
48
|
+
console.log();
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// "invalid" event fires when you have changed a file, and webpack is
|
|
53
|
+
// recompiling a bundle. WebpackDevServer takes care to pause serving the
|
|
54
|
+
// bundle, so if you refresh, it'll wait instead of serving the old one.
|
|
55
|
+
// "invalid" is short for "bundle invalidated", it doesn't imply any errors.
|
|
56
|
+
compiler.hooks.invalid.tap('invalid', () => {
|
|
57
|
+
if (isInteractive) {
|
|
58
|
+
clearConsole();
|
|
59
|
+
}
|
|
60
|
+
console.log('Compiling...');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// "done" event fires when webpack has finished recompiling the bundle.
|
|
64
|
+
// Whether or not you have warnings or errors, you will get this event.
|
|
65
|
+
compiler.hooks.done.tap('done', async (stats) => {
|
|
66
|
+
if (isInteractive) {
|
|
67
|
+
clearConsole();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const statsData = stats.toJson({
|
|
71
|
+
all: false,
|
|
72
|
+
warnings: true,
|
|
73
|
+
errors: true,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const messages = statsData;
|
|
77
|
+
const isSuccessful = !messages.errors.length && !messages.warnings.length;
|
|
78
|
+
if (isSuccessful) {
|
|
79
|
+
console.log(chalk.green('Compiled successfully!'));
|
|
80
|
+
}
|
|
81
|
+
if (isSuccessful && (isInteractive || isFirstCompile)) {
|
|
82
|
+
printInstructions(appName, urls);
|
|
83
|
+
}
|
|
84
|
+
isFirstCompile = false;
|
|
85
|
+
|
|
86
|
+
if (messages.errors.length) {
|
|
87
|
+
if (messages.errors.length > 1) {
|
|
88
|
+
messages.errors.length = 1;
|
|
89
|
+
}
|
|
90
|
+
console.log(chalk.red('Failed to compile.\n'));
|
|
91
|
+
console.log(messages.errors.join('\n\n'));
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (messages.warnings.length) {
|
|
96
|
+
console.log(chalk.yellow('Compiled with warnings.\n'));
|
|
97
|
+
console.log(messages.warnings.join('\n\n'));
|
|
98
|
+
|
|
99
|
+
console.log(
|
|
100
|
+
'\nSearch for the ' +
|
|
101
|
+
chalk.underline(chalk.yellow('keywords')) +
|
|
102
|
+
' to learn more about each warning.',
|
|
103
|
+
);
|
|
104
|
+
console.log(
|
|
105
|
+
'To ignore, add ' +
|
|
106
|
+
chalk.cyan('// eslint-disable-next-line') +
|
|
107
|
+
' to the line before.\n',
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
return compiler;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function start({ port, modules }) {
|
|
116
|
+
const url = `http://localhost:${port}`;
|
|
117
|
+
|
|
118
|
+
const config = getWebpackConfig({ port, modules });
|
|
119
|
+
const compiler = createCompiler({
|
|
120
|
+
appName: appPackage.name,
|
|
121
|
+
config,
|
|
122
|
+
urls: {
|
|
123
|
+
localUrlForTerminal: url,
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const server = new WebpackDevServer(compiler, config.devServer);
|
|
128
|
+
|
|
129
|
+
server.listen(port, HOST, (err) => {
|
|
130
|
+
if (err) {
|
|
131
|
+
return console.log(err);
|
|
132
|
+
}
|
|
133
|
+
if (isInteractive) {
|
|
134
|
+
clearConsole();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
console.log(chalk.cyan('Starting the development server...\n'));
|
|
138
|
+
openBrowser(url);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
['SIGINT', 'SIGTERM'].forEach(function (sig) {
|
|
142
|
+
process.on(sig, function () {
|
|
143
|
+
server.close();
|
|
144
|
+
process.exit();
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function getBuildEntrys(modules = []) {
|
|
150
|
+
// 优先级
|
|
151
|
+
const suffix = ['jsx', 'tsx', 'js', 'ts'];
|
|
152
|
+
|
|
153
|
+
return new Promise((resolve) => {
|
|
154
|
+
// 两种获取方式配置方式
|
|
155
|
+
// new configs: ['config/main.(json|js)', 'config/main.data.(json|js)']
|
|
156
|
+
// old configs: ['config/base.js', 'config/config.js', 'mock/data.js']
|
|
157
|
+
|
|
158
|
+
glob(
|
|
159
|
+
`*/index.+(${suffix.join('|')})`,
|
|
160
|
+
{
|
|
161
|
+
cwd: appComponents,
|
|
162
|
+
},
|
|
163
|
+
function (err, matches) {
|
|
164
|
+
if (err) {
|
|
165
|
+
console.error(err);
|
|
166
|
+
process.exit();
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (!matches.length) process.exit();
|
|
170
|
+
|
|
171
|
+
const dir = matches.reduce((acc, path) => {
|
|
172
|
+
const name = path.slice(0, path.indexOf('/'));
|
|
173
|
+
if (modules.length && modules.indexOf(name) === -1) {
|
|
174
|
+
// 排除不打包的 如果目录是空的则忽略
|
|
175
|
+
return acc;
|
|
176
|
+
}
|
|
177
|
+
if (!acc[name]) {
|
|
178
|
+
acc[name] = [path];
|
|
179
|
+
} else {
|
|
180
|
+
acc[name].push(path);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return acc;
|
|
184
|
+
}, {});
|
|
185
|
+
|
|
186
|
+
const moduleNames = new Set();
|
|
187
|
+
|
|
188
|
+
// {a: [a.js, a.jsx, ...], ...}
|
|
189
|
+
const components = Object.keys(dir).map((dirname) => {
|
|
190
|
+
let indexPath;
|
|
191
|
+
suffix.every((ext) => {
|
|
192
|
+
const i = dir[dirname].findIndex((path) =>
|
|
193
|
+
path.endsWith('.' + ext),
|
|
194
|
+
);
|
|
195
|
+
return i > -1
|
|
196
|
+
? ((indexPath = path.join(appComponents, dir[dirname][i])), false)
|
|
197
|
+
: true;
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
const { base } = checkComponentFiles(
|
|
201
|
+
path.join(appComponents, dirname),
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
// 组件名称重复检查
|
|
205
|
+
let name = base.module_name;
|
|
206
|
+
if (moduleNames.has(moduleNames)) {
|
|
207
|
+
console.error(chalk.red`component name ${name} is duplicate.`);
|
|
208
|
+
process.exit();
|
|
209
|
+
}
|
|
210
|
+
moduleNames.add(name);
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
dirname,
|
|
214
|
+
name,
|
|
215
|
+
base,
|
|
216
|
+
path: indexPath,
|
|
217
|
+
};
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
if (components.length) {
|
|
221
|
+
resolve(components);
|
|
222
|
+
} else {
|
|
223
|
+
process.exit();
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
);
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
module.exports = (modules) => {
|
|
231
|
+
getBuildEntrys(modules).then((modules) => {
|
|
232
|
+
autoAssignPort(DEFAULT_PORT, (port) => {
|
|
233
|
+
start({ port, modules });
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
module.exports.getBuildEntrys = getBuildEntrys;
|