-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add require.on
function to loader. Taken example from Dojo 1.0. Related to Issue #14
#43
Changes from 12 commits
862be35
8b21694
db3e6eb
3e8ff8c
977c341
bd3a739
0234801
12616b9
4fd26db
32fd398
6d66b5d
2b2cea7
1db58ce
e8bf185
bfb9ae9
02c8def
ccfe58d
1bf81d6
95849c9
773e559
377ba0c
c600f8c
cdac75a
640119f
3fe2501
ae80fa2
ce57790
281ffd0
6c6b04c
1a77e3b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
export interface Config { | ||
baseUrl?: string; | ||
map?: ModuleMap; | ||
packages?: Package[]; | ||
paths?: { [ path: string ]: string; }; | ||
} | ||
|
||
export interface Define { | ||
(moduleId: string, dependencies: string[], factory: Factory): void; | ||
(dependencies: string[], factory: Factory): void; | ||
(factory: Factory): void; | ||
(value: any): void; | ||
} | ||
|
||
export interface Factory { | ||
(...modules: any[]): any; | ||
} | ||
|
||
export interface Has { | ||
(name: string): any; | ||
add(name: string, value: (global: Window, document?: HTMLDocument, element?: HTMLDivElement) => any, | ||
now?: boolean, force?: boolean): void; | ||
add(name: string, value: any, now?: boolean, force?: boolean): void; | ||
} | ||
|
||
export interface LoaderPlugin { | ||
load?: (resourceId: string, require: Require, load: (value?: any) => void, config?: Object) => void; | ||
normalize?: (moduleId: string, normalize: (moduleId: string) => string) => string; | ||
} | ||
|
||
export interface MapItem extends Array<any> { | ||
/* prefix */ 0: string; | ||
/* replacement */ 1: any; | ||
/* regExp */ 2: RegExp; | ||
/* length */ 3: number; | ||
} | ||
|
||
export interface MapReplacement extends MapItem { | ||
/* replacement */ 1: string; | ||
} | ||
|
||
export interface MapRoot extends Array<MapSource> { | ||
star?: MapSource; | ||
} | ||
|
||
export interface MapSource extends MapItem { | ||
/* replacement */ 1: MapReplacement[]; | ||
} | ||
|
||
export interface ModuleMap extends ModuleMapItem { | ||
[ sourceMid: string ]: ModuleMapReplacement; | ||
} | ||
|
||
export interface ModuleMapItem { | ||
[ mid: string ]: /* ModuleMapReplacement | ModuleMap */ any; | ||
} | ||
|
||
export interface ModuleMapReplacement extends ModuleMapItem { | ||
[ findMid: string ]: /* replaceMid */ string; | ||
} | ||
|
||
export interface Package { | ||
location?: string; | ||
main?: string; | ||
name?: string; | ||
} | ||
|
||
export interface PackageMap { | ||
[ packageId: string ]: Package; | ||
} | ||
|
||
export interface PathMap extends MapReplacement {} | ||
|
||
export interface Require { | ||
(config: Config, dependencies?: string[], callback?: RequireCallback): void; | ||
(dependencies: string[], callback: RequireCallback): void; | ||
<ModuleType>(moduleId: string): ModuleType; | ||
|
||
toAbsMid(moduleId: string): string; | ||
toUrl(path: string): string; | ||
} | ||
|
||
export interface RequireCallback { | ||
(...modules: any[]): void; | ||
} | ||
|
||
export type SignalType = 'error'; | ||
|
||
export interface RootRequire extends Require { | ||
has: Has; | ||
on(type: SignalType, listener: any): { remove: () => void }; | ||
config(config: Config): void; | ||
inspect?(name: string): any; | ||
nodeRequire?(id: string): any; | ||
undef(moduleId: string): void; | ||
} | ||
|
||
// TODO are we still abbreviating these properties? | ||
export interface Module extends LoaderPlugin { | ||
cjs: { | ||
exports: any; | ||
id: string; | ||
setExports: (exports: any) => void; | ||
uri: string; | ||
}; | ||
def: Factory; | ||
deps: Module[]; | ||
executed: any; // TODO: enum | ||
injected: boolean; | ||
fix?: (module: Module) => void; | ||
gc: boolean; | ||
mid: string; | ||
pack: Package; | ||
req: Require; | ||
require?: Require; // TODO: WTF? | ||
result: any; | ||
url: string; | ||
|
||
// plugin interface | ||
loadQ?: Module[]; | ||
plugin?: Module; | ||
prid: string; | ||
} | ||
|
||
export interface LoaderError extends Error { | ||
src: string; | ||
info: { module: Module, url: string }; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should |
||
} | ||
|
||
export interface ObjectMap { [ key: string ]: any; } | ||
|
||
export interface ModuleDefinitionArguments extends Array<any> { | ||
0: string[]; | ||
1: Factory; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,136 +1,31 @@ | ||
import { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You shouldn't need to import from a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't follow There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You shouldn't need to import anything. If the |
||
Config, | ||
Define, | ||
Factory, | ||
Has, | ||
MapItem, | ||
MapRoot, | ||
MapSource, | ||
ModuleMap, | ||
ModuleMapItem, | ||
Package, | ||
PackageMap, | ||
PathMap, | ||
Require, | ||
RequireCallback, | ||
SignalType, | ||
RootRequire, | ||
Module, | ||
LoaderError, | ||
ObjectMap, | ||
ModuleDefinitionArguments | ||
} from 'interfaces'; | ||
|
||
// Create ambient declarations for global node.js variables. | ||
declare var process: any; | ||
declare var require: <ModuleType>(moduleId: string) => ModuleType; | ||
declare var module: { exports: any; }; | ||
|
||
export interface Config { | ||
baseUrl?: string; | ||
map?: ModuleMap; | ||
packages?: Package[]; | ||
paths?: { [ path: string ]: string; }; | ||
} | ||
|
||
export interface Define { | ||
(moduleId: string, dependencies: string[], factory: Factory): void; | ||
(dependencies: string[], factory: Factory): void; | ||
(factory: Factory): void; | ||
(value: any): void; | ||
} | ||
|
||
export interface Factory { | ||
(...modules: any[]): any; | ||
} | ||
|
||
export interface Has { | ||
(name: string): any; | ||
add(name: string, value: (global: Window, document?: HTMLDocument, element?: HTMLDivElement) => any, | ||
now?: boolean, force?: boolean): void; | ||
add(name: string, value: any, now?: boolean, force?: boolean): void; | ||
} | ||
|
||
export interface LoaderPlugin { | ||
load?: (resourceId: string, require: Require, load: (value?: any) => void, config?: Object) => void; | ||
normalize?: (moduleId: string, normalize: (moduleId: string) => string) => string; | ||
} | ||
|
||
export interface MapItem extends Array<any> { | ||
/* prefix */ 0: string; | ||
/* replacement */ 1: any; | ||
/* regExp */ 2: RegExp; | ||
/* length */ 3: number; | ||
} | ||
|
||
export interface MapReplacement extends MapItem { | ||
/* replacement */ 1: string; | ||
} | ||
|
||
export interface MapRoot extends Array<MapSource> { | ||
star?: MapSource; | ||
} | ||
|
||
export interface MapSource extends MapItem { | ||
/* replacement */ 1: MapReplacement[]; | ||
} | ||
|
||
// TODO are we still abbreviating these properties? | ||
export interface Module extends LoaderPlugin { | ||
cjs: { | ||
exports: any; | ||
id: string; | ||
setExports: (exports: any) => void; | ||
uri: string; | ||
}; | ||
def: Factory; | ||
deps: Module[]; | ||
executed: any; // TODO: enum | ||
injected: boolean; | ||
fix?: (module: Module) => void; | ||
gc: boolean; | ||
mid: string; | ||
pack: Package; | ||
req: Require; | ||
require?: Require; // TODO: WTF? | ||
result: any; | ||
url: string; | ||
|
||
// plugin interface | ||
loadQ?: Module[]; | ||
plugin?: Module; | ||
prid: string; | ||
} | ||
|
||
export interface ModuleMap extends ModuleMapItem { | ||
[ sourceMid: string ]: ModuleMapReplacement; | ||
} | ||
|
||
export interface ModuleMapItem { | ||
[ mid: string ]: /* ModuleMapReplacement | ModuleMap */ any; | ||
} | ||
|
||
export interface ModuleMapReplacement extends ModuleMapItem { | ||
[ findMid: string ]: /* replaceMid */ string; | ||
} | ||
|
||
export interface Package { | ||
location?: string; | ||
main?: string; | ||
name?: string; | ||
} | ||
|
||
export interface PackageMap { | ||
[ packageId: string ]: Package; | ||
} | ||
|
||
export interface PathMap extends MapReplacement {} | ||
|
||
export interface Require { | ||
(config: Config, dependencies?: string[], callback?: RequireCallback): void; | ||
(dependencies: string[], callback: RequireCallback): void; | ||
<ModuleType>(moduleId: string): ModuleType; | ||
|
||
toAbsMid(moduleId: string): string; | ||
toUrl(path: string): string; | ||
} | ||
|
||
export interface RequireCallback { | ||
(...modules: any[]): void; | ||
} | ||
|
||
export interface RootRequire extends Require { | ||
has: Has; | ||
config(config: Config): void; | ||
inspect?(name: string): any; | ||
nodeRequire?(id: string): any; | ||
undef(moduleId: string): void; | ||
} | ||
|
||
interface ObjectMap { [ key: string ]: any; } | ||
|
||
interface ModuleDefinitionArguments extends Array<any> { | ||
0: string[]; | ||
1: Factory; | ||
} | ||
|
||
(function (): void { | ||
const EXECUTING: string = 'executing'; | ||
const ABORT_EXECUTION: Object = {}; | ||
|
@@ -241,6 +136,53 @@ interface ModuleDefinitionArguments extends Array<any> { | |
return has; | ||
})(); | ||
|
||
let listenerQueues = {}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Immutable, so should be Should be typed as something like this: const listenerQueues: { [queue: string]: ((error: LoaderError) => void[] } = {}; Also, you use that typing below, so maybe create an interface or type alias for it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. forgot that you can add keys to a const object. Thanks |
||
|
||
const reportModuleLoadError = function (parent: Module, module: Module, url: string): void { | ||
let parentMid = (parent ? ' (parent: ' + parent.mid + ')' : ''); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why string literal on the next line but not here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You never change the value of |
||
let message = `Failed to load module ${module.mid} from ${url}${parentMid}`; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, no re-assignment, should be |
||
let error = mix<LoaderError>(new Error(message), { | ||
src: 'dojo/loader', | ||
info: { | ||
module, | ||
url, | ||
parentMid | ||
} | ||
}); | ||
|
||
if (!emit('error', error)) { throw error; }; | ||
}; | ||
|
||
const emit = function(type: SignalType, args: {}): number | boolean { | ||
let queue: any[] = listenerQueues[type]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With the typing of listenerQueues above, there should be no reason to assert a type here. |
||
let hasListeners = queue && queue.length; | ||
|
||
if (hasListeners) { | ||
for (let listener of queue.slice(0)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't get the reason for copying the queue here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there was a comment on the previous implementation // notice we run a copy of the queue; this allows listeners to add/remove If not longer vaild i'm happy to change or add this comment in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now I get it... ;-) I would just add those comments there, so I don't ask silly questions again! |
||
listener.apply(null, Array.isArray(args) ? args : [args]); | ||
} | ||
} | ||
|
||
return hasListeners; | ||
}; | ||
|
||
const on = function(type: string, listener: (error: LoaderError) => any): { remove: () => void } { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably should be |
||
let queue = listenerQueues[type] || (listenerQueues[type] = []); | ||
|
||
queue.push(listener); | ||
|
||
return { | ||
remove() : void { | ||
for (let i = 0; i < queue.length; i++) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wouldn't there be a better way of slicing based on indexOf? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, but you would have to guard the const idx = queue.indexOf(listener);
if (idx >= 0) {
queue.splice(idx, 1);
} I don't know which is faster, maybe a JSPerf is in order? Likely immaterial, but an |
||
if (queue[i] === listener) { | ||
queue.splice(i, 1); | ||
return; | ||
} | ||
} | ||
} | ||
}; | ||
}; | ||
|
||
const requireModule: RootRequire = | ||
<RootRequire> function (configuration: any, dependencies?: any, callback?: RequireCallback): Module { | ||
if (Array.isArray(configuration) || /* require(mid) */ typeof configuration === 'string') { | ||
|
@@ -254,6 +196,7 @@ interface ModuleDefinitionArguments extends Array<any> { | |
return contextRequire(dependencies, callback); | ||
}; | ||
requireModule.has = has; | ||
requireModule.on = on; | ||
|
||
has.add('host-browser', typeof document !== 'undefined' && typeof location !== 'undefined'); | ||
has.add('host-node', typeof process === 'object' && process.versions && process.versions.node); | ||
|
@@ -364,11 +307,11 @@ interface ModuleDefinitionArguments extends Array<any> { | |
array && array.forEach(callback); | ||
} | ||
|
||
function mix(target: {}, source: {}): {} { | ||
function mix<T extends {}>(target: {}, source: {}): T { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we call this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. happy to do in a follow up PR but isn't that outside the scope of this issue? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. Sorry, I got into a stream of consciousness mode. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed, we should assign and offload to native assign actually, depending on how easy it is. We should open an issue. |
||
for (let key in source) { | ||
(<ObjectMap> target)[key] = (<ObjectMap> source)[key]; | ||
} | ||
return target; | ||
return <T> target; | ||
} | ||
|
||
function consumePendingCacheInsert(referenceModule?: Module): void { | ||
|
@@ -905,8 +848,7 @@ interface ModuleDefinitionArguments extends Array<any> { | |
let result = loadNodeModule(module.mid, parent); | ||
|
||
if (!result) { | ||
let parentMid = (parent ? ' (parent: ' + parent.mid + ')' : ''); | ||
throw new Error('Failed to load module ' + module.mid + ' from ' + url + parentMid); | ||
reportModuleLoadError(parent, module, url); | ||
} | ||
|
||
return result; | ||
|
@@ -951,8 +893,7 @@ interface ModuleDefinitionArguments extends Array<any> { | |
has('loader-ie9-compat') ? callback(node) : callback(); | ||
} | ||
else { | ||
let parentMid = (parent ? ' (parent: ' + parent.mid + ')' : ''); | ||
throw new Error('Failed to load module ' + module.mid + ' from ' + url + parentMid); | ||
reportModuleLoadError(parent, module, url); | ||
} | ||
}; | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to our Style Guide, module exports should be ordered alphabetically.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
meant to do that, will do now