dumber-module-loader
v1.2.5
Published
A modern module loader (loose AMD implementation), designed to work with dumber.
Downloads
300
Readme
dumber-module-loader
A modern AMD module loader, used by dumber bundler internally.
dumber-module-loader is a loose AMD implementation, does not strictly follow the AMD spec.
For users of dumber bundler, you only need to know that the internal module loader is an AMD loader, similar to requirejs. The good old AMD gives dumber bundler intuitive code splitting, and flexible runtime composition.
Our violation on AMD spec:
- AMD spec doesn't allow defining module id starting with '..',
define('../package.json', ...)
. We allow it. This is to support dependency'../package.json'
that could be required bysrc/app.js
. We say module id'../package.json'
is above surface. - Only supports plugin's
load()
function, doesn't supportnormalize()
function, doesn't supportload.fromText()
function (not in spec, but some requirejs plugins use it). Note there is built-in support of traditionaltext!
andjson!
plugins out of the box. - Special RegExp support for mass require, mainly for test runner.
requirejs([/\.spec$/], function() {
});
Our touch on AMD:
Mimic Node.js module resolving behaviour so dumber bundler can do less work.
require('foo/bar')
could load modulefoo/bar
,foo/bar.js
,foo/bar.json
,foo/bar/index.js
, orfoo/bar/index.json
.- if there is a
package.json
file in folderfoo/bar/
, it can load filefoo/bar/resolved/main.js
, dumber will build an aliasfoo/bar/index
tofoo/bar/resolved/main.js
.
Two module spaces:
user
(default, for local source file) andpackage
(for npm packages and local packages).- module in
user
space can acquireuser
orpackage
modules. - module in
package
space can only acquirepackage
modules. - both
user
andpackage
space can contain module with the same id. This is designed to avoid localsrc/util.js
over-shadowing Node.js core moduleutil
.
- module in
Full support of Node.js circular dependencies (for packages like yallist, note yallist 3.0.3 has removed circular dependency).
Besides normal plugin, we support ext plugin which targets ext name.
- by default, dumber-module-loader ships with ext plugins for json/html/svg/css/wasm (do not yet support wasm importObjects).
- all ext plugins should resolve the underneath content using one of our three predefined plugins:
text!
,json!
, andraw!
. text!some.fie
will resolve to the text content of the file, at runtime it uses fetch APIreponse.text()
to get the content.json!some.fie
will resolve to the parsed json, at runtime it uses fetch APIreponse.json()
to parse the content.raw!some.fie
will resolve to fetch APIreponse
, note the result is a promise, not final value.- for instance, our default html support is implemented as
define('ext:html', {load: function(name, req, load) { req(['text!' + name], text => load(text)); }});
- note, our default css support is just returning the text content, same as our html support. By default, it doesn't inject style sheet to html head. However dumber bundler by default overrides the default
'ext:css'
plugin to support style sheet injection.
Difference from requirejs:
- No multi-contexts.
- Only supports config on
baseUrl
,paths
, andbundles
. data-main
attribute on script tag doesn't affectbaseUrl
,data-main
is purely a module id.paths
support is simplified.- supports absolute path like
"foo": "/foo"
- supports normal
"foo": "common/foo"
, resolvefoo/bar/lo
tocommon/foo/bar/lo
. Note we treatcommon/foo/bar/lo
as the real module id, it could result to an existing known module, otherwise go through remote fetch. - doesn't support
"foo": ["common/foo", "shared/foo"]
the fail-over array. - relative module resolution is simplified. This is a breaking change. We changed the behaviour because we think our behaviour is less surprising.
- supports absolute path like
define('common/foo', ['./bar'], function (bar) { /* ... */ });
requirejs.config({paths: {'foo': 'common/foo'}});
requirejs(['foo'], function (foo) {
// requirejs resolves './bar' to 'bar',
// we resolves './bar' to 'common/bar'.
});
- No automatic commonjs wrapping for runtime fetched module. For any module loaded remotely at runtime, we only support AMD anonymous module format, unless you supply a plugin to deal with the raw content.
bundles
config is different, it needs two arrays,'user'
and'package'
for the two module spaces.- for example,
{"a-bundle": {"user": ['a', 'b'], "package": ["lodash", "jquery"]}}
. - if no module in
package
space, it can be written in requirejs compatible format,{"a-bundle": ['a', 'b']}
.
- for example,
require([...], callback, errback)
doesn't support optional config, errback only gets one error object.- We only support browser/Worker/Node.js environments, didn't test on Rhino or any other environments.
- Note there is no support of
package
ormap
config. - There is no support of shim. Shim is all done by dumber bundler.
API
There globals, define
, requirejs
(same as require
).
define(id? :string, deps?: string[], callback: function | any)
Ref: https://github.com/amdjs/amdjs-api/blob/master/AMD.md
When id
is absent, it defines an anonymous module. Anonymous module is only for runtime dynamically module loading.
requirejs(deps: string[], callback?: function, errback?: function)
Ref: https://github.com/amdjs/amdjs-api/blob/master/require.md
When errback
is called, it only gets one error object (an instance of Error
);
define.switchToUserSpace()
Switch to user module space, define()
call after this will define module in user space.
User module space is the default module space.
define.switchToPackageSpace()
Switch to package module space, define()
call after this will define module in package space.
define.currentSpace()
Returns "user"
if current space is user space, or "package"
if current space is packaeg space. Current space only affects define()
call, it doesn't affect requirejs()
call.
define.nameAnonymous(id)
Provide a module id for the last anonymous module defined like define([deps], function() {})
. The new module id is defined on current space (either user space or package space).
When there is no anonymous module defined, this method will do nothing.
define.reset()
Reset all config, remove all registered and defined modules, switch to default user space.
requirejs.config(options)
Options supports:
1. optional baseUrl
The default baseUrl is empty string ""
, the behaviour is same as requirejs
default baseUrl "./"
.
When dumber-module-loader tries to load a missing module 'foo/bar' at runtime, it will call fetch API fetch("foo/bar.js")
.
The real url is relative to app's current route.
If there is <base href="/some/folder/">
in html head, the real url is relative to "/some/folder/"
, note the ending "/"
is significant.
If you set baseUrl
to some/folder
, the resulting fetch call fetch("some/folder/foo/bar.js")
is still relative to current route or <base>
tag.
To ignore app's current route and <base>
tag, set baseUrl
to an absolute value like /some/folder
, the resulting fetch call fetch("/some/folder/foo/bar.js")
hits absolute URL.
2. optional paths
Similar to requirejs
paths, but simplified, see above.
3. optional bundles
Tells dumber-module-loader what remote bundle file contains certain missing module. Note user and package space modules are listed separately.
nameSpace
is optional, it's designed to load foreign bundle file at runtime.
When nameSpace
is in use, all modules in user module space will be prefixed with optional-name-space/
. For instance, app
module is name spaced as optional-name-space/app
. Note all modules in package module space are not affected, for instance, lodash
will still be lodash
.
bundles: {
'app-bundle': {
nameSpace: 'optional-name-space',
user: ['app', 'app.html', 'util', 'common/index'],
package: ['lodash', 'lodash/map', 'util']
}
}
for bundles only contain user space modules, a simplified config can be used.
bundles: {
'app-bundle': ['app', 'app.html', 'util', 'common/index']
}
requirejs.definedValues()
Return all defined module values {"id": val, "id2": val2}
, excluding registered but not evaluated. This is to match existing behaviour of requirejs
and webpack
. Note if there is duplicated module id in user and package space, the user space module value will show up.
requirejs.defined(id: string)
Check whether a module id is defined, excluding registered but not evaluated. This is to match existing behaviour of requirejs
.
requirejs.specified(id: string)
Check whether a module id is defined or registered but not evaluated. This is to match existing behaviour of requirejs
.