Upload
joseph-chiang
View
3.453
Download
6
Embed Size (px)
DESCRIPTION
在北京 2012/9/9 所举办的 SDCC 分享「模块加载策略」
Citation preview
模块加载策略
讲者 - 蒋定宇 / josephj
https://speakerdeck.com/u/josephj/p/sdcc
Module Loader Strategy
关于我 - 蒋定宇 (josephj)
关于我 - 蒋定宇 跑步环岛
·共 27 天·约 900 多公里
2008 年 5 月份
(josephj)
关于我 - 蒋定宇
雅虎奇摩
·前端工程师·YDN 技术布道师·主要项目:知识+
跑步环岛
·共 27 天·约 900 多公里
2008 年 5 月份
2005.10 - 2009.8
(josephj)
关于我 - 蒋定宇
雅虎奇摩
·前端工程师·YDN 技术布道师·主要项目:知识+
miiiCasa 云永科技
·前端技术团队主管·技术布道师
跑步环岛
·共 27 天·约 900 多公里
2008 年 5 月份
2005.10 - 2009.8
2009.9 至今
(josephj)
2010.7 两天一夜的北京行留下极深刻的印象
2010.7 两天一夜的北京行留下极深刻的印象
担任讲师感谢裕波!
百度参访
2010.7 两天一夜的北京行留下极深刻的印象
担任讲师感谢裕波!
百度参访
http://josephj.com/entry.php?id=336
北京 WebRebuild 演講,收獲滿檔!
https://speakerdeck.com/u/josephj/p/webrebuild
建立前端开发团队当时演讲主题
什么是模块?可以被重复利用的元件
由 7 个不同国家所提供的 50 多个模块所构成
http://astronomy.wikia.com/wiki/International_Space_Station
NASA 美国太空总署太空站
由 7 个不同国家所提供的 50 多个模块所构成
http://astronomy.wikia.com/wiki/International_Space_Station
NASA 美国太空总署太空站
在任何分工精细的工程领域
模块化开发是必然趋势:
「采用既有模块、避免重新打造轮子」
GitHub
GitHubGitHub 是软体业界的「轮子交流区」
git submodule add 就可以轻松加入别人写好的模块
http://www.flickr.com/photos/halfbisqued/2353845688/
网页中的模块又是什么?
http://www.flickr.com/photos/halfbisqued/2353845688/
任何可以被载入使用的 HTML、CSS 与 JavaScript 档案
网页中的模块又是什么?
http://www.flickr.com/photos/halfbisqued/2353845688/
任何可以被载入使用的 HTML、CSS 与 JavaScript 档案
超级好用的两个模块:jQuery 与 Twitter Bootstrap
网页中的模块又是什么?
程序员也可以做出漂亮网站
主题:模块加载策略
主题:模块加载策略
·传统 模式
主题:模块加载策略
·传统 模式
·页层级设定 模式 Page-level Setting
主题:模块加载策略
·传统 模式
·页层级设定 模式 Page-level Setting
·模块层级设定 模式 Module-level Setting
传统模式
传统模式用 <link href> 或 <script src> 做加载
两岸三地的 GitHub 开发者https://github.com/josephj/github-chinese-developer
这次演讲的范例跟工具都在不同的 Branch 中
两岸三地的 GitHub 开发者https://github.com/josephj/github-chinese-developer
这次演讲的范例跟工具都在不同的 Branch 中
两岸三地的 GitHub 开发者https://github.com/josephj/github-chinese-developer
这次演讲的范例跟工具都在不同的 Branch 中
<link href="assets/stylesheets/bootstrap.min.css" rel="stylesheet"><link href="assets/stylesheets/bootstrap-responsive.css" rel="stylesheet"><link href="assets/stylesheets/demo.css" rel="stylesheet">
<script src="assets/javascripts/jquery-1.8.1.min.js"></script><script src="assets/javascripts/handlebars-1.0.0.beta.6.js"></script>
<script src="assets/javascripts/demo.js"></script>
这样的小玩意,肯定大部分人都是直接加载模块的Bootstrap CSS
Bootstrap CSS
Page CSS
jQuery
Handlebars
Page JS
对于一个网站开发团队而言,这样做会陷入混乱
需要一定的开发模式来遵守
页面模块:一种团队开发模式每个页面模块都切分出 HTML、JavaScript、CSS
页面模块:一种团队开发模式每个页面模块都切分出 HTML、JavaScript、CSS
<div id=”nav”> <div class=”hd”> <h2>標題</h2> </div> <div class=”bd”> <p>內文</p> </div> <div class=”ft”> <a href=”...”>更多... </a> </div></div>
页面模块的 HTML 结构
<div id=”nav”> <div class=”hd”> <h2>標題</h2> </div> <div class=”bd”> <p>內文</p> </div> <div class=”ft”> <a href=”...”>更多... </a> </div></div>
<div id=”nav”> <div class=”hd”> <h2>標題</h2> </div> <div class=”bd”> <p>內文</p> </div> <div class=”ft”> <a href=”...”>更多... </a> </div></div>
页面模块的 HTML 结构
<div id=”nav”> <div class=”hd”> <h2>標題</h2> </div> <div class=”bd”> <p>內文</p> </div> <div class=”ft”> <a href=”...”>更多... </a> </div></div>
<div id=”nav”> <div class=”hd”> <h2>標題</h2> </div> <div class=”bd”> <p>內文</p> </div> <div class=”ft”> <a href=”...”>更多... </a> </div></div>
页面模块的 HTML 结构
一个 ID 代表一个模块
不能重复
<div id=”nav”> <div class=”hd”> <h2>標題</h2> </div> <div class=”bd”> <p>內文</p> </div> <div class=”ft”> <a href=”...”>更多... </a> </div></div>
<div id=”nav”> <div class=”hd”> <h2>標題</h2> </div> <div class=”bd”> <p>內文</p> </div> <div class=”ft”> <a href=”...”>更多... </a> </div></div>
页面模块的 HTML 结构
一个 ID 代表一个模块
不能重复
.hd, .bd, .ft 代表模块的标
头、内容、标尾结构
因每个模块 ID 独立、CSS 不会互相污染此模块叫 #ykpsb
#ykp 是项目缩写、sb 是 Search Box 的縮寫
<div id=”ykpsb”> <div class=”bd clearfix”> <form ...> ... </form> <div class=”extra”> ... </div> </div></div>
form .extra
[HTML]
因每个模块 ID 独立、CSS 不会互相污染此模块叫 #ykpsb
#ykp 是项目缩写、sb 是 Search Box 的縮寫
<div id=”ykpsb”> <div class=”bd clearfix”> <form ...> ... </form> <div class=”extra”> ... </div> </div></div>
form .extra
[HTML]<style>#ykpsb { margin-bottom:10px;}#ykpsb form { float:left;}#ykpsb .extra { float:right;}</style>
[CSS]
因每个模块 ID 独立、CSS 不会互相污染此模块叫 #ykpsb
#ykp 是项目缩写、sb 是 Search Box 的縮寫
老道所提的 JavaScript 模块模式
window.mods[“ykpsb”] = function () {
}();
老道所提的 JavaScript 模块模式
window.mods[“ykpsb”] = function () {
}();
// 利用闭包与外界隔绝 var privateVar, publicFn;
// 内部自行处理,不会影响其他模块 privateVar = "123";
publicFn = function () {};
老道所提的 JavaScript 模块模式
window.mods[“ykpsb”] = function () {
}();
// 利用闭包与外界隔绝 var privateVar, publicFn;
// 内部自行处理,不会影响其他模块 privateVar = "123";
publicFn = function () {};
return { // 仅揭露需公开的方法 publicFn: publicFn };
老道所提的 JavaScript 模块模式
window.mods[“ykpsb”] = function () {
}();
// 利用闭包与外界隔绝 var privateVar, publicFn;
// 内部自行处理,不会影响其他模块 privateVar = "123";
publicFn = function () {};
return { // 仅揭露需公开的方法 publicFn: publicFn };
// 外界仅可存取公开方法mod["ykpsb"].publicFn();
Nicholas ZakasFormer Principal Front End Engineer, Yahoo!
Zakas 的 Scalable JavaScript 模块
观察者模式:
实作类似 Hub 广播跟监听的行为,达到不使用全域变数跨模组沟通的目的。
https://github.com/miiicasa/module
http://www.nipic.com/show/2/55/d96dde66860c5190.html
发展到一定规模,该如何选择每页所需的模块档呢?
页面模块化会切分出很多零散的档案,如何载入是一门学问
http://www.nipic.com/show/2/55/d96dde66860c5190.html
天哪!我该如何处理
这么多模块档案呢?
发展到一定规模,该如何选择每页所需的模块档呢?
页面模块化会切分出很多零散的档案,如何载入是一门学问
http://www.flickr.com/photos/billjacobus1/123644872/
这时我们需要一个 Loader 机制协助载入零散且多的模块档案
页层级设定模式2010 年、北京 WebRebuild 议题之一
https://speakerdeck.com/u/josephj/p/webrebuild
http://josephj.com/lab/2012/github-chinese-develope/
两岸三地的开发者假设我们用较有规模的「页面模块模式」来开发...
两岸三地的开发者假设我们用较有规模的「页面模块模式」来开发...
http://josephj.com/lab/2012/github-chinese-develope/
两岸三地的开发者
条件过滤模块 _filter.php _filter.css _filter.js
假设我们用较有规模的「页面模块模式」来开发...
http://josephj.com/lab/2012/github-chinese-develope/
两岸三地的开发者
列表模块_list.php_list.css_list.js
条件过滤模块 _filter.php _filter.css _filter.js
假设我们用较有规模的「页面模块模式」来开发...
http://josephj.com/lab/2012/github-chinese-develope/
两岸三地的开发者
资讯模块 列表模块_info.php_info.css_info.js
_list.php_list.css_list.js
条件过滤模块 _filter.php _filter.css _filter.js
假设我们用较有规模的「页面模块模式」来开发...
http://josephj.com/lab/2012/github-chinese-develope/
传统作法肯定会产生悲剧
·HTTP 请求数量过多
·会造成页面阻塞
·档案内容未压缩
·需用全域变数沟通
·载入得考虑先后顺序
·没有清楚的架构、易陷入混乱
MINI
透过设定档
将多个檔案合并、最小化
的开发环境工具
http://www.flickr.com/photos/prettypony/2644225789/
https://github.com/josephj/mini
Mini 的设定档, 十分容易设定
寻找档案的路径,可以设定多个$DEV_ROOT 是 VirtualHost 的环境变量
Mini 的设定档, 十分容易设定
寻找档案的路径,可以设定多个$DEV_ROOT 是 VirtualHost 的环境变量
定义 demo 有哪些 CSS 与 JS 档
Mini 的设定档, 十分容易设定
指定 type 与 module 即可自动合并且最小化
指定 type 与 module 即可自动合并且最小化
/mini?module=<module>&type=<css|js>
指定 type 与 module 即可自动合并且最小化
/mini?module=<module>&type=<css|js>
没有 Mini 时的情况
没有 Mini 时的情况
透过 Mini 可以大幅减少请求数量
透过 Mini 可以大幅减少请求数量
由于 Mini 没有缓存机制、只能用在开发环境
在 build 时得预先产生合并及最小化后的档案
由于 Mini 没有缓存机制、只能用在开发环境
在 build 时得预先产生合并及最小化后的档案
由于 Mini 没有缓存机制、只能用在开发环境
在 build 时得预先产生合并及最小化后的档案
线上的 CSS/JS 在 Build 后成为单一档案
页层级设定模式的整体架构
页层级设定模式的整体架构
很直觉的载入机制,可以有效地将模块档案合并压缩
这是 miiiCasa 从一开始就使用的模块加载方式
网站上线后都很稳定、很满意
但随著几次的改版,我們發现了不少问题
页层级设定模式
改版必定伴随著模块 (功能) 的新增、修改、移除
修改 Mini 的组态设定不就好了吗?
缺点 - 维护不易
改版必定伴随著模块 (功能) 的新增、修改、移除
修改 Mini 的组态设定不就好了吗?
缺点 - 维护不易
改版到新版后,有 3 个页面模块需要移除(基本就有 9 个档案需移除)
但模块依赖关系是非常复杂的!
http://www.flickr.com/photos/kalavinka/4617897952/
但模块依赖关系是非常复杂的!
http://www.flickr.com/photos/kalavinka/4617897952/
但模块依赖关系是非常复杂的!
页面模块 JavaScript
http://www.flickr.com/photos/kalavinka/4617897952/
但模块依赖关系是非常复杂的!
功能模块 JavaScript
页面模块 JavaScript
http://www.flickr.com/photos/kalavinka/4617897952/
但模块依赖关系是非常复杂的!YUI CSS
页面模块 CSS
功能模块 JavaScript
页面模块 JavaScript
http://www.flickr.com/photos/kalavinka/4617897952/
但模块依赖关系是非常复杂的!YUI CSS
页面模块 CSS
功能模块 JavaScript
页面模块 JavaScript
想要移除一个页面模块哪些功能模块也需要一起移除呢?
http://www.flickr.com/photos/kalavinka/4617897952/
解决依赖问题,最近很火热的 AMD 架构
6006
// 定义⼀一个 AMD 模块define(“editor”, [“handlebars”], function () { function Editor { /* Constructor */ } return Editor;},);
解决依赖问题,最近很火热的 AMD 架构
6006
// 定义⼀一个 AMD 模块define(“editor”, [“handlebars”], function () { function Editor { /* Constructor */ } return Editor;},);
解决依赖问题,最近很火热的 AMD 架构
第二个参数可以定义此模块需要哪些模块
6006
6006
// 定义⼀一个 AMD 模块define(“editor”, [“handlebars”], function () { function Editor { /* Constructor */ } return Editor;},);
解决依赖问题,最近很火热的 AMD 架构
// 使用⼀一个 AMD 模块require(["editor"], function (Editor) { new Editor();});
第二个参数可以定义此模块需要哪些模块
在使用时以动态载入方式将相关模块档案一并载入
缺点 - Build 耗时过久我们共有这么多的页面需预先 Build:
缺点 - Build 耗时过久我们共有这么多的页面需预先 Build:
miiiCasa Build 流程中得为所有页面建置静态档此单项作业得耗时 2 分半!
缺点 - Build 耗时过久我们共有这么多的页面需预先 Build:
miiiCasa Build 流程中得为所有页面建置静态档此单项作业得耗时 2 分半!
但是持续整合的标准是完整 Build 不应超过 10 分钟
缺点 - Build 耗时过久我们共有这么多的页面需预先 Build:
缺点 - 线上除虫困难
缺点 - 线上除虫困难
即使经过 Beautifier 仍不易修改、还是得 Build、对要求敏捷开发就差了些
每页的 JS 与 CSS 档案都是完全不重复的也因此没有办法做到跨页间的缓存
缺点 - 缓存效率差
miii_index_my_contact_18fa331dfbf2bd392660925ba8f41239.js
miii_index_my_contact_34945d9e0efb63c7dc62dcbbc3442a60.css
两页有许多共用的页面模块、却无缓存的好处
miii_index_my_device_704b3ae3682d178a94465c066b0f6d42.js
miii_index_my_device_623f7e30575a7180ddeb11fd748aed31.css
缺点 - 缓存效率差
后来我们为了缓存、抽离出一些共用 Mini 模块
但这样做反而让设定更难易维护
模块层级设定模式真正的模块导向开发!
我心目中的乌托邦!让模块化开发不需要再有烦恼页面配置!
我心目中的乌托邦!让模块化开发不需要再有烦恼页面配置!
我心目中的乌托邦!
开发者专注于单一模块的开发设定此模块需要哪些依赖模块
让模块化开发不需要再有烦恼页面配置!
模块架构
我心目中的乌托邦!
Loader 计算出页面有哪些模块需载入
开发者专注于单一模块的开发设定此模块需要哪些依赖模块
让模块化开发不需要再有烦恼页面配置!
模块架构
模块 Loader
我心目中的乌托邦!
Loader 计算出页面有哪些模块需载入
开发者专注于单一模块的开发设定此模块需要哪些依赖模块
让模块化开发不需要再有烦恼页面配置!
模块架构
模块 Loader
远端模块载入机制服务器与浏览器端交互配合自动以效能最佳化方式载入远端模块
RequireJS 是目前最牛逼的 AMD 实作
RequireJS 是目前最牛逼的 AMD 实作
可以自动一个一个载入依赖的模块或发布前透过 r.js 做合并及最小化
// AMD Moduledefine(“editor”, [‘a’,’b’,’c’], function () { function Editor { /* Constructor */ } return Editor;});require(["editor"], function (Editor) { new Editor();});
RequireJS 是目前最牛逼的 AMD 实作
可以自动一个一个载入依赖的模块或发布前透过 r.js 做合并及最小化
// AMD Moduledefine(“editor”, [‘a’,’b’,’c’], function () { function Editor { /* Constructor */ } return Editor;});require(["editor"], function (Editor) { new Editor();});
合并与最小化仍然会有线上除错困难与
Build 时间过久的两个问题、
甚至模块一多对开发速度也会造成冲击
RequireJS 的架构因此不太符合我的需求
国内较少人使用的 YUI 函式库
国内较少人使用的 YUI 函式库
早在三年前、2009/6 月就提出的模块架构
国内较少人使用的 YUI 函式库
早在三年前、2009/6 月就提出的模块架构
// AMD Moduledefine(‘editor’, [‘a’,’b’,’c’], function () { function Editor { /* Constructor */ } return Editor;});
require(["editor"], function (Editor) { new Editor();});
国内较少人使用的 YUI 函式库
早在三年前、2009/6 月就提出的模块架构
跟去年才有的 AMD、所要解决模块依赖性的思路是一致的
// AMD Moduledefine(‘editor’, [‘a’,’b’,’c’], function () { function Editor { /* Constructor */ } return Editor;});
require(["editor"], function (Editor) { new Editor();});
// YUI ModuleYUI.add("editor", function () { function Editor { /* Constructor */ } Y.Editor = Editor; }, “VERSION”, {requires:[‘a’,’b’,’c’]});
YUI.use("editor", function (Y) { new Y.Editor();});
以 YUI DataTable 为范例
以 YUI DataTable 为范例
以 YUI DataTable 为范例
不 Reload 的行为很多:换页、排序、直接编辑。也可以接受各类资料来源,是很复杂的模组
只要几行代码就可以载入所需模块
只要几行代码就可以载入所需模块
<script src="http://yui.yahooapis.com/3.5.0/build/yui/yui-min.js"></script>
只要几行代码就可以载入所需模块
<script src="http://yui.yahooapis.com/3.5.0/build/yui/yui-min.js"></script>
<script>
</script>
YUI().use('datatable', function (Y) {
});
只要几行代码就可以载入所需模块
<script src="http://yui.yahooapis.com/3.5.0/build/yui/yui-min.js"></script>
<script>
</script>
YUI().use('datatable', function (Y) {
});
能想像 6 行代码背后,做了多少事情吗?
alert(Y.DataTable);
yui (Seed)
计算所需模块的流程
yui (Seed)
计算所需模块的流程
YUI().use('datatable')
yui (Seed)
widget
datatable-core
base-build
datatable-head datatable-body
计算所需模块的流程
YUI().use('datatable')
escape
yui (Seed)
widget
datatable-core
base-build
datatable-head datatable-body
model-list
node-event-delegate
base-base
attribute
event-focus
base-plugin-hostnode-base node-style
classnamemanager
view
计算所需模块的流程
YUI().use('datatable')
escape
yui (Seed)
widget
datatable-core
base-build
datatable-head datatable-body
model-list
node-event-delegate
base-base
attribute
event-focus
base-plugin-hostnode-base node-style
classnamemanager
view
yui-base
event-delegate
pluginhost event-synthetic attribute-core attribute-events
attribute-extras array-extras array-invoke
arraylist
json-parsemodel
计算所需模块的流程
YUI().use('datatable')
escape
yui (Seed)
widget
datatable-core
base-build
datatable-head datatable-body
model-list
node-event-delegate
base-base
attribute
event-focus
base-plugin-hostnode-base node-style
classnamemanager
view
yui-base
event-delegate
pluginhost event-synthetic attribute-core attribute-events
attribute-extras array-extras array-invoke
arraylist
json-parsemodel
计算所需模块的流程
YUI().use('datatable')
实际上 datatable 共有 64 個模块档需载入一个一个载入会很操效能YUI 的处理方式为何?
强大的压缩机 Combo
强大的压缩机 Combo
雅虎的 Combo 机制
直接以 GET 参数将不同模块档案串连并最小化
强大的压缩机 Combo
雅虎的 Combo 机制
直接以 GET 参数将不同模块档案串连并最小化
http://yui.yahooapis.com/combo? <模块 1 的对应路径>&
<模块 2 的对应路径>&
<模块 3 的对应路径>& ...
<模块 n 的对应路径>
并行非堵塞加载YUI().use('datatable')
YUI 种子档案
并行非堵塞加载YUI().use('datatable')
YUI 种子档案
载入相关 CSS
并行非堵塞加载YUI().use('datatable')
将所需 JavaScript 模块分散请求、并行下载
YUI 种子档案
载入相关 CSS
并行非堵塞加载YUI().use('datatable')
将所需 JavaScript 模块分散请求、并行下载
YUI 种子档案
载入相关 CSS
并行非堵塞加载
分散与 Combo 逻辑考虑了:「模块先后顺序」、「模块数量」、「浏览器同时请求数量」、「浏览器 GET 长度限制」,非常的自动化。自己要做这样的机制非常不易。
YUI().use('datatable')
YUI().use('datatable')
从种子变成大树仅花了 323ms
323ms
YUI().use('datatable')
从种子变成大树仅花了 323ms
323ms
不了解内情的人会说 YUI 很肥很庞大实际上它只载入需要的模块、其他函式库沒有這樣的效率
YUI().use('datatable')
从种子变成大树仅花了 323ms
323ms
不了解内情的人会说 YUI 很肥很庞大实际上它只载入需要的模块、其他函式库沒有這樣的效率
YUI().use('datatable')
例如:使用 jQuery 真的每页都用的到 ajax 这个函式吗?
John ResigThe creator of jQuery
http://www.quora.com/How-could-YUI3-improve-its-image-compared-to-jQuery-MooTools-etc
YUI 载入方式实在太 Sexy 了、应被大力推广!
John ResigThe creator of jQuery
YUI().use() + pulling code off of Yahoo's CDN is damn sexy and should be promoted *VERY* heavily.
http://www.quora.com/How-could-YUI3-improve-its-image-compared-to-jQuery-MooTools-etc
YUI 载入方式实在太 Sexy 了、应被大力推广!
有模块架构、有模块 Loader、配合最佳化的远端模块载入机制!
还等什么?快到用在网站页面模块的载入机制上!
YUI 的架构正是我所期盼的
问题:寻找 Combo 机制的替代品
问题:寻找 Combo 机制的替代品
雅虎的 Combo 仅供内部使用、还好有人写了替代品!我选择的是 Minify 这个工具,一样会帮我做伺服器端的缓存、合并与档案最小化
问题:寻找 Combo 机制的替代品
雅虎的 Combo 仅供内部使用、还好有人写了替代品!
http://code.google.com/p/minify/
Minify (PHP5)
https://github.com/mrclay/minify
我选择的是 Minify 这个工具,一样会帮我做伺服器端的缓存、合并与档案最小化
问题:寻找 Combo 机制的替代品
雅虎的 Combo 仅供内部使用、还好有人写了替代品!
http://code.google.com/p/minify/
Minify (PHP5)
https://github.com/mrclay/minify
http://<your host>/minify?f= <模块 1 的对应路径>,
<模块 2 的对应路径>, ...
<模块 n 的对应路径>
我选择的是 Minify 这个工具,一样会帮我做伺服器端的缓存、合并与档案最小化
困难二:YUI 自订模块组态设定复杂
困难二:YUI 自订模块组态设定复杂
非 YUI 本身的模块得另外定义,但这样不好维护
困难二:YUI 自订模块组态设定复杂
YUI_config = {"filter":"raw","async":true,"combine":true,"comboBase":"combo/?f=","comboSep":",","root":"lib/yui/build/","langs":"zh-TW,en-US","groups":{"mui":{"combine":true,"fetchCSS":true,"root":"lib/mui/","lang":["en-US","zh-TW"],"modules":{"platform-core":{"path":"platform/core.js","requires":["node-base","event-base","platform-sandbox"]},"platform-sandbox":{"path":"platform/sandbox.js"},"lang-service":{"path":"platform/lang_service.js","requires":["platform-core","platform-sandbox","intl"]},"scroll-pagination":{"path":"scroll-pagination/scroll-pagination.js","requires":["event","event-resize","node-event-delegate","datasource","scroll-pagination-css"]},"scroll-pagination-css":{"path":"scroll-pagination/assets/scroll-pagination.css","type":"css"},"shjs":{"path":"shjs/sh_php.min.js","requires":["shjs-core","shjs-css"]},"shjs-css":{"path":"shjs/sh_nedit.css","type":"css"},"mui-cssbutton":{"path":"cssbutton/assets/skins/miiicasa/cssbutton-skin.css","type":"css"},"shjs-core":{"path":"shjs/sh_main.min.js"}}},"index":{"combine":true,"fetchCSS":false,"root":"index/","lang":["en-US","zh-TW"],"modules":{"welcome":{"path":"welcome/welcome.js","lang":["en-US","zh-TW"],"requires":["platform-core","platform-sandbox","lang-service","console"]},"welcome/_notification":{"path":"welcome/_notification.js","requires":["substitute","scroll-pagination","yql","panel","node-event-delegate","handlebars"]},"charming/_masthead":{"path":"charming/_masthead.js","requires":["panel","shjs"]},"common/_sidebar":{"requires":["mui-cssbutton"]}}}}};YUI().use("welcome","welcome/_notification","charming/_masthead","common/_sidebar");
非 YUI 本身的模块得另外定义,但这样不好维护
困难三:CSS 不适用于动态加载
困难三:CSS 不适用于动态加载
YUI 与 RequireJS 都可以加载 CSS、但都只能采用动态加载
困难三:CSS 不适用于动态加载
CSS 须在 HTML 显示前就准备好,不然浏览器须一直重新绘制,对网站效能会是很大的冲击
YUI 与 RequireJS 都可以加载 CSS、但都只能采用动态加载
困难三:CSS 不适用于动态加载
CSS 须在 HTML 显示前就准备好,不然浏览器须一直重新绘制,对网站效能会是很大的冲击
<link rel="stylesheet" href="page.css" media="all">
YUI 与 RequireJS 都可以加载 CSS、但都只能采用动态加载
YUI 解决了大部分的需求剩下的桥梁得自己建设!
http://www.flickr.com/photos/defenceimages/6771187177/
https://github.com/josephj/static-loader
一并解决 YUI 组态的复杂度与让 CSS 传统加载
YUI 解决了大部分的需求剩下的桥梁得自己建设!
http://www.flickr.com/photos/defenceimages/6771187177/
两岸三地的开发者这回我们要加上模块依赖关系!
http://josephj.com/lab/2012/github-chinese-develope/
资讯模块 列表模块_info.php_info.css_info.js
_list.php_list.css_list.js
条件过滤模块 _filter.php _filter.css _filter.js
两岸三地的开发者这回我们要加上模块依赖关系!
http://josephj.com/lab/2012/github-chinese-develope/
资讯模块 列表模块_info.php_info.css_info.js
_list.php_list.css_list.js
条件过滤模块 _filter.php _filter.css _filter.js
module,cookie
•module
• node-event-delegate• node-style
• node-screen • cache
• jsonp
• handlebars• event-resize
•cookie
•module
• node-base• handlebars
每个模块的组态设定不再維護類似 Mini 的頁面設定
每个模块的组态设定不再維護類似 Mini 的頁面設定
每个模块的组态设定
模块定义自身 JS 与 CSS 位置及依赖关系
不再維護類似 Mini 的頁面設定
指定此页面有哪些页面模块很直觉的指定方式
指定此页面有哪些页面模块很直觉的指定方式
指定此页面有哪些页面模块
不需知道背後的依賴模塊!只要指定页面模块移除也不需要担心影响别的模块
很直觉的指定方式
轻易将所有需要的设定与标签输出复杂的事情应该交给程式来做啊!
轻易将所有需要的设定与标签输出复杂的事情应该交给程式来做啊!
轻易将所有需要的设定与标签输出复杂的事情应该交给程式来做啊!
加载的方式十分优异
加载的方式十分优异
以传统方式加载种子与页面 CSS
加载的方式十分优异
分散並發的 JS 请求是自动计算依赖关系而生成
以传统方式加载种子与页面 CSS
未来开发可以完全专注在模块上
未来开发可以完全专注在模块上A. 通知讯息模块 (_notification)
模块开发者 A
模块名称 welcome/_notification
CSS 档案 welcome/_notification.css
JS 档案 welcome/_notification.js
相依模块 scroll-pagination, node-event-delegate, viewer
未来开发可以完全专注在模块上A. 通知讯息模块 (_notification)
模块开发者 A
B. 页首模块 (_masthead)
模块开发者 B
模块名称 welcome/_notification
CSS 档案 welcome/_notification.css
JS 档案 welcome/_notification.js
相依模块 scroll-pagination, node-event-delegate, viewer
模块名称 common/_masthead
CSS 档案 common/_masthead.css
JS 档案 common/_masthead.js
所需模块 panel, device-navigation
未来开发可以完全专注在模块上A. 通知讯息模块 (_notification)
模块开发者 A
B. 页首模块 (_masthead)
模块开发者 B
C. 侧边栏模块 (_sidebar)
模块开发者 C
模块名称 welcome/_notification
CSS 档案 welcome/_notification.css
JS 档案 welcome/_notification.js
相依模块 scroll-pagination, node-event-delegate, viewer
模块名称 common/_masthead
CSS 档案 common/_masthead.css
JS 档案 common/_masthead.js
所需模块 panel, device-navigation
模块名称 welcome/_sidebar
CSS 档案 welcome/_sidebar.css
JS 档案 無
所需模块 無
<?php ?>
最后再 Controller 指定页面模块即可
登入后首页 (welcome.php)页面开发者
最后再 Controller 指定页面模块即可
登入后首页 (welcome.php)页面开发者
此页面有以下模块:
·•welcome/_notification
·•charming/_masthead
·•common/_sidebar
回顧页层级设定所遭遇的困难
回顧页层级设定所遭遇的困难
· Build 效率问题不再 Build,由 Minify 在线上自动合并、压缩、版本控管。
回顧页层级设定所遭遇的困难
· Build 效率问题不再 Build,由 Minify 在线上自动合并、压缩、版本控管。
·线上除错问题原始档案皆存在,可以直接修正问题,只要把 Minify 对应的缓存砍掉即可
回顧页层级设定所遭遇的困难
· Build 效率问题不再 Build,由 Minify 在线上自动合并、压缩、版本控管。
·线上除错问题原始档案皆存在,可以直接修正问题,只要把 Minify 对应的缓存砍掉即可
·维护性问题開發者只定义自身模块的相依性、整页所需模塊由 YUI Loader 計算後自動載入,管理容易许多。
回顧页层级设定所遭遇的困难
· Build 效率问题不再 Build,由 Minify 在线上自动合并、压缩、版本控管。
·线上除错问题原始档案皆存在,可以直接修正问题,只要把 Minify 对应的缓存砍掉即可
·维护性问题開發者只定义自身模块的相依性、整页所需模塊由 YUI Loader 計算後自動載入,管理容易许多。
·共用的缓存问题除了全域共用采用 Minify 中的 groupConfig,其馀不处理、避免维护问题
结语
页层级的设置可想成「中央集权」设置容易。初期一目了然,但规模变大就管理不易。
结语
页层级的设置可想成「中央集权」设置容易。初期一目了然,但规模变大就管理不易。
模块层级設定则是「地方自治」设置较复杂、对长期维护较有效率。
配合相依性计算、自动合并、非同步下载等机制让页面模块真的做到随插即用
结语
结语
BigPipe 是很多网站想实作的目标
但首先你得「建立模块相依性」、「采用页面模块开发模式」
先建立模块导向开发模式才可能有实作的机会
鼓励较具规模的网站开始往这方向移动
结语
相关连结
·2010 建立前端开发团队 (http://www.slideshare.net/sdcc)
·跨模块沟通机制 (http://github.com/miiicasa/module)
·Mini 加载工具 (http://github.com/josephj/mini)
·模块加载机制 (http://github.com/josephj/static-loader)
·两岸三地的 GitHub 开发者 (http://github.com/josephj/github-chinese-develop)
·我的博客:这样做就对了 (http://josephj.com)
·我的 Email:[email protected]
今天看到的所有程式码或工具都是可分享的!
Questions?
miiiCasa家庭雲、建立家中的 SNS!
在北京工作的⼀一家人
miiiCasa家庭雲、建立家中的 SNS!
在北京工作的⼀一家人
在老家重慶的奶奶
miiiCasa家庭雲、建立家中的 SNS!
在北京工作的⼀一家人
在老家重慶的奶奶
位於家中、可存放照片的分享器
miiiCasa家庭雲、建立家中的 SNS!
在北京工作的⼀一家人
在老家重慶的奶奶
位於家中、可存放照片的分享器
互连网
miiiCasa家庭雲、建立家中的 SNS!
在北京工作的⼀一家人
在老家重慶的奶奶
想看孫女只要换个频道就可以了
位於家中、可存放照片的分享器
互连网