How big is Angular?
$ cloc-1.6.0 --by-file ~/angular-1.2.0/angular!(*scen*,*min*|*.css)
-------------------
File code
-------------------
angular.js 7730
mocks.js 806
animate.js 591
route.js 260
sanitize.js 232
touch.js 231
resource.js 210
cookies.js 75
loader.js 58
-------------------
SUM: 10193
-------------------
Angular squished into Backbone
BB: Unit of measure
Backbone: 937 LOC = 1 BB
- Ember: 16.7 BB (+ jQuery)
- Angular: 7.8 BB
- Cute: 0.6 BB
Comparison
$ cloc --by-file targets/
http://cloc.sourceforge.net v 1.60
-------------------------
File code
-------------------------
ember-1.3.1.js 15825
angular.js 7386
backbone1.1.0.js 937
-------------------------
With cute
$ cloc --by-file targets/
http://cloc.sourceforge.net v 1.60
-------------------------
File code
-------------------------
ember-1.3.1.js 15825
angular-1.2.0.js 7386
backbone1.1.0.js 937
cute-0.1.js 591
-------------------------
Features to implement
- compiler
- scopes
- directives
- controllers
Compiling
- Identify extensions to DOM
- Apply them within a specific scope
Requirements
- Recursive
- Control recursion - allow
ng-repeat
style abilities
- Capture DOM: 'transclusion'
Stages
- For node, find directives
- Apply directives in priority order, stopping if required
- Return a function to link directives to a specific scope
Inside link
- Run each directive's linking function
- If compilation hasn't stopped, compile and link children
Allows watchers
scope.$watch(someExpressionOrFunction,function(now,was) {
})
Watcher requirements
- knows when value changes
- storing values
- can be a string - compile/interpret
Equality in JS
- HORRIBLE
- just edge cases, all the way down
- so: shallow equality +
.isEqual(to)
- cheap watch, cheap clone, promotes good code
Expressions
<div te-style='{selected: s.item.state == "selected"}'>
<span te-bind="s.title(s.item)"></span>
</div>
var prop = scope.$eval("s.some.property")
Evaluation: 799 lines (0.86 BB)
Security vs surprise
- Angular's parser will ignore lots of JS
- How secure? Ish...
- Don't use cute with untrusted Javascript (is it a good idea... ever?)
Cute evaluation
- It's just Javascript: not a new language
new Function("return (" + src + ")",'s','scope')(this,this)
- So
s.foo()
or s.foo.bar["baz"] && s.ƒƒƒƒ
will work
Directives
- Passed through to a compile
- Not with a global registry like Angular
Directives
- Passed through to a compile
- Not with a global registry like Angular
Cute.compile(someEl,directives)
Controllers
- Passed through to directive
- Store object and add
- Again, can be local rather than global
var controllersA = {}
var directivesA = []
Cute.registerDirectives(directivesA,controllersA)
var withAControllers = Cute.compile(someEl,directivesA)
var controllersB = {}
var directivesB = []
Cute.registerDirectives(directivesB,controllersB)
var withBControllers = Cute.compile(someEl,directivesB)
Cutting the magic
- No 'angular script'
- Pass directives + controllers directly
- Scope resolution clear 's.xxx'
Bootstrapping
- No
ng-app
directive: magic
- Explicit bootstrap:
var directives = []
var controllers = {}
Cute.registerDirectives(directives,controllers)
var rootAttach = Cute.compile(document.body,directives)
var rootScope = new Cute.Scope
rootAttach(rootScope)
rootScope.$apply()
What's the essence of Angular?
Module-system: the superflous
- DI: great for Java
- Unit tests need 1 level mocks
- Functional test: stub the boundaries
Module-system: the bad
- 'It must be modular, I'm using modules'
- The 'controllers' module
$rootScope
as mutable global variable
- Singletons: 'but it said so in the docs'
Module-system
- Just a wrapper
- Put your old class/module definitions in a factory, done
Routing
app.controller("top",function(scope) {
var someRouter = new SomeRouterLibrary()
// te-view listens for route events, pops in template + compiles
someRouter.on("route",function(route) {
var routeParams = slice(arguments,1)
scope.$broadcast.apply(scope,["route"].concat(routeParams))
})
})
HTTP
var ajaxForCute = function(opts) {
if(opts.success) opts.success = Cute.wrap(ops.success)
if(opts.error) opts.error = Cute.wrap(ops.error)
return $.ajax(opts)
}
Core can hold back progress
- A bad version in core will be more popular than good module
- Having no core, or asking for replacements would promote development
$resource
, $router
both feature poor
Promises
- A good idea
- Not necessary without periphery -
$http
, $resource
etc
- Promises: 214 LOC (0.23 BB)
Things I learned
- AngularJS has a big, great idea in scopes + controllers
- It broke some rules: uses
new Function
- It has really, really hairy code
- Big API = complex, hard to grok code
Next for cute
- Become a useable library? IE8+ or similar?
- Unit test vs angular?
Any other questions?
@timruffles, @sidekicksrc