asynchronous frontend dependency management without AMD
Dec 24, 2014
module like support, it really sucks developers.
For years ago, developers used to use
<script> tag to write code, however when the page codes grows, the maintainability will be harder and harder. Then, with the arise of nodejs, CommonJS brings up using
exports to resolve modules. It seems really nice when using in nodejs, however, when it meets browser, it works not quite well. The reason is simply that browser does not support synchronous
require, it can not load a script from file I/O. Then AMD comes up a specification used well for browser, as the AMD says:
The Asynchronous Module Definition (AMD) API specifies a mechanism for defining modules such that the module and its dependencies can be asynchronously loaded. This is particularly well suited for the browser environment where synchronous loading of modules incurs performance, usability, debugging, and cross-domain access problems.
AMD has two main concerns:
asynchronous loading script
this works well in browser, and fascinates developers a lot, developers write modular scripts in different files, different modules can be dependent with some others, which makes codes resuable, moreover debug and edit files are quite simple and smooth.
define to define a module and its dependecies
to use AMD, the module must use
define which really makes developers messy.
when using AMD, it is easy to run into the following road-blocks:
- want to use Libray X, does it suport AMD ?
- if it is not, I have to add a shim ? Should I patch the library ?
- if it supports, I’ll want to load it from a libs directory
- Where is the root of my application ? Should I write a alias to use it ?
- What about sharing code client/server ?
AMD especially requirejs has its answers for every question. AMD’s answer for
nearly every one of them is to
add some configuration directivers or
write a r.js plug-in.
Then we write configrutions file with many lines long of obscure directives, and these files are hard to be reused for example, used for the tests.
So, what about asynchronous loading scripts without using AMD like
define or writing messy configuration file ?
This is what bearcat tries to make an effort, which enables developers to write
Show me some codes
Let’s begin with a dead simple example:
A simple car must have an engine to startup, so you write two files.
Car has the dependency of engine, so how to resolve the dependency ?
In AMD(requirejs), you should do the following:
- wrap the code with
- in define, resolve
- setup data-main, then run
so codes may be like this:
define, the codes will be hard to be shared for client/server
relative path, car and engine are tightly coupled, what if the car wants to use another engine to run ?
In bearcat, it is dead simple and nature.
Just add some
car and engine use
this.$id attribute to define its unique id
this.$engine attribute to tell bearcat that it wants a dependency with the id of
car and engine both register its function constructor with magic attributes to bearcat
then, what does bearcat do ?
- resolve dependencies, knows car wants a dependency with the id of
- asynchronously load
- when car instance is created, automatically inject
engineinstance into car’s
- when car invokes
runmethod, engine is also ready to
So, as you can see, what bearcat does is
dependency injection with asynchronous loading.
the whole demo sources can be found on AMD vs bearcat
AMD vs bearcat
- AMD resolves script files as modules, modules use
defineto resolve dependencies,
definemakes it hard be compatible especially when some library does not provides
definehook. Besides, modules are relative to some others, thus are
tightlycoupled, so unit-tests will be quite messy.
AMD and bearcat both supports asynchronous scripts loading as needed, both are easy to edit and debug.
- AMD(requirejs) needs to config for
packagesetc … What’s more, this configuration file can not be shared very well. When you want to use in another project or for use in unit-test, you should modifiy configuration file to make AMD happy.
Want to use a libray ?
Using with browserify
Browserify lets you require(‘modules’) in the browser by bundling up all of your dependencies. Therefore, it is easy to resolve a library using browserify by simply call
require('library'). However, browserify bundles up all files, debug and edit files may meet up some problems. You should watch files and build up bundle file whenever code files changes, moreover when build errored, the error message should show up in the browser to make developer know what happened. For better debugger, developers should know how to use source-map.
With bearcat, browserify will simply be a role of
Here comes with an example: use
requireUtil, this acts as a bridge between browserify and bearcat
testJquery, it has the dependency of
requireUtil.js into browserify to enable
the whole sources can be found on bearcat-browserify-jquery
bearcat is still a young but promising project, it heavilly needs your contributions.
May you enjoy coding with bearcat …