ee-core 2.9.2 → 2.10.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/LICENSE +21 -21
- package/README.md +65 -65
- package/addon/index.js +34 -34
- package/addon/window/index.js +98 -98
- package/bin/tools.js +8 -8
- package/config/cache.js +41 -38
- package/config/config.default.js +331 -330
- package/config/index.js +75 -73
- package/const/channel.js +17 -17
- package/const/index.js +8 -8
- package/controller/baseContextClass.js +34 -34
- package/controller/index.js +34 -34
- package/core/index.js +10 -10
- package/core/lib/ee.js +216 -216
- package/core/lib/loader/context_loader.js +106 -106
- package/core/lib/loader/ee_loader.js +435 -435
- package/core/lib/loader/file_loader.js +326 -326
- package/core/lib/loader/mixin/addon.js +32 -32
- package/core/lib/loader/mixin/config.js +130 -130
- package/core/lib/loader/mixin/controller.js +125 -125
- package/core/lib/loader/mixin/service.js +28 -28
- package/core/lib/utils/base_context_class.js +34 -34
- package/core/lib/utils/function.js +30 -30
- package/core/lib/utils/index.js +133 -133
- package/core/lib/utils/sequencify.js +59 -59
- package/core/lib/utils/timing.js +77 -77
- package/cross/index.js +183 -183
- package/cross/spawnProcess.js +183 -183
- package/ee/appLoader.js +48 -48
- package/ee/application.js +99 -99
- package/ee/baseApp.js +103 -102
- package/ee/eeApp.js +408 -408
- package/ee/index.js +57 -57
- package/electron/app/index.js +64 -58
- package/electron/index.js +19 -19
- package/electron/window/index.js +73 -73
- package/electron/window/winState.js +186 -186
- package/exception/index.js +112 -112
- package/html/boot.html +98 -98
- package/html/cross-failure.html +28 -28
- package/html/failure.html +28 -28
- package/html/index.js +13 -13
- package/httpclient/index.js +161 -161
- package/index.js +54 -54
- package/jobs/baseJobClass.js +16 -16
- package/jobs/child/app.js +65 -65
- package/jobs/child/forkProcess.js +145 -145
- package/jobs/child/index.js +82 -82
- package/jobs/child-pool/index.js +213 -213
- package/jobs/index.js +8 -8
- package/jobs/load-balancer/algorithm/index.js +11 -11
- package/jobs/load-balancer/algorithm/minimumConnection.js +18 -18
- package/jobs/load-balancer/algorithm/polling.js +11 -11
- package/jobs/load-balancer/algorithm/random.js +9 -9
- package/jobs/load-balancer/algorithm/specify.js +14 -14
- package/jobs/load-balancer/algorithm/weights.js +21 -21
- package/jobs/load-balancer/algorithm/weightsMinimumConnection.js +29 -29
- package/jobs/load-balancer/algorithm/weightsPolling.js +22 -22
- package/jobs/load-balancer/algorithm/weightsRandom.js +16 -16
- package/jobs/load-balancer/consts.js +9 -9
- package/jobs/load-balancer/index.js +201 -201
- package/jobs/load-balancer/scheduler.js +31 -31
- package/jobs/renderer/index.js +141 -141
- package/jobs/renderer/loadView.js +40 -40
- package/jobs/unification.js +63 -63
- package/loader/index.js +172 -172
- package/log/index.js +68 -68
- package/log/logger.js +86 -80
- package/main/index.js +56 -56
- package/message/childMessage.js +54 -54
- package/message/index.js +18 -18
- package/old-utils/index.js +91 -91
- package/package.json +38 -38
- package/ps/index.js +371 -371
- package/services/baseContextClass.js +34 -34
- package/services/index.js +40 -40
- package/socket/httpServer.js +147 -147
- package/socket/index.js +81 -81
- package/socket/io.js +27 -27
- package/socket/ipcServer.js +112 -112
- package/socket/socketServer.js +69 -67
- package/storage/index.js +38 -38
- package/storage/jsondb/adapters/Base.js +23 -23
- package/storage/jsondb/adapters/FileSync.js +64 -52
- package/storage/jsondb/main.js +55 -42
- package/storage/jsondbStorage.js +195 -195
- package/storage/sqliteStorage.js +123 -123
- package/utils/co.js +237 -237
- package/utils/copyto.js +160 -160
- package/utils/depd/index.js +538 -538
- package/utils/depd/lib/browser/index.js +77 -77
- package/utils/extend.js +73 -73
- package/utils/get-port/index.d.ts +64 -64
- package/utils/get-port/index.js +148 -148
- package/utils/helper.js +220 -220
- package/utils/index.js +160 -160
- package/utils/ip.js +261 -261
- package/utils/is.js +145 -145
- package/utils/json.js +72 -72
- package/utils/pargv.js +263 -263
- package/utils/time/index.js +19 -19
- package/utils/time/ms.js +162 -162
- package/utils/wrap.js +35 -35
|
@@ -1,435 +1,435 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const assert = require('assert');
|
|
6
|
-
const is = require('is-type-of');
|
|
7
|
-
const debug = require('debug')('ee-core:EeLoader');
|
|
8
|
-
const FileLoader = require('./file_loader');
|
|
9
|
-
const ContextLoader = require('./context_loader');
|
|
10
|
-
const Utils = require('../utils');
|
|
11
|
-
const Timing = require('../utils/timing');
|
|
12
|
-
const Ps = require('../../../ps');
|
|
13
|
-
|
|
14
|
-
const REQUIRE_COUNT = Symbol('EeLoader#requireCount');
|
|
15
|
-
|
|
16
|
-
class EeLoader {
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* @class
|
|
20
|
-
* @param {Object} options - options
|
|
21
|
-
* @param {String} options.baseDir - the directory of application
|
|
22
|
-
* @param {EeCore} options.app - Application instance
|
|
23
|
-
* @param {Logger} options.logger - logger
|
|
24
|
-
* @since 1.0.0
|
|
25
|
-
*/
|
|
26
|
-
constructor(options) {
|
|
27
|
-
this.options = options;
|
|
28
|
-
// assert(fs.existsSync(this.options.baseDir), `${this.options.baseDir} not exists`);
|
|
29
|
-
assert(this.options.app, 'options.app is required');
|
|
30
|
-
assert(this.options.logger, 'options.logger is required');
|
|
31
|
-
|
|
32
|
-
this.app = this.options.app;
|
|
33
|
-
this.timing = this.app.timing || new Timing();
|
|
34
|
-
this[REQUIRE_COUNT] = 0;
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* @member {Object} EeLoader#pkg
|
|
38
|
-
* @see {@link AppInfo#pkg}
|
|
39
|
-
* @since 1.0.0
|
|
40
|
-
*/
|
|
41
|
-
this.pkg = this.getPkg();
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Framework directories
|
|
45
|
-
*
|
|
46
|
-
* @member {Array} EeLoader#EePaths
|
|
47
|
-
* @see EeLoader#getEePaths
|
|
48
|
-
* @since 1.0.0
|
|
49
|
-
*/
|
|
50
|
-
this.EePaths = this.getEePaths();
|
|
51
|
-
debug('Loaded EePaths %j', this.EePaths);
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* @member {String} EeLoader#serverEnv
|
|
55
|
-
* @see AppInfo#env
|
|
56
|
-
* @since 1.0.0
|
|
57
|
-
*/
|
|
58
|
-
this.serverEnv = this.getServerEnv();
|
|
59
|
-
debug('Loaded serverEnv %j', this.serverEnv);
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* @member {AppInfo} EeLoader#appInfo
|
|
63
|
-
* @since 1.0.0
|
|
64
|
-
*/
|
|
65
|
-
this.appInfo = this.getAppInfo();
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* @member {String} EeLoader#serverScope
|
|
69
|
-
* @see AppInfo#serverScope
|
|
70
|
-
*/
|
|
71
|
-
this.serverScope = options.serverScope !== undefined
|
|
72
|
-
? options.serverScope
|
|
73
|
-
: this.getServerScope();
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Get {@link AppInfo#env}
|
|
78
|
-
* @return {String} env
|
|
79
|
-
* @see AppInfo#env
|
|
80
|
-
* @private
|
|
81
|
-
* @since 1.0.0
|
|
82
|
-
*/
|
|
83
|
-
getServerEnv() {
|
|
84
|
-
let serverEnv = this.options.env;
|
|
85
|
-
|
|
86
|
-
if (!serverEnv) {
|
|
87
|
-
throw new Error('[core] [lib] [loader] getServerEnv serverEnv can not be empty!');
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return serverEnv;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Get {@link AppInfo#scope}
|
|
95
|
-
* @return {String} serverScope
|
|
96
|
-
* @private
|
|
97
|
-
*/
|
|
98
|
-
getServerScope() {
|
|
99
|
-
return process.env.EE_SERVER_SCOPE || '';
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Get {@link AppInfo#name}
|
|
104
|
-
* @return {String} appname
|
|
105
|
-
* @private
|
|
106
|
-
* @since 1.0.0
|
|
107
|
-
*/
|
|
108
|
-
getAppname() {
|
|
109
|
-
if (this.pkg.name) {
|
|
110
|
-
debug('Loaded appname(%s) from package.json', this.pkg.name);
|
|
111
|
-
return this.pkg.name;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
throw new Error(`name is required from ${pkg}`);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Get home directory
|
|
119
|
-
* @return {String} home directory
|
|
120
|
-
* @since 3.4.0
|
|
121
|
-
*/
|
|
122
|
-
getHomedir() {
|
|
123
|
-
return this.options.homeDir;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Get app info
|
|
128
|
-
* @return {AppInfo} appInfo
|
|
129
|
-
* @since 1.0.0
|
|
130
|
-
*/
|
|
131
|
-
getAppInfo() {
|
|
132
|
-
const env = this.serverEnv;
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Meta information of the application
|
|
136
|
-
* @class AppInfo
|
|
137
|
-
*/
|
|
138
|
-
return {
|
|
139
|
-
/**
|
|
140
|
-
* The name of the application, retrieve from the name property in `package.json`.
|
|
141
|
-
* @member {String} AppInfo#name
|
|
142
|
-
*/
|
|
143
|
-
name: this.getAppname(),
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* The current directory, where the application code is.
|
|
147
|
-
* @member {String} AppInfo#baseDir
|
|
148
|
-
*/
|
|
149
|
-
baseDir: this.options.baseDir,
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* The environment of the application, **it's not NODE_ENV**
|
|
153
|
-
*
|
|
154
|
-
* 1. from `$baseDir/config/env`
|
|
155
|
-
* 2. from EE_SERVER_ENV
|
|
156
|
-
* 3. from NODE_ENV
|
|
157
|
-
*
|
|
158
|
-
* env | description
|
|
159
|
-
* --- | ---
|
|
160
|
-
* test | system integration testing
|
|
161
|
-
* prod | production
|
|
162
|
-
* local | local on your own computer
|
|
163
|
-
* unittest | unit test
|
|
164
|
-
*
|
|
165
|
-
* @member {String} AppInfo#env
|
|
166
|
-
* @see https://Eejs.org/zh-cn/basics/env.html
|
|
167
|
-
*/
|
|
168
|
-
env: env,
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* @member {String} AppInfo#scope
|
|
172
|
-
*/
|
|
173
|
-
scope: this.serverScope,
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* The use directory, same as `process.env.HOME`
|
|
177
|
-
* @member {String} AppInfo#HOME
|
|
178
|
-
*/
|
|
179
|
-
home: this.getHomedir(),
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* The directory whether is homeDir or appUserData depend on env.
|
|
183
|
-
* @member {String} AppInfo#root
|
|
184
|
-
*/
|
|
185
|
-
root: Ps.getRootDir(),
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* electron application data dir
|
|
189
|
-
* @member {String} AppInfo#appUserDataDir
|
|
190
|
-
*/
|
|
191
|
-
appUserDataDir: this.options.appUserData,
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* system user home dir
|
|
195
|
-
* @member {String} AppInfo#userHome
|
|
196
|
-
*/
|
|
197
|
-
userHome: this.options.userHome,
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* application version
|
|
201
|
-
* @member {String} AppInfo#appVersion
|
|
202
|
-
*/
|
|
203
|
-
appVersion: this.options.appVersion,
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* application package status
|
|
207
|
-
* @member {boolean} AppInfo#isPackaged
|
|
208
|
-
*/
|
|
209
|
-
isPackaged: this.options.isPackaged,
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* application exec file dir
|
|
213
|
-
* @member {String} AppInfo#execDir
|
|
214
|
-
*/
|
|
215
|
-
execDir: this.options.execDir
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Get {@link EeLoader#EePaths}
|
|
221
|
-
* @return {Array} framework directories
|
|
222
|
-
* @see {@link EeLoader#EePaths}
|
|
223
|
-
* @private
|
|
224
|
-
* @since 1.0.0
|
|
225
|
-
*/
|
|
226
|
-
getEePaths() {
|
|
227
|
-
// avoid require recursively
|
|
228
|
-
const EePaths = [];
|
|
229
|
-
EePaths.push(this.app[Symbol.for('ee#eePath')]);
|
|
230
|
-
|
|
231
|
-
return EePaths;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// Low Level API
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Load single file, will invoke when export is function
|
|
238
|
-
*
|
|
239
|
-
* @param {String} filepath - fullpath
|
|
240
|
-
* @param {Array} inject - pass rest arguments into the function when invoke
|
|
241
|
-
* @return {Object} exports
|
|
242
|
-
* @example
|
|
243
|
-
* ```js
|
|
244
|
-
* app.loader.loadFile(path.join(app.options.baseDir, 'config/router.js'));
|
|
245
|
-
* ```
|
|
246
|
-
* @since 1.0.0
|
|
247
|
-
*/
|
|
248
|
-
loadFile(filepath, ...inject) {
|
|
249
|
-
filepath = filepath && this.resolveModule(filepath);
|
|
250
|
-
if (!filepath) {
|
|
251
|
-
return null;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// function(arg1, args, ...) {}
|
|
255
|
-
if (inject.length === 0) inject = [ this.app ];
|
|
256
|
-
|
|
257
|
-
let ret = this.requireFile(filepath);
|
|
258
|
-
if (is.function(ret) && !is.class(ret) && !Utils.isBytecodeClass(ret)) {
|
|
259
|
-
ret = ret(...inject);
|
|
260
|
-
}
|
|
261
|
-
return ret;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* @param {String} filepath - fullpath
|
|
266
|
-
* @return {Object} exports
|
|
267
|
-
* @private
|
|
268
|
-
*/
|
|
269
|
-
requireFile(filepath) {
|
|
270
|
-
const timingKey = `Require(${this[REQUIRE_COUNT]++}) ${Utils.getResolvedFilename(filepath, this.options.baseDir)}`;
|
|
271
|
-
this.timing.start(timingKey);
|
|
272
|
-
const ret = Utils.loadFile(filepath);
|
|
273
|
-
this.timing.end(timingKey);
|
|
274
|
-
return ret;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Get all loadUnit
|
|
279
|
-
*
|
|
280
|
-
* loadUnit is a directory that can be loaded by EeLoader, it has the same structure.
|
|
281
|
-
* loadUnit has a path and a type(app, framework, plugin).
|
|
282
|
-
*
|
|
283
|
-
* The order of the loadUnits:
|
|
284
|
-
*
|
|
285
|
-
* 1. plugin
|
|
286
|
-
* 2. framework
|
|
287
|
-
* 3. app
|
|
288
|
-
*
|
|
289
|
-
* @return {Array} loadUnits
|
|
290
|
-
* @since 1.0.0
|
|
291
|
-
*/
|
|
292
|
-
getLoadUnits() {
|
|
293
|
-
if (this.dirs) {
|
|
294
|
-
return this.dirs;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
const dirs = this.dirs = [];
|
|
298
|
-
|
|
299
|
-
// framework or Ee path
|
|
300
|
-
for (const EePath of this.EePaths) {
|
|
301
|
-
dirs.push({
|
|
302
|
-
path: EePath,
|
|
303
|
-
type: 'framework',
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// application
|
|
308
|
-
dirs.push({
|
|
309
|
-
path: this.options.baseDir,
|
|
310
|
-
type: 'app',
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
debug('Loaded dirs %j', dirs);
|
|
314
|
-
return dirs;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
* Load files using {@link FileLoader}, inject to {@link Application}
|
|
319
|
-
* @param {String|Array} directory - see {@link FileLoader}
|
|
320
|
-
* @param {String} property - see {@link FileLoader}
|
|
321
|
-
* @param {Object} opt - see {@link FileLoader}
|
|
322
|
-
* @since 1.0.0
|
|
323
|
-
*/
|
|
324
|
-
loadToApp(directory, property, opt) {
|
|
325
|
-
const target = this.app[property] = {};
|
|
326
|
-
opt = Object.assign({}, {
|
|
327
|
-
directory,
|
|
328
|
-
target,
|
|
329
|
-
inject: this.app,
|
|
330
|
-
}, opt);
|
|
331
|
-
|
|
332
|
-
const timingKey = `Load "${String(property)}" to Application`;
|
|
333
|
-
this.timing.start(timingKey);
|
|
334
|
-
new FileLoader(opt).load();
|
|
335
|
-
this.timing.end(timingKey);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
/**
|
|
339
|
-
* Load files using {@link ContextLoader}
|
|
340
|
-
* @param {String|Array} directory - see {@link ContextLoader}
|
|
341
|
-
* @param {String} property - see {@link ContextLoader}
|
|
342
|
-
* @param {Object} opt - see {@link ContextLoader}
|
|
343
|
-
* @since 1.0.0
|
|
344
|
-
*/
|
|
345
|
-
loadToContext(directory, property, opt) {
|
|
346
|
-
opt = Object.assign({}, {
|
|
347
|
-
directory,
|
|
348
|
-
property,
|
|
349
|
-
inject: this.app,
|
|
350
|
-
loader: this
|
|
351
|
-
}, opt);
|
|
352
|
-
const timingKey = `Load "${String(property)}" to Context`;
|
|
353
|
-
this.timing.start(timingKey);
|
|
354
|
-
if (['addon'].includes(property)) {
|
|
355
|
-
new ContextLoader(opt).loadAddons();
|
|
356
|
-
} else {
|
|
357
|
-
new ContextLoader(opt).load();
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
this.timing.end(timingKey);
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* @member {FileLoader} EeLoader#FileLoader
|
|
365
|
-
* @since 1.0.0
|
|
366
|
-
*/
|
|
367
|
-
get FileLoader() {
|
|
368
|
-
return FileLoader;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
/**
|
|
372
|
-
* @member {ContextLoader} EeLoader#ContextLoader
|
|
373
|
-
* @since 1.0.0
|
|
374
|
-
*/
|
|
375
|
-
get ContextLoader() {
|
|
376
|
-
return ContextLoader;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
getTypeFiles(filename) {
|
|
380
|
-
const files = [ `${filename}.default` ];
|
|
381
|
-
files.push(`${filename}.${this.serverEnv}`);
|
|
382
|
-
|
|
383
|
-
return files;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
resolveModule(filepath) {
|
|
387
|
-
let fullpath;
|
|
388
|
-
try {
|
|
389
|
-
fullpath = require.resolve(filepath);
|
|
390
|
-
} catch (e) {
|
|
391
|
-
|
|
392
|
-
// 特殊后缀处理
|
|
393
|
-
if (filepath && (filepath.endsWith('.defalut') || filepath.endsWith('.prod'))) {
|
|
394
|
-
fullpath = filepath + '.jsc';
|
|
395
|
-
} else if (filepath && filepath.endsWith('.js')) {
|
|
396
|
-
fullpath = filepath + 'c';
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
if (!fs.existsSync(filepath) && !fs.existsSync(fullpath)) {
|
|
400
|
-
//this.options.logger.warn(`[ee-core] [core/lib/loader/ee_loader] resolveModule unknow filepath: ${filepath}`)
|
|
401
|
-
return undefined;
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
return fullpath;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
getPkg() {
|
|
409
|
-
const filePath = path.join(this.options.homeDir, 'package.json');
|
|
410
|
-
if (!fs.existsSync(filePath)) {
|
|
411
|
-
throw new Error(filePath + ' is not found');
|
|
412
|
-
}
|
|
413
|
-
const json = JSON.parse(fs.readFileSync(filePath));
|
|
414
|
-
|
|
415
|
-
return json;
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
/**
|
|
420
|
-
* Mixin methods to EeLoader
|
|
421
|
-
* // ES6 Multiple Inheritance
|
|
422
|
-
* https://medium.com/@leocavalcante/es6-multiple-inheritance-73a3c66d2b6b
|
|
423
|
-
*/
|
|
424
|
-
const loaders = [
|
|
425
|
-
require('./mixin/config'),
|
|
426
|
-
require('./mixin/service'),
|
|
427
|
-
require('./mixin/controller'),
|
|
428
|
-
require('./mixin/addon'),
|
|
429
|
-
];
|
|
430
|
-
|
|
431
|
-
for (const loader of loaders) {
|
|
432
|
-
Object.assign(EeLoader.prototype, loader);
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
module.exports = EeLoader;
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const assert = require('assert');
|
|
6
|
+
const is = require('is-type-of');
|
|
7
|
+
const debug = require('debug')('ee-core:EeLoader');
|
|
8
|
+
const FileLoader = require('./file_loader');
|
|
9
|
+
const ContextLoader = require('./context_loader');
|
|
10
|
+
const Utils = require('../utils');
|
|
11
|
+
const Timing = require('../utils/timing');
|
|
12
|
+
const Ps = require('../../../ps');
|
|
13
|
+
|
|
14
|
+
const REQUIRE_COUNT = Symbol('EeLoader#requireCount');
|
|
15
|
+
|
|
16
|
+
class EeLoader {
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @class
|
|
20
|
+
* @param {Object} options - options
|
|
21
|
+
* @param {String} options.baseDir - the directory of application
|
|
22
|
+
* @param {EeCore} options.app - Application instance
|
|
23
|
+
* @param {Logger} options.logger - logger
|
|
24
|
+
* @since 1.0.0
|
|
25
|
+
*/
|
|
26
|
+
constructor(options) {
|
|
27
|
+
this.options = options;
|
|
28
|
+
// assert(fs.existsSync(this.options.baseDir), `${this.options.baseDir} not exists`);
|
|
29
|
+
assert(this.options.app, 'options.app is required');
|
|
30
|
+
assert(this.options.logger, 'options.logger is required');
|
|
31
|
+
|
|
32
|
+
this.app = this.options.app;
|
|
33
|
+
this.timing = this.app.timing || new Timing();
|
|
34
|
+
this[REQUIRE_COUNT] = 0;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @member {Object} EeLoader#pkg
|
|
38
|
+
* @see {@link AppInfo#pkg}
|
|
39
|
+
* @since 1.0.0
|
|
40
|
+
*/
|
|
41
|
+
this.pkg = this.getPkg();
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Framework directories
|
|
45
|
+
*
|
|
46
|
+
* @member {Array} EeLoader#EePaths
|
|
47
|
+
* @see EeLoader#getEePaths
|
|
48
|
+
* @since 1.0.0
|
|
49
|
+
*/
|
|
50
|
+
this.EePaths = this.getEePaths();
|
|
51
|
+
debug('Loaded EePaths %j', this.EePaths);
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @member {String} EeLoader#serverEnv
|
|
55
|
+
* @see AppInfo#env
|
|
56
|
+
* @since 1.0.0
|
|
57
|
+
*/
|
|
58
|
+
this.serverEnv = this.getServerEnv();
|
|
59
|
+
debug('Loaded serverEnv %j', this.serverEnv);
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @member {AppInfo} EeLoader#appInfo
|
|
63
|
+
* @since 1.0.0
|
|
64
|
+
*/
|
|
65
|
+
this.appInfo = this.getAppInfo();
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @member {String} EeLoader#serverScope
|
|
69
|
+
* @see AppInfo#serverScope
|
|
70
|
+
*/
|
|
71
|
+
this.serverScope = options.serverScope !== undefined
|
|
72
|
+
? options.serverScope
|
|
73
|
+
: this.getServerScope();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Get {@link AppInfo#env}
|
|
78
|
+
* @return {String} env
|
|
79
|
+
* @see AppInfo#env
|
|
80
|
+
* @private
|
|
81
|
+
* @since 1.0.0
|
|
82
|
+
*/
|
|
83
|
+
getServerEnv() {
|
|
84
|
+
let serverEnv = this.options.env;
|
|
85
|
+
|
|
86
|
+
if (!serverEnv) {
|
|
87
|
+
throw new Error('[core] [lib] [loader] getServerEnv serverEnv can not be empty!');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return serverEnv;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Get {@link AppInfo#scope}
|
|
95
|
+
* @return {String} serverScope
|
|
96
|
+
* @private
|
|
97
|
+
*/
|
|
98
|
+
getServerScope() {
|
|
99
|
+
return process.env.EE_SERVER_SCOPE || '';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Get {@link AppInfo#name}
|
|
104
|
+
* @return {String} appname
|
|
105
|
+
* @private
|
|
106
|
+
* @since 1.0.0
|
|
107
|
+
*/
|
|
108
|
+
getAppname() {
|
|
109
|
+
if (this.pkg.name) {
|
|
110
|
+
debug('Loaded appname(%s) from package.json', this.pkg.name);
|
|
111
|
+
return this.pkg.name;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
throw new Error(`name is required from ${pkg}`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Get home directory
|
|
119
|
+
* @return {String} home directory
|
|
120
|
+
* @since 3.4.0
|
|
121
|
+
*/
|
|
122
|
+
getHomedir() {
|
|
123
|
+
return this.options.homeDir;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Get app info
|
|
128
|
+
* @return {AppInfo} appInfo
|
|
129
|
+
* @since 1.0.0
|
|
130
|
+
*/
|
|
131
|
+
getAppInfo() {
|
|
132
|
+
const env = this.serverEnv;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Meta information of the application
|
|
136
|
+
* @class AppInfo
|
|
137
|
+
*/
|
|
138
|
+
return {
|
|
139
|
+
/**
|
|
140
|
+
* The name of the application, retrieve from the name property in `package.json`.
|
|
141
|
+
* @member {String} AppInfo#name
|
|
142
|
+
*/
|
|
143
|
+
name: this.getAppname(),
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* The current directory, where the application code is.
|
|
147
|
+
* @member {String} AppInfo#baseDir
|
|
148
|
+
*/
|
|
149
|
+
baseDir: this.options.baseDir,
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* The environment of the application, **it's not NODE_ENV**
|
|
153
|
+
*
|
|
154
|
+
* 1. from `$baseDir/config/env`
|
|
155
|
+
* 2. from EE_SERVER_ENV
|
|
156
|
+
* 3. from NODE_ENV
|
|
157
|
+
*
|
|
158
|
+
* env | description
|
|
159
|
+
* --- | ---
|
|
160
|
+
* test | system integration testing
|
|
161
|
+
* prod | production
|
|
162
|
+
* local | local on your own computer
|
|
163
|
+
* unittest | unit test
|
|
164
|
+
*
|
|
165
|
+
* @member {String} AppInfo#env
|
|
166
|
+
* @see https://Eejs.org/zh-cn/basics/env.html
|
|
167
|
+
*/
|
|
168
|
+
env: env,
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* @member {String} AppInfo#scope
|
|
172
|
+
*/
|
|
173
|
+
scope: this.serverScope,
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* The use directory, same as `process.env.HOME`
|
|
177
|
+
* @member {String} AppInfo#HOME
|
|
178
|
+
*/
|
|
179
|
+
home: this.getHomedir(),
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* The directory whether is homeDir or appUserData depend on env.
|
|
183
|
+
* @member {String} AppInfo#root
|
|
184
|
+
*/
|
|
185
|
+
root: Ps.getRootDir(),
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* electron application data dir
|
|
189
|
+
* @member {String} AppInfo#appUserDataDir
|
|
190
|
+
*/
|
|
191
|
+
appUserDataDir: this.options.appUserData,
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* system user home dir
|
|
195
|
+
* @member {String} AppInfo#userHome
|
|
196
|
+
*/
|
|
197
|
+
userHome: this.options.userHome,
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* application version
|
|
201
|
+
* @member {String} AppInfo#appVersion
|
|
202
|
+
*/
|
|
203
|
+
appVersion: this.options.appVersion,
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* application package status
|
|
207
|
+
* @member {boolean} AppInfo#isPackaged
|
|
208
|
+
*/
|
|
209
|
+
isPackaged: this.options.isPackaged,
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* application exec file dir
|
|
213
|
+
* @member {String} AppInfo#execDir
|
|
214
|
+
*/
|
|
215
|
+
execDir: this.options.execDir
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Get {@link EeLoader#EePaths}
|
|
221
|
+
* @return {Array} framework directories
|
|
222
|
+
* @see {@link EeLoader#EePaths}
|
|
223
|
+
* @private
|
|
224
|
+
* @since 1.0.0
|
|
225
|
+
*/
|
|
226
|
+
getEePaths() {
|
|
227
|
+
// avoid require recursively
|
|
228
|
+
const EePaths = [];
|
|
229
|
+
EePaths.push(this.app[Symbol.for('ee#eePath')]);
|
|
230
|
+
|
|
231
|
+
return EePaths;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Low Level API
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Load single file, will invoke when export is function
|
|
238
|
+
*
|
|
239
|
+
* @param {String} filepath - fullpath
|
|
240
|
+
* @param {Array} inject - pass rest arguments into the function when invoke
|
|
241
|
+
* @return {Object} exports
|
|
242
|
+
* @example
|
|
243
|
+
* ```js
|
|
244
|
+
* app.loader.loadFile(path.join(app.options.baseDir, 'config/router.js'));
|
|
245
|
+
* ```
|
|
246
|
+
* @since 1.0.0
|
|
247
|
+
*/
|
|
248
|
+
loadFile(filepath, ...inject) {
|
|
249
|
+
filepath = filepath && this.resolveModule(filepath);
|
|
250
|
+
if (!filepath) {
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// function(arg1, args, ...) {}
|
|
255
|
+
if (inject.length === 0) inject = [ this.app ];
|
|
256
|
+
|
|
257
|
+
let ret = this.requireFile(filepath);
|
|
258
|
+
if (is.function(ret) && !is.class(ret) && !Utils.isBytecodeClass(ret)) {
|
|
259
|
+
ret = ret(...inject);
|
|
260
|
+
}
|
|
261
|
+
return ret;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* @param {String} filepath - fullpath
|
|
266
|
+
* @return {Object} exports
|
|
267
|
+
* @private
|
|
268
|
+
*/
|
|
269
|
+
requireFile(filepath) {
|
|
270
|
+
const timingKey = `Require(${this[REQUIRE_COUNT]++}) ${Utils.getResolvedFilename(filepath, this.options.baseDir)}`;
|
|
271
|
+
this.timing.start(timingKey);
|
|
272
|
+
const ret = Utils.loadFile(filepath);
|
|
273
|
+
this.timing.end(timingKey);
|
|
274
|
+
return ret;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Get all loadUnit
|
|
279
|
+
*
|
|
280
|
+
* loadUnit is a directory that can be loaded by EeLoader, it has the same structure.
|
|
281
|
+
* loadUnit has a path and a type(app, framework, plugin).
|
|
282
|
+
*
|
|
283
|
+
* The order of the loadUnits:
|
|
284
|
+
*
|
|
285
|
+
* 1. plugin
|
|
286
|
+
* 2. framework
|
|
287
|
+
* 3. app
|
|
288
|
+
*
|
|
289
|
+
* @return {Array} loadUnits
|
|
290
|
+
* @since 1.0.0
|
|
291
|
+
*/
|
|
292
|
+
getLoadUnits() {
|
|
293
|
+
if (this.dirs) {
|
|
294
|
+
return this.dirs;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const dirs = this.dirs = [];
|
|
298
|
+
|
|
299
|
+
// framework or Ee path
|
|
300
|
+
for (const EePath of this.EePaths) {
|
|
301
|
+
dirs.push({
|
|
302
|
+
path: EePath,
|
|
303
|
+
type: 'framework',
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// application
|
|
308
|
+
dirs.push({
|
|
309
|
+
path: this.options.baseDir,
|
|
310
|
+
type: 'app',
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
debug('Loaded dirs %j', dirs);
|
|
314
|
+
return dirs;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Load files using {@link FileLoader}, inject to {@link Application}
|
|
319
|
+
* @param {String|Array} directory - see {@link FileLoader}
|
|
320
|
+
* @param {String} property - see {@link FileLoader}
|
|
321
|
+
* @param {Object} opt - see {@link FileLoader}
|
|
322
|
+
* @since 1.0.0
|
|
323
|
+
*/
|
|
324
|
+
loadToApp(directory, property, opt) {
|
|
325
|
+
const target = this.app[property] = {};
|
|
326
|
+
opt = Object.assign({}, {
|
|
327
|
+
directory,
|
|
328
|
+
target,
|
|
329
|
+
inject: this.app,
|
|
330
|
+
}, opt);
|
|
331
|
+
|
|
332
|
+
const timingKey = `Load "${String(property)}" to Application`;
|
|
333
|
+
this.timing.start(timingKey);
|
|
334
|
+
new FileLoader(opt).load();
|
|
335
|
+
this.timing.end(timingKey);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Load files using {@link ContextLoader}
|
|
340
|
+
* @param {String|Array} directory - see {@link ContextLoader}
|
|
341
|
+
* @param {String} property - see {@link ContextLoader}
|
|
342
|
+
* @param {Object} opt - see {@link ContextLoader}
|
|
343
|
+
* @since 1.0.0
|
|
344
|
+
*/
|
|
345
|
+
loadToContext(directory, property, opt) {
|
|
346
|
+
opt = Object.assign({}, {
|
|
347
|
+
directory,
|
|
348
|
+
property,
|
|
349
|
+
inject: this.app,
|
|
350
|
+
loader: this
|
|
351
|
+
}, opt);
|
|
352
|
+
const timingKey = `Load "${String(property)}" to Context`;
|
|
353
|
+
this.timing.start(timingKey);
|
|
354
|
+
if (['addon'].includes(property)) {
|
|
355
|
+
new ContextLoader(opt).loadAddons();
|
|
356
|
+
} else {
|
|
357
|
+
new ContextLoader(opt).load();
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
this.timing.end(timingKey);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* @member {FileLoader} EeLoader#FileLoader
|
|
365
|
+
* @since 1.0.0
|
|
366
|
+
*/
|
|
367
|
+
get FileLoader() {
|
|
368
|
+
return FileLoader;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* @member {ContextLoader} EeLoader#ContextLoader
|
|
373
|
+
* @since 1.0.0
|
|
374
|
+
*/
|
|
375
|
+
get ContextLoader() {
|
|
376
|
+
return ContextLoader;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
getTypeFiles(filename) {
|
|
380
|
+
const files = [ `${filename}.default` ];
|
|
381
|
+
files.push(`${filename}.${this.serverEnv}`);
|
|
382
|
+
|
|
383
|
+
return files;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
resolveModule(filepath) {
|
|
387
|
+
let fullpath;
|
|
388
|
+
try {
|
|
389
|
+
fullpath = require.resolve(filepath);
|
|
390
|
+
} catch (e) {
|
|
391
|
+
|
|
392
|
+
// 特殊后缀处理
|
|
393
|
+
if (filepath && (filepath.endsWith('.defalut') || filepath.endsWith('.prod'))) {
|
|
394
|
+
fullpath = filepath + '.jsc';
|
|
395
|
+
} else if (filepath && filepath.endsWith('.js')) {
|
|
396
|
+
fullpath = filepath + 'c';
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (!fs.existsSync(filepath) && !fs.existsSync(fullpath)) {
|
|
400
|
+
//this.options.logger.warn(`[ee-core] [core/lib/loader/ee_loader] resolveModule unknow filepath: ${filepath}`)
|
|
401
|
+
return undefined;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
return fullpath;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
getPkg() {
|
|
409
|
+
const filePath = path.join(this.options.homeDir, 'package.json');
|
|
410
|
+
if (!fs.existsSync(filePath)) {
|
|
411
|
+
throw new Error(filePath + ' is not found');
|
|
412
|
+
}
|
|
413
|
+
const json = JSON.parse(fs.readFileSync(filePath));
|
|
414
|
+
|
|
415
|
+
return json;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Mixin methods to EeLoader
|
|
421
|
+
* // ES6 Multiple Inheritance
|
|
422
|
+
* https://medium.com/@leocavalcante/es6-multiple-inheritance-73a3c66d2b6b
|
|
423
|
+
*/
|
|
424
|
+
const loaders = [
|
|
425
|
+
require('./mixin/config'),
|
|
426
|
+
require('./mixin/service'),
|
|
427
|
+
require('./mixin/controller'),
|
|
428
|
+
require('./mixin/addon'),
|
|
429
|
+
];
|
|
430
|
+
|
|
431
|
+
for (const loader of loaders) {
|
|
432
|
+
Object.assign(EeLoader.prototype, loader);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
module.exports = EeLoader;
|