Skip to content

Commit 2275a51

Browse files
Merge pull request #885 from bigopon/aurelia-static
feat(config): accepts classes beside module id string
2 parents cbaaecd + d445289 commit 2275a51

3 files changed

Lines changed: 326 additions & 74 deletions

File tree

config.js

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
11
System.config({
22
defaultJSExtensions: true,
3+
transpiler: "babel",
4+
babelOptions: {
5+
"optional": [
6+
"runtime",
7+
"optimisation.modules.system"
8+
]
9+
},
310
paths: {
411
"github:*": "jspm_packages/github/*",
512
"aurelia-framework/*": "dist/*",
613
"npm:*": "jspm_packages/npm/*"
714
},
815

916
map: {
10-
"aurelia-binding": "npm:aurelia-binding@1.0.0",
11-
"aurelia-dependency-injection": "npm:aurelia-dependency-injection@1.0.0",
17+
"aurelia-binding": "npm:aurelia-binding@1.7.1",
18+
"aurelia-dependency-injection": "npm:aurelia-dependency-injection@1.3.2",
1219
"aurelia-loader": "npm:aurelia-loader@1.0.0",
13-
"aurelia-logging": "npm:aurelia-logging@1.0.0",
14-
"aurelia-metadata": "npm:aurelia-metadata@1.0.0",
15-
"aurelia-pal": "npm:aurelia-pal@1.0.0",
20+
"aurelia-logging": "npm:aurelia-logging@1.4.0",
21+
"aurelia-metadata": "npm:aurelia-metadata@1.0.3",
22+
"aurelia-pal": "npm:aurelia-pal@1.8.0",
1623
"aurelia-pal-browser": "npm:aurelia-pal-browser@1.0.0",
17-
"aurelia-path": "npm:aurelia-path@1.0.0",
18-
"aurelia-task-queue": "npm:aurelia-task-queue@1.0.0",
19-
"aurelia-templating": "npm:aurelia-templating@1.0.0",
24+
"aurelia-path": "npm:aurelia-path@1.1.1",
25+
"aurelia-task-queue": "npm:aurelia-task-queue@1.3.0",
26+
"aurelia-templating": "npm:aurelia-templating@1.7.0",
2027
"babel": "npm:babel-core@5.8.38",
2128
"babel-runtime": "npm:babel-runtime@5.8.38",
2229
"core-js": "npm:core-js@2.4.1",
@@ -44,38 +51,38 @@ System.config({
4451
"process": "github:jspm/nodelibs-process@0.1.2",
4552
"util": "npm:util@0.10.3"
4653
},
47-
"npm:aurelia-binding@1.0.0": {
48-
"aurelia-logging": "npm:aurelia-logging@1.0.0",
49-
"aurelia-metadata": "npm:aurelia-metadata@1.0.0",
50-
"aurelia-pal": "npm:aurelia-pal@1.0.0",
51-
"aurelia-task-queue": "npm:aurelia-task-queue@1.0.0"
54+
"npm:aurelia-binding@1.7.1": {
55+
"aurelia-logging": "npm:aurelia-logging@1.4.0",
56+
"aurelia-metadata": "npm:aurelia-metadata@1.0.3",
57+
"aurelia-pal": "npm:aurelia-pal@1.8.0",
58+
"aurelia-task-queue": "npm:aurelia-task-queue@1.3.0"
5259
},
53-
"npm:aurelia-dependency-injection@1.0.0": {
54-
"aurelia-metadata": "npm:aurelia-metadata@1.0.0",
55-
"aurelia-pal": "npm:aurelia-pal@1.0.0"
60+
"npm:aurelia-dependency-injection@1.3.2": {
61+
"aurelia-metadata": "npm:aurelia-metadata@1.0.3",
62+
"aurelia-pal": "npm:aurelia-pal@1.8.0"
5663
},
5764
"npm:aurelia-loader@1.0.0": {
58-
"aurelia-metadata": "npm:aurelia-metadata@1.0.0",
59-
"aurelia-path": "npm:aurelia-path@1.0.0"
65+
"aurelia-metadata": "npm:aurelia-metadata@1.0.3",
66+
"aurelia-path": "npm:aurelia-path@1.1.1"
6067
},
61-
"npm:aurelia-metadata@1.0.0": {
62-
"aurelia-pal": "npm:aurelia-pal@1.0.0"
68+
"npm:aurelia-metadata@1.0.3": {
69+
"aurelia-pal": "npm:aurelia-pal@1.8.0"
6370
},
6471
"npm:aurelia-pal-browser@1.0.0": {
65-
"aurelia-pal": "npm:aurelia-pal@1.0.0"
72+
"aurelia-pal": "npm:aurelia-pal@1.8.0"
6673
},
67-
"npm:aurelia-task-queue@1.0.0": {
68-
"aurelia-pal": "npm:aurelia-pal@1.0.0"
74+
"npm:aurelia-task-queue@1.3.0": {
75+
"aurelia-pal": "npm:aurelia-pal@1.8.0"
6976
},
70-
"npm:aurelia-templating@1.0.0": {
71-
"aurelia-binding": "npm:aurelia-binding@1.0.0",
72-
"aurelia-dependency-injection": "npm:aurelia-dependency-injection@1.0.0",
77+
"npm:aurelia-templating@1.7.0": {
78+
"aurelia-binding": "npm:aurelia-binding@1.7.1",
79+
"aurelia-dependency-injection": "npm:aurelia-dependency-injection@1.3.2",
7380
"aurelia-loader": "npm:aurelia-loader@1.0.0",
74-
"aurelia-logging": "npm:aurelia-logging@1.0.0",
75-
"aurelia-metadata": "npm:aurelia-metadata@1.0.0",
76-
"aurelia-pal": "npm:aurelia-pal@1.0.0",
77-
"aurelia-path": "npm:aurelia-path@1.0.0",
78-
"aurelia-task-queue": "npm:aurelia-task-queue@1.0.0"
81+
"aurelia-logging": "npm:aurelia-logging@1.4.0",
82+
"aurelia-metadata": "npm:aurelia-metadata@1.0.3",
83+
"aurelia-pal": "npm:aurelia-pal@1.8.0",
84+
"aurelia-path": "npm:aurelia-path@1.1.1",
85+
"aurelia-task-queue": "npm:aurelia-task-queue@1.3.0"
7986
},
8087
"npm:babel-runtime@5.8.38": {
8188
"process": "github:jspm/nodelibs-process@0.1.2"

src/framework-configuration.js

Lines changed: 122 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import * as TheLogManager from 'aurelia-logging';
2-
import {ViewEngine} from 'aurelia-templating';
2+
import {ViewEngine, HtmlBehaviorResource} from 'aurelia-templating';
33
import {join} from 'aurelia-path';
44
import {Container} from 'aurelia-dependency-injection';
55

66
const logger = TheLogManager.getLogger('aurelia');
77
const extPattern = /\.[^/.]+$/;
88

9-
function runTasks(config, tasks) {
9+
function runTasks(config: FrameworkConfiguration, tasks) {
1010
let current;
1111
let next = () => {
1212
current = tasks.shift();
@@ -20,35 +20,62 @@ function runTasks(config, tasks) {
2020
return next();
2121
}
2222

23-
function loadPlugin(config, loader, info) {
23+
interface FrameworkPluginInfo {
24+
moduleId?: string;
25+
resourcesRelativeTo?: string[];
26+
configure?: (config: FrameworkConfiguration, pluginConfig?: any) => any;
27+
config?: any;
28+
}
29+
30+
function loadPlugin(fwConfig: FrameworkConfiguration, loader: Loader, info: FrameworkPluginInfo) {
2431
logger.debug(`Loading plugin ${info.moduleId}.`);
25-
config.resourcesRelativeTo = info.resourcesRelativeTo;
32+
if (typeof info.moduleId === 'string') {
33+
fwConfig.resourcesRelativeTo = info.resourcesRelativeTo;
2634

27-
let id = info.moduleId; // General plugins installed/configured by the end user.
35+
let id = info.moduleId; // General plugins installed/configured by the end user.
2836

29-
if (info.resourcesRelativeTo.length > 1 ) { // In case of bootstrapper installed plugins like `aurelia-templating-resources` or `aurelia-history-browser`.
30-
return loader.normalize(info.moduleId, info.resourcesRelativeTo[1])
31-
.then(normalizedId => _loadPlugin(normalizedId));
32-
}
37+
if (info.resourcesRelativeTo.length > 1 ) { // In case of bootstrapper installed plugins like `aurelia-templating-resources` or `aurelia-history-browser`.
38+
return loader.normalize(info.moduleId, info.resourcesRelativeTo[1])
39+
.then(normalizedId => _loadPlugin(normalizedId));
40+
}
3341

34-
return _loadPlugin(id);
42+
return _loadPlugin(id);
43+
} else if (typeof info.configure === 'function') {
44+
if (fwConfig.configuredPlugins.indexOf(info.configure) !== -1) {
45+
return Promise.resolve();
46+
}
47+
fwConfig.configuredPlugins.push(info.configure);
48+
// use info.config || {} to keep behavior consistent with loading from string
49+
return Promise.resolve(info.configure.call(null, fwConfig, info.config || {}));
50+
}
51+
throw new Error(invalidConfigMsg(info.moduleId || info.configure, 'plugin'));
3552

3653
function _loadPlugin(moduleId) {
3754
return loader.loadModule(moduleId).then(m => { // eslint-disable-line consistent-return
3855
if ('configure' in m) {
39-
return Promise.resolve(m.configure(config, info.config || {})).then(() => {
40-
config.resourcesRelativeTo = null;
56+
if (fwConfig.configuredPlugins.indexOf(m.configure) !== -1) {
57+
return Promise.resolve();
58+
}
59+
return Promise.resolve(m.configure(fwConfig, info.config || {})).then(() => {
60+
fwConfig.configuredPlugins.push(m.configure);
61+
fwConfig.resourcesRelativeTo = null;
4162
logger.debug(`Configured plugin ${info.moduleId}.`);
4263
});
4364
}
4465

45-
config.resourcesRelativeTo = null;
66+
fwConfig.resourcesRelativeTo = null;
4667
logger.debug(`Loaded plugin ${info.moduleId}.`);
4768
});
4869
}
4970
}
5071

5172
function loadResources(aurelia, resourcesToLoad, appResources) {
73+
// if devs want to go all in static, and remove loader
74+
// the code after this fucntion shouldn't run
75+
// add a check to make sure it only runs when there is something to do so
76+
if (Object.keys(resourcesToLoad).length === 0) {
77+
return Promise.resolve();
78+
}
5279
let viewEngine = aurelia.container.get(ViewEngine);
5380

5481
return Promise.all(Object.keys(resourcesToLoad).map(n => _normalize(resourcesToLoad[n])))
@@ -98,19 +125,29 @@ function loadResources(aurelia, resourcesToLoad, appResources) {
98125
}
99126
}
100127

101-
function getExt(name) { // eslint-disable-line consistent-return
128+
function getExt(name: string) { // eslint-disable-line consistent-return
102129
let match = name.match(extPattern);
103130
if (match && match.length > 0) {
104131
return (match[0].split('.'))[1];
105132
}
106133
}
107134

108-
function assertProcessed(plugins) {
135+
function loadBehaviors(config: FrameworkConfiguration) {
136+
return Promise.all(config.behaviorsToLoad.map(m => m.load(config.container, m.target))).then(() => {
137+
config.behaviorsToLoad = null;
138+
});
139+
}
140+
141+
function assertProcessed(plugins: FrameworkConfiguration) {
109142
if (plugins.processed) {
110143
throw new Error('This config instance has already been applied. To load more plugins or global resources, create a new FrameworkConfiguration instance.');
111144
}
112145
}
113146

147+
function invalidConfigMsg(cfg: any, type: string) {
148+
return `Invalid ${type} [${cfg}], ${type} must be specified as functions or relative module IDs.`;
149+
}
150+
114151
/**
115152
* Manages configuring the aurelia framework instance.
116153
*/
@@ -132,10 +169,24 @@ export class FrameworkConfiguration {
132169
constructor(aurelia: Aurelia) {
133170
this.aurelia = aurelia;
134171
this.container = aurelia.container;
172+
/**
173+
* Plugin / feature loading instruction
174+
* @type {FrameworkPluginInfo[]}
175+
*/
135176
this.info = [];
136177
this.processed = false;
137178
this.preTasks = [];
138179
this.postTasks = [];
180+
/**
181+
* Custom element's metadata queue for loading view factory
182+
* @type {HtmlBehaviorResource[]}
183+
*/
184+
this.behaviorsToLoad = [];
185+
/**
186+
* Plugin configure functions temporary cache for avoid duplicate calls
187+
* @type {Function[]}
188+
*/
189+
this.configuredPlugins = [];
139190
this.resourcesToLoad = {};
140191
this.preTask(() => aurelia.loader.normalize('aurelia-bootstrapper').then(name => this.bootstrapperName = name));
141192
this.postTask(() => loadResources(aurelia, this.resourcesToLoad, aurelia.resources));
@@ -202,19 +253,31 @@ export class FrameworkConfiguration {
202253
* @param config The configuration for the specified plugin.
203254
* @return Returns the current FrameworkConfiguration instance.
204255
*/
205-
feature(plugin: string, config?: any = {}): FrameworkConfiguration {
206-
let hasIndex = /\/index$/i.test(plugin);
207-
let moduleId = hasIndex || getExt(plugin) ? plugin : plugin + '/index';
208-
let root = hasIndex ? plugin.substr(0, plugin.length - 6) : plugin;
209-
return this.plugin({ moduleId, resourcesRelativeTo: [root, ''], config });
256+
feature(plugin: string | ((config: FrameworkConfiguration, pluginConfig?: any) => any), config?: any = {}): FrameworkConfiguration {
257+
switch (typeof plugin) {
258+
case 'string':
259+
let hasIndex = /\/index$/i.test(plugin);
260+
let moduleId = hasIndex || getExt(plugin) ? plugin : plugin + '/index';
261+
let root = hasIndex ? plugin.substr(0, plugin.length - 6) : plugin;
262+
this.info.push({ moduleId, resourcesRelativeTo: [root, ''], config });
263+
break;
264+
// return this.plugin({ moduleId, resourcesRelativeTo: [root, ''], config });
265+
case 'function':
266+
this.info.push({ configure: plugin, config: config || {} });
267+
break;
268+
default:
269+
throw new Error(invalidConfigMsg(plugin, 'feature'));
270+
}
271+
return this;
272+
// return this.plugin(plugin, config);
210273
}
211274
212275
/**
213276
* Adds globally available view resources to be imported into the Aurelia framework.
214277
* @param resources The relative module id to the resource. (Relative to the plugin's installer.)
215278
* @return Returns the current FrameworkConfiguration instance.
216279
*/
217-
globalResources(resources: string|string[]): FrameworkConfiguration {
280+
globalResources(resources: string | Function | Array<string | Function>): FrameworkConfiguration {
218281
assertProcessed(this);
219282
220283
let toAdd = Array.isArray(resources) ? resources : arguments;
@@ -223,19 +286,29 @@ export class FrameworkConfiguration {
223286
224287
for (let i = 0, ii = toAdd.length; i < ii; ++i) {
225288
resource = toAdd[i];
226-
if (typeof resource !== 'string') {
227-
throw new Error(`Invalid resource path [${resource}]. Resources must be specified as relative module IDs.`);
228-
}
229-
230-
let parent = resourcesRelativeTo[0];
231-
let grandParent = resourcesRelativeTo[1];
232-
let name = resource;
289+
switch (typeof resource) {
290+
case 'string':
291+
let parent = resourcesRelativeTo[0];
292+
let grandParent = resourcesRelativeTo[1];
293+
let name = resource;
294+
295+
if ((resource.startsWith('./') || resource.startsWith('../')) && parent !== '') {
296+
name = join(parent, resource);
297+
}
233298
234-
if ((resource.startsWith('./') || resource.startsWith('../')) && parent !== '') {
235-
name = join(parent, resource);
299+
this.resourcesToLoad[name] = { moduleId: name, relativeTo: grandParent };
300+
break;
301+
case 'function':
302+
let meta = this.aurelia.resources.autoRegister(this.container, resource);
303+
if (meta instanceof HtmlBehaviorResource && meta.elementName !== null) {
304+
if (this.behaviorsToLoad.push(meta) === 1) {
305+
this.postTask(() => loadBehaviors(this));
306+
}
307+
}
308+
break;
309+
default:
310+
throw new Error(invalidConfigMsg(resource, 'resource'));
236311
}
237-
238-
this.resourcesToLoad[name] = { moduleId: name, relativeTo: grandParent };
239312
}
240313
241314
return this;
@@ -256,17 +329,27 @@ export class FrameworkConfiguration {
256329
/**
257330
* Configures an external, 3rd party plugin before Aurelia starts.
258331
* @param plugin The ID of the 3rd party plugin to configure.
259-
* @param config The configuration for the specified plugin.
332+
* @param pluginConfig The configuration for the specified plugin.
260333
* @return Returns the current FrameworkConfiguration instance.
261334
*/
262-
plugin(plugin: string, config?: any): FrameworkConfiguration {
335+
plugin(
336+
plugin: string | ((frameworkConfig: FrameworkConfiguration) => any) | FrameworkPluginInfo,
337+
pluginConfig?: any
338+
): FrameworkConfiguration {
263339
assertProcessed(this);
264340
265-
if (typeof (plugin) === 'string') {
266-
return this.plugin({ moduleId: plugin, resourcesRelativeTo: [plugin, ''], config: config || {} });
341+
let info: FrameworkPluginInfo;
342+
switch (typeof plugin) {
343+
case 'string':
344+
info = { moduleId: plugin, resourcesRelativeTo: [plugin, ''], config: pluginConfig || {} };
345+
break;
346+
case 'function':
347+
info = { configure: plugin, config: pluginConfig || {} };
348+
break;
349+
default:
350+
throw new Error(invalidConfigMsg(plugin, 'plugin'));
267351
}
268-
269-
this.info.push(plugin);
352+
this.info.push(info);
270353
return this;
271354
}
272355
@@ -393,6 +476,7 @@ export class FrameworkConfiguration {
393476
}
394477

395478
this.processed = true;
479+
this.configuredPlugins = null;
396480
return Promise.resolve();
397481
};
398482

0 commit comments

Comments
 (0)