Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e30d33a

Browse files
committedAug 3, 2016
feat: add loader.loadToContext, it can load files that bind ctx
move proxy/service to mixin
1 parent 0b6a424 commit e30d33a

File tree

11 files changed

+174
-121
lines changed

11 files changed

+174
-121
lines changed
 

‎lib/context_loader.js

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
'use strict';
2+
3+
const assert = require('assert');
4+
const is = require('is-type-of');
5+
const Loader = require('./Loader');
6+
const classLoader = Symbol('classLoader');
7+
const END = Loader.END;
8+
9+
class ClassLoader {
10+
11+
constructor(options) {
12+
assert(options.ctx, 'options.ctx is required');
13+
const properties = options.properties;
14+
this._cache = new Map();
15+
this._ctx = options.ctx;
16+
17+
for (const property in properties) {
18+
this.defineProperty(property, properties[property]);
19+
}
20+
}
21+
22+
defineProperty(property, values) {
23+
Object.defineProperty(this, property, {
24+
get() {
25+
if (!this._cache.has(property)) {
26+
this._cache.set(property, getInstance(values, this._ctx));
27+
}
28+
return this._cache.get(property);
29+
},
30+
});
31+
}
32+
}
33+
34+
class ContextLoader extends Loader {
35+
36+
constructor(options) {
37+
assert(options.field, 'options.field is required');
38+
assert(options.inject, 'options.inject is required');
39+
const target = options.target = {};
40+
if (options.fieldClass) {
41+
options.inject[options.fieldClass] = target;
42+
}
43+
super(options);
44+
45+
const app = this.options.inject;
46+
47+
Object.defineProperty(app.context, options.field, {
48+
get() {
49+
if (!this[classLoader]) {
50+
this[classLoader] = getInstance(target, this);
51+
}
52+
return this[classLoader];
53+
},
54+
});
55+
}
56+
}
57+
58+
module.exports = ContextLoader;
59+
60+
61+
function getInstance(values, ctx) {
62+
const Class = values[END] ? values : null;
63+
let instance;
64+
if (Class) {
65+
if (is.class(Class)) {
66+
instance = new Class(ctx);
67+
} else {
68+
instance = Class;
69+
}
70+
} else {
71+
instance = new ClassLoader({ ctx, properties: values });
72+
}
73+
return instance;
74+
}

‎lib/egg_loader.js

+12-6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const assert = require('assert');
66
const isFunction = require('is-type-of').function;
77
const debug = require('debug')('egg-loader');
88
const Loader = require('./loader');
9+
const ContextLoader = require('./context_loader');
910
const loadFile = require('./utils').loadFile;
1011
const getHomedir = require('./utils').getHomedir;
1112
const Emitter = require('events').EventEmitter;
@@ -235,7 +236,8 @@ class EggLoader {
235236
return dirs;
236237
}
237238

