Template-BasedModular
ArchitectureAdvanced JavaScript
genify(caijf@corp)
Content
• Modular
• Module
• Template
• Dispatcher
• Case Study
• Deployment
Modular
• Features
– Independence
– Composability
– Decomposability
– Replaceability
Modular
• Advantages
– Several programmers can work on
individual programs at the same time, thus,
making development of program faster
– Concerns are separated such that modules
perform logically discrete functions
– The code base is easier to debug, update
and modify
Content
• Modular
• Module
• Template
• Dispatcher
• Deployment
Module
• Elements
– CSS
– HTML
– JAVASCRIPT
Module
• Encapsulation
– DSL
– JavaScript
– Html
[@STYLE] .m-test a{color:#aaa;} .m-test b{color:#bbb;}[/ @STYLE]
[@HTML] <div class="m-test"> <span class="a">aaaaaaaaaaaa</ span> <span class="b">bbbbbbbbbbbb</span> </ div>[/ @HTML]
[@SCRI PT] var a = 'aaaaa'; var b = 'bbbbb';[/ @SCRI PT]
var style = '\ .m-test a{color:#aaa;}\ .m-test b{color:#bbb;}\';
var html = '\ <div class="m-test">\ <span class="a">aaaaaaaaaaaa</span>\ <span class="b">bbbbbbbbbbbb</span>\ </div>\';
(function(){ var a = 'aaaaaaa'; var b = 'bbbbbbb'; / / TODO})();
<style> .m-test a{color:#aaa;} .m-test b{color:#bbb;}</style>
<div class="m-test"> <span class="a">aaaaaaaaaaaa</ span> <span class="b">bbbbbbbbbbbb</span></div>
<script> var a = 'aaaaa'; var b = 'bbbbb'; / / TODO</script>
Module
• Encapsulation<style> .m-test a{color:#aaa;} .m-test b{color:#bbb;}</style>
<div class="m-test"> <span class="a">aaaaaaaaaaaa</ span> <span class="b">bbbbbbbbbbbb</span></div>
<script> var a = 'aaaaa'; var b = 'bbbbb'; / / TODO</script>
<textarea name="css"> .m-test a{color:#aaa;} .m-test b{color:#bbb;}</ textarea>
<textarea name="html"> <div class="m-test"> <span class="a">aaaaaaaaaaaa</span> <span class="b">bbbbbbbbbbbb</span> </div></ textarea>
<textarea name="j s"> var a = 'aaaaa'; var b = 'bbbbb'; / / TODO</ textarea>
Content
• Modular
• Module
• Template
• Dispatcher
• Case Study
• Deployment
Template
• Import Style
<style> .m-test a{color:#aaa;} .m-test b{color:#bbb;}</style>
<link rel="stylesheet" type="text/ css" href="http:/ / b.126.net/ r/ c.css"/>
<textarea name="css"> .m-test a{color:#aaa;} .m-test b{color:#bbb;}</ textarea>
<textarea name="css" data-src="http:/ / b.126.net/ r/ c.css"></ textarea>
<textarea name="css" data-src="http:/ / b.126.net/ r/ c.css"> .m-test a{color:#aaa;} .m-test b{color:#bbb;}</ textarea>
Template
• Import Script
<script> var a = 'aaaaa'; var b = 'bbbbb';</ script>
<script src="http:/ / b.126.net/ r/ c.j s"></script>
<textarea name="j s"> var a = 'aaaaa'; var b = 'bbbbb';</ textarea>
<textarea name="j s" data-src="http:/ / b.126.net/ r/ c.j s"></ textarea>
<textarea name="j s" data-src="http:/ / b.126.net/ r/ c.j s"> var a = 'aaaaa'; var b = 'bbbbb';</ textarea>
Template
• Import html
<div class="m-test"> <span class="a">aaaaaaaaaaaa</ span> <span class="b">bbbbbbbbbbbb</span></div>
<div class="m-test"> <span class="a">aaaaaaaaaaaa</ span> <span class="b">bbbbbbbbbbbb</span></div>
<textarea name="txt" id="txt-test-html"> <div class="m-test"> <span class="a">aaaaaaaaaaaa</span> <span class="b">bbbbbbbbbbbb</span> </ div></ textarea>
<textarea name="j st" id="j st-test-html"> <div class="m-test"> <span class="a">${x.a}</ span> <span class="b">${x.b}</ span> </ div></ textarea>
<textarea name="ntp" id="ntp-test-html"> <div class="m-test"> <span class="a"></span> <span class="b"></span> </ div></ textarea>
<textarea name="html" data-src="/pub/module/widget.html"></ textarea>
Template<meta charset="utf -8"/>
<textarea name="txt" id="m-if rm-module"> <div class="n-login"> <div class="iner j-flag"> <span class="cls j -flag">×</ span> <span class="min j -flag">-</span> </div> <div class="cnt j-cnt"></div> </ div></ textarea>
<!-- @TEMPLATE --><textarea name="j s" data-src="./ index.css"></ textarea><textarea name="j s" data-src="./ index.j s"></ textarea><!-- /@TEMPLATE -->
module.html
Content
• Modular
• Module
• Template
• Dispatcher
• Case Study
• Deployment
Dispatcher
• Principle
Blog
BlogList BlogTags
Setting
Account
Profile EduExp
Permission
SystemA
B C
D E F G
H I
System
Blog Setting
BlogList BlogTags Account Permission
Profile EduExp
Dispatcher
• UMI
– Uniform Module Identifier
– Format
• Path of URI, e.g. /m/m0/
• Begin with “/”
• Begin with“/?”if private module
– Dependency
• e.g. parent of “/m/m0/”and “/m/m1/”is “/m”
m
blog
list tag/
setting
/ account permission
/ edu
/
/
/
/ /
• UMI
– Split Dependency by UMI
Blog
BlogList BlogTags
Setting
Account
Profile EduExp
Permission
System
Dispatcher
Dispatcher
• UMI
– Mapping UMI to Modulem
blog
list tag/
setting
/ account permission
/ edu
/
/
/
/ /
System
Blog Setting
BlogList BlogTags
Account
PermissionProfile
EduExpBlogList
/ m/ blog/ list/
Dispatcher
• UMI
– Mapping UMI to html
BlogList
<style> … <html> … <script> …
module.html
BlogList
/ m/ blog/ list/
Dispatcher
• UMI
– Mapping UMI to htmlm
blog
list tag/
setting
/ account permission
/ edu
/
/
/
/ /
module/ frame.html
module/blog/ frame.html module/setting/ frame.html
module/blog/ list.html
module/setting/account/ frame.html
module/setting/account/edu.html
Dispatcher
• Strategy
– dispatch to /m/blog/list/
• Check action
• Load or Dispatch
• Waiting Loaded Callback
m
blog
list tag/
setting
/ account permission
/ edu
/
/
/
/ /
Dispatcher
• Strategy
– dispatch to /m/setting/account/
• Find common root
• Hide : source -> common
• Refresh : root -> common
• Show : common -> target
m
blog
list tag/
setting
/ account permission
/ edu
/
/
/
/ /
Dispatcher
• Module Type
Module- I Module- I
Module- I I Module- I I
Dispatcher
• Composite
Module- aa
Module- aa- b2
Module- aa- b1 Module- aa- b3
' /m':{ module:'module/ frame/ frame/ index.html', composite:{ onrefresh:{ top:'/ ?/ frame/ top/ ', side:'/ ?/ frame/ side/ ' }, onshow:{ lyric:' / ?/ frame/ foot/ lyric/ ' , player:'/ ?/ frame/ foot/ player/ ' , detailtag:'/ ?/ frame/ detailtag/ ' } }}
Dispatcher
• Message Channel
– Pointer to Pointer m
blog
list tag/
setting
/ account permission
/ edu
/
/
/
/ /this.__doSendMessage( ' /m/ setting/account/ ' , {d:'ddddd',e:'eeeeee'});
_proModuleAccountProfi le.__onMessage = function(_event){ console.log( 'receive message f rom '+ _event.from+' and say: '+ J SON.stringify(_event.data) );};
Dispatcher
• Message Channel
– Publish and Subscribe
m
blog
list tag/
setting
/ account permission
/ edu
/
/
/
/ /this.__doPublishMessage( 'onok',{a:'aaaa',b:'bbbbb'});
this.__doSubscribeMessage( ' /m/ setting/account/ ','onok', this.__onSubscribe._$bind(this));
this.__doSubscribeMessage( ' /m/ setting/account/ ','onok', this.__onSubscribe._$bind(this));
Content
• Modular
• Module
• Template
• Dispatcher
• Case Study
• Deployment
Case Study
• System Decomposition
Blog
BlogList BlogTags
Setting
Account
Profile EduExp
Permission
Systemm
blog
list tag/
setting
/ account permission
/ edu
/
/
/
/ // / /
/
/
m
blog setting
account
Case Study
• System Decomposition收件箱切换
类别列表
标签列表日志列表
?
blog
tag listbox
/
/ /
class
/ //?/blog/box//?/blog/tag//?/blog/ list//?/blog/class/
Case Study
• Module Development
Case Study
• Module Development
<meta charset="utf-8"/><textarea name="txt" id="module-id-2"> <div class="mdl-2"> <div class="lbx js-flag"></div> <div class="pgr j s-flag"></div> </div></ textarea><textarea name="j st" id="j st-2-blog-list"> {list beg..end as y} {var x=xlist[y]} <div class="w-bit"> <div class="f -cb"> <p class="fl ztl"><a href="#">${x.title}</a></p> <div class="fr xat"> <a href="#">编辑</a> <a href="#">删除</a> </div> </div> <p class="inf "> <span>${x.publishTime|format:'yyyy-MM-dd HH:mm'}</span> <span>阅读(${x.accessCount})</ span> <span>评论(${x.commentCount})</ span> </p> </div> {/ list}</ textarea><!-- @TEMPLATE --><textarea name="css" data-src="./ index.css"></ textarea><textarea name="j s" data-src="./ index.j s"></ textarea><!-- /@TEMPLATE -->
Case Study
• Module Development
_$$AbstractModule
__doBuild
__onShow
__onHide
__onRefresh
/ ** * 构建模块 * @return {Void} */ _pro.__doBuild = function(){ this.__body = _e._$html2node( _e._$getTextTemplate('module-id-2') ); / / 0 - list box / / 1 - pager box var _ list = _e._$getByClassName(this.__body,' js-fl ag'); this.__mopt = { limit:15, parent:_ list[0], item:' jst-2-blog-list' , cache:{klass:_d._$$CacheBlog}, pager:{clazz:'w-pager' ,parent:_ list[1]}, onbeforelistload:this.__onLoadingShow._$bind(this), onemptylist:this.__onMessageShow._$bind(this,'没有日志列表!' ) }; };
/ ** * 显示模块触发事件,子类实现具体逻辑 * @param {Object} 事件对象 * @return {Void} */ _pro.__onShow = function(_options){ var _parent = this.__doParseParent(_options); / / show and ref resh module if (!!_parent&&!!this.__body) _parent.appendChild(this.__body); this.__supOnShow(_options); this.__doApplyComposite('onshow',_options); this.__onRefresh(_options); };
/ ** * 隐藏模块触发事件,子类实现具体逻辑 * @return {Void} */ _pro.__onHide = function(){ this.__supOnHide(); this.__doHideComposite(); _e._$removeByEC(this.__body); };
/ ** * 刷新模块 * @param {Object} 配置信息 * @return {Void} */ _pro.__onRef resh = (function(){ var _doParseCKey = function(_param){ if (!!_param.cid) return 'class-'+_param.cid; if (!!_param.tid) return ' tag-'+_param.tid; return 'box-'+(_param.box||1); }; return function(_options){ this.__supOnRef resh(_options); if (this.__ lmdl) this.__ lmdl._$recycle(); this.__mopt.cache.lkey = _doParseCKey(_options.param||_o); this.__ lmdl = _t._$$ListModulePG._$allocate(this.__mopt); }; })();
_e._$regist('blog-list' ,_p._$$ModuleBlogList);
Case Study
• Module Test
<!-- template box --><div id="template-box" style="display:none;"> <textarea name="html" data-src="../ index.html"></ textarea></div>
<script> define(['{lib}util/ dispatcher/ test.j s'], function(){ / / test module document.mbody = 'module-id-0'; NEJ .P('nej.e')._$testByTemplate('template-box'); });</ script>
Case Study
• System Composition
<script> define(['{lib}util/ dispatcher/ dispatcher.2.j s'], function(){ var _ = NEJ .P; / * start up dispatcher */ _('nej .e')._$startup({ rules:{...}, modules:{...} }); });</ script>
rules:{ rewrite:{ '404':' /m/blog/ list/ ' , ' /m/ blog/ list/ ' :' /m/ blog/ ', ' /m/ setting/ account/ ':' /m/ setting/ ' }, title:{ ' /m/ blog/ tag/ ':'日志标签' , ' /m/ blog/ list/ ' :'日志列表' , ' /m/ setting/ permission/ ':'权限管理' , ' /m/ setting/ account/ ':'基本资料' , ' /m/ setting/ account/ edu/ ':'教育经历' }, alias:{ 'system-tab':' / ?/ tab/ ', 'blog-tab':'/ ?/ blog/ tab/ ', 'blog-list-box':' / ?/ blog/ box/ ', 'blog-list-tag':' / ?/ blog/ tag/ ', 'blog-list-class':' / ?/ blog/ class/ ' , 'blog-list' :' / ?/ blog/ list/ ' , 'setting-tab':' / ?/ setting/ tab/ ', 'setting-account-tab':' / ?/ setting/account/ tab/ ', ' layout-system':'/m', ' layout-blog':' /m/blog', ' layout-blog-list' :' /m/blog/ list/ ' , ' layout-setting':' / m/ setting', ' layout-setting-account':' /m/ setting/account', 'blog-tag':' / m/ blog/ tag/ ', 'setting-edu':'/ m/ setting/ account/ edu/ ', 'setting-profile':' / m/ setting/ account/ ', 'setting-permission':' /m/ setting/permission/ ' } }
modules:{ ' / ?/ tab/ ':'module/ tab/ index.html', ' / ?/ blog/ tab/ ':'module/blog/ tab/ index.html', ' / ?/ blog/box/ ':'module/blog/ list.box/ index.html', ' / ?/ blog/ tag/ ':'module/blog/ list.tag/ index.html', ' / ?/ blog/ class/ ':'module/blog/ list.class/ index.html', ' / ?/ blog/ list/ ' :'module/blog/ list/ index.html', ' / ?/ setting/ tab/ ':'module/ setting/ tab/ index.html', ' / ?/ setting/account/ tab/ ':'module/ setting/account.tab/ index.html', ' /m':{ module:'module/ layout/ system/ index.html', composite:{ tab:'/ ?/ tab/ ' } }, ' /m/blog':{ module:'module/ layout/blog/ index.html', composite:{ tab:'/ ?/ blog/ tab/ ' } }, ' /m/blog/ list/ ' :{ module:'module/ layout/blog.list/ index.html', composite:{ box:'/ ?/ blog/box/ ', tag:'/ ?/ blog/ tag/ ', list:' / ?/ blog/ list/ ' , clazz:'/ ?/ blog/ class/ ' } }, ' /m/blog/ tag/ ':'module/blog/ tag/ index.html', ' /m/ setting':{ module:'module/ layout/ setting/ index.html', composite:{ tab:'/ ?/ setting/ tab/ ' } }, ' /m/ setting/account':{ module:'module/ layout/ setting.account/ index.html', composite:{ tab:'/ ?/ setting/account/ tab/ ' } }, ' /m/ setting/account/ ':'module/ setting/profile/ index.html', ' /m/ setting/account/ edu/ ':'module/ setting/edu/ index.html', ' /m/ setting/permission/ ':'module/ setting/permission/ index.html' }
Content
• Modular
• Module
• Template
• Dispatcher
• Case Study
• Deployment
Deployment
• Publisher
– NodeJS
– NEJ-Publisher
– Project Configuration
– do release
Deployment
• Performance Improvement <div id="template-box" style="display:none;"> <!-- @TEMPLATE --> <textarea name="html" data-src="module/ tab/ index.html"></ textarea> <textarea name="html" data-src="module/blog/ tab/ index.html"></ textarea> <textarea name="html" data-src="module/blog/ list.box/ index.html"></ textarea> <textarea name="html" data-src="module/blog/ list.tag/ index.html"></ textarea> <textarea name="html" data-src="module/blog/ list.class/ index.html"></ textarea> <textarea name="html" data-src="module/ layout/ system/ index.html"></ textarea> <textarea name="html" data-src="module/ layout/blog/ index.html"></ textarea> <textarea name="html" data-src="module/ layout/blog.list/ index.html"></ textarea> <textarea name="html" data-src="module/ layout/ setting/ index.html"></ textarea> <textarea name="html" data-src="module/ layout/ setting.account/ index.html"></ textarea> <textarea name="html" data-src="module/blog/ tag/ index.html"></ textarea> <textarea name="html" data-src="module/blog/ list/ index.html"></ textarea> <textarea name="html" data-src="module/ setting/ tab/ index.html"></ textarea> <textarea name="html" data-src="module/ setting/account.tab/ index.html"></ textarea> <!-- /@TEMPLATE --> </div>
Deployment
• Performance Improvement <div id="template-box" style="display:none;"> <!-- @MODULE --> <textarea name="html" data-src="module/ tab/ index.html"></ textarea> <textarea name="html" data-src="module/blog/ tab/ index.html"></ textarea> <textarea name="html" data-src="module/blog/ list.box/ index.html"></ textarea> <textarea name="html" data-src="module/blog/ list.tag/ index.html"></ textarea> <textarea name="html" data-src="module/blog/ list.class/ index.html"></ textarea> <textarea name="html" data-src="module/ layout/ system/ index.html"></ textarea> <textarea name="html" data-src="module/ layout/ blog/ index.html"></ textarea> <textarea name="html" data-src="module/ layout/ blog.list/ index.html"></ textarea> <textarea name="html" data-src="module/ layout/ setting/ index.html"></ textarea> <textarea name="html" data-src="module/ layout/ setting.account/ index.html"></ textarea> <textarea name="html" data-src="module/blog/ tag/ index.html"></ textarea> <textarea name="html" data-src="module/blog/ list/ index.html"></ textarea> <textarea name="html" data-src="module/ setting/ tab/ index.html"></ textarea> <textarea name="html" data-src="module/ setting/account.tab/ index.html"></ textarea> <!-- /@MODULE --> </div>
Deployment
• Performance Improvement<!-- @TEMPLATE --><textarea name="html" data-src="./blog/ tab/ index.html"></ textarea><textarea name="html" data-src="./blog/ tag/ index.html"></ textarea><textarea name="html" data-src="./blog/ list/ index.html"></ textarea><textarea name="html" data-src="./blog/ list.box/ index.html"></ textarea><textarea name="html" data-src="./blog/ list.tag/ index.html"></ textarea><textarea name="html" data-src="./blog/ list.class/ index.html"></ textarea><!-- /@TEMPLATE -->
modules:{ ' / ?/ tab/ ':'module/ tab/ index.html', ' / ?/ blog/ tab/ ':'module/ blog.html', ' / ?/ blog/ box/ ':'module/ blog.html', ' / ?/ blog/ tag/ ':'module/blog.html', ' / ?/ blog/ class/ ':'module/blog.html', ' / ?/ blog/ list/ ' :'module/blog.html', ' / ?/ setting/ tab/ ':'module/ setting.html', ' / ?/ setting/ account/ tab/ ':'module/ setting.html',
DEMO
Q&A
Thank You !