238-
loadTo(directory, target, opt) {
239+
loadToApp(directory, field, opt) {
240+
const target = this.app[field] = {};
239241
opt = Object.assign({}, {
240242
directory,
241243
target,
@@ -244,9 +246,13 @@ class EggLoader {
244246
new Loader(opt).load();
245247
}
246248

247-
loadToApp(directory, field, opt) {
248-
const target = this.app[field] = {};
249-
this.loadTo(directory, target, opt);
249+
loadToContext(directory, field, opt) {
250+
opt = Object.assign({}, {
251+
directory,
252+
field,
253+
inject: this.app,
254+
}, opt);
255+
new ContextLoader(opt).load();
250256
}
251257

252258
}
@@ -261,8 +267,8 @@ const loaders = [
261267
require('./mixin/config'),
262268
require('./mixin/extend'),
263269
require('./mixin/custom'),
264-
require('./proxy_loader'),
265-
require('./service_loader'),
270+
require('./mixin/proxy'),
271+
require('./mixin/service'),
266272
require('./mixin/middleware'),
267273
require('./mixin/controller'),
268274
];

‎lib/loader.js

+22-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const globby = require('globby');
88
const is = require('is-type-of');
99
const loadFile = require('./utils').loadFile;
1010
const FULLPATH = Symbol('EGG_LOADER_ITEM_FULLPATH');
11+
const END = Symbol('EGG_LOADER_ITEM_END');
1112

1213
const defaults = {
1314
directory: null,
@@ -33,6 +34,8 @@ class Loader {
3334
const target = this.options.target;
3435
for (const item of items) {
3536
debug('loading item %j', item);
37+
// item { properties: [ 'a', 'b', 'c'], exports }
38+
// => target.a.b.c = exports
3639
item.properties.reduce((target, property, index) => {
3740
let obj;
3841
const properties = item.properties.slice(0, index + 1).join('.');
@@ -41,7 +44,10 @@ class Loader {
4144
if (!this.options.override) throw new Error(`can't overwrite property '${properties}' from ${target[property][FULLPATH]} by ${item.fullpath}`);
4245
}
4346
obj = item.exports;
44-
if (obj) obj[FULLPATH] = item.fullpath;
47+
if (obj) {
48+
obj[FULLPATH] = item.fullpath;
49+
obj[END] = true;
50+
}
4551
} else {
4652
obj = target[property] || {};
4753
}
@@ -87,6 +93,7 @@ class Loader {
8793
}
8894

8995
module.exports = Loader;
96+
module.exports.END = END;
9097

9198
// a/b/c.js => ['a', 'b', 'c']
9299
function getProperties(filepath, lowercaseFirst) {
@@ -105,23 +112,37 @@ function getProperties(filepath, lowercaseFirst) {
105112
});
106113
}
107114

115+
// Get exports from filepath
116+
// If exports is null/undefined, it will be ignored
108117
function getExports(fullpath, initializer, isCall, inject) {
109118
let exports = loadFile(fullpath);
110119

120+
// process exports as you like
111121
if (initializer) {
112122
exports = initializer(exports);
113123
}
114124

125+
// return exports when it's a class or generator
126+
//
127+
// module.exports = class Service {};
128+
// or
129+
// module.exports = function*() {}
115130
if (is.class(exports) || is.generatorFunction(exports)) {
116131
return exports;
117132
}
118133

134+
// return exports after call when it's a function
135+
//
136+
// module.exports = function(app) {
137+
// return {};
138+
// }
119139
if (isCall && is.function(exports)) {
120140
exports = exports(inject);
121141
if (exports != null) {
122142
return exports;
123143
}
124144
}
125145

146+
// return exports what is
126147
return exports;
127148
}

‎lib/mixin/proxy.js

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
'use strict';
2+
3+
const join = require('path').join;
4+
5+
module.exports = {
6+
7+
/**
8+
* 加载 app/proxy 目录下的文件
9+
*
10+
* 1. 加载应用 app/proxy
11+
* 2. 加载插件 app/proxy
12+
*
13+
* @method EggLoader#loadProxy
14+
* @param {Object} opt - loading 参数
15+
*/
16+
loadProxy(opt) {
17+
const app = this.app;
18+
const arr = this.getLoadUnits().map(unit => join(unit.path, 'app/proxy'));
19+
20+
opt = Object.assign({
21+
call: true,
22+
lowercaseFirst: true,
23+
fieldClass: 'proxyClasses',
24+
}, opt);
25+
this.loadToContext(arr, 'proxy', opt);
26+
27+
app.coreLogger.info('[egg:loader] Proxy loaded from %j', arr);
28+
},
29+
30+
};

‎lib/mixin/service.js

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
'use strict';
2+
3+
const path = require('path');
4+
5+
module.exports = {
6+
7+
/**
8+
* 加载 app/service 目录下的文件
9+
*
10+
* 1. 加载应用 app/service
11+
* 2. 加载插件 app/service
12+
*
13+
* @method EggLoader#loadService
14+
* @param {Object} opt - loading 参数
15+
*/
16+
loadService(opt) {
17+
const servicePaths = this.getLoadUnits().map(unit => {
18+
return path.join(unit.path, 'app/service');
19+
});
20+
21+
// 载入到 app.serviceClasses
22+
opt = Object.assign({
23+
call: true,
24+
lowercaseFirst: true,
25+
fieldClass: 'serviceClasses',
26+
}, opt);
27+
this.loadToContext(servicePaths, 'service', opt);
28+
},
29+
30+
};

‎lib/proxy_loader.js

-51
This file was deleted.

‎lib/service_loader.js

-58
This file was deleted.

‎test/fixtures/subdir-proxy/app/router.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@ module.exports = function (app) {
1313
oldStyle: yield this.proxy.oldStyle.url(this),
1414
};
1515
});
16-
}
16+
}

‎test/fixtures/subdir-services/app/controller/home.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ module.exports = function* () {
55
bar1: yield this.service.foo.bar.get('bar1name'),
66
bar2: yield this.service.foo.subdir.bar.get('bar2name'),
77
'foo.subdir2.sub2': yield this.service.foo.subdir2.sub2.get('bar3name'),
8-
subdir11bar: !!this.service.foo.subdir1,
8+
subdir11bar: yield this.service.foo.subdir1.subdir11.bar.get(),
99
ok: yield this.service.ok.get(),
1010
cmd: yield this.service.certifyPersonal.mobileHi.doCertify.exec('hihi'),
1111
serviceIsSame: this.service.certifyPersonal === this.service.certifyPersonal,

‎test/load_proxy.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ describe('test/load_proxy.test.js', function() {
5858
name: 'bar3name',
5959
bar: 'bar3',
6060
},
61-
subdir11bar: false,
61+
subdir11bar: true,
6262
ok: {
6363
ok: true,
6464
},

‎test/load_service.test.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ describe('test/load_service.test.js', function() {
1010

1111
it('should load from application and plugin', function(done) {
1212
const app = utils.createApp('plugin');
13-
console.log(app.serviceClasses);
1413
should.exists(app.serviceClasses.foo);
1514
should.exists(app.serviceClasses.foo2);
1615
should.not.exists(app.serviceClasses.bar1);
@@ -79,7 +78,9 @@ describe('test/load_service.test.js', function() {
7978
name: 'bar3name',
8079
bar: 'bar3',
8180
},
82-
subdir11bar: false,
81+
subdir11bar: {
82+
bar: 'bar111',
83+
},
8384
ok: {
8485
ok: true,
8586
},

0 commit comments

Comments
 (0)
Please sign in to comment.