新萄京娱乐场.2959.com 17

致我们终将组件化的Web

致大家必定组件化的Web

2015/11/25 · HTML5 · 1
评论 ·
组件化

原版的书文出处:
AlloyTeam   

那篇小说将从两年前的一回技术争议起来。争执的聚焦正是下图的多少个目录分层结构。我说按模块划分好,他说你傻逼啊,当然是按能源划分。

新萄京娱乐场.2959.com 1 《=》新萄京娱乐场.2959.com 2

”按模块划分“目录结构,把当下模块下的全数逻辑和能源都放壹块了,那对于四人独自开荒和保证个人模块不是很好呢?当然了,那争辩的结果是自己婴儿地改回主流的”按能源划分“的目录结构。因为,未有到位JS模块化和资源模块化,仅仅物理地方上的模块划分是尚未意思的,只会增添构建的本金而已。

就算她说得好有道理笔者无言以对,可是自个儿心不甘,等待他多年来端组件化成熟了,再来世界第一次大战!

而前几天正是作者重申正义的生活!只是这时候丰盛跟你撕逼的人不在。

模块化的缺乏

模块壹般指可以单独拆分且通用的代码单元。由于JavaScript语言本人并未有内置的模块机制(ES六有了!!),大家1般会选用CMD或ADM建立起模块机制。以往多数稍稍大型一点的项目,都会动用requirejs或然seajs来促成JS的模块化。多个人分工合营开采,其个别定义依赖和暴光接口,维护功效模块间独立性,对于项目标费用功能和花色中期扩张和爱护,都以是有非常的大的扶植意义。

但,麻烦大家不怎么略读一下底下的代码

JavaScript

require([
‘Tmpl!../tmpl/list.html’,’lib/qqapi’,’module/position’,’module/refresh’,’module/page’,’module/net’
], function(listTmpl, QQapi, Position, Refresh, Page, NET){ var foo =
”, bar = []; QQapi.report(); Position.getLocaiton(function(data){
//… }); var init = function(){ bind();
NET.get(‘/cgi-bin/xxx/xxx’,function(data){ renderA(data.banner);
renderB(data.list); }); }; var processData = function(){ }; var bind =
function(){ }; var renderA = function(){ }; var renderB =
function(data){ listTmpl.render(‘#listContent’,processData(data)); };
var refresh = function(){ Page.refresh(); }; // app start init(); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
require([
    ‘Tmpl!../tmpl/list.html’,’lib/qqapi’,’module/position’,’module/refresh’,’module/page’,’module/net’
], function(listTmpl, QQapi, Position, Refresh, Page, NET){
    var foo = ”,
        bar = [];
    QQapi.report();
    Position.getLocaiton(function(data){
        //…
    });
    var init = function(){
        bind();
        NET.get(‘/cgi-bin/xxx/xxx’,function(data){
            renderA(data.banner);
            renderB(data.list);
        });
    };
    var processData = function(){
    };
    var bind = function(){
    };
    var renderA = function(){
    };
    var renderB = function(data){
        listTmpl.render(‘#listContent’,processData(data));
    };
    var refresh = function(){
        Page.refresh();
    };
    // app start
    init();
});

下边是具体有些页面的主js,已经封装了像Position,NET,Refresh等功效模块,但页面的主逻辑依然是”面向进度“的代码结构。所谓面向进度,是指遵照页面包车型地铁渲染进程来编排代码结构。像:init
-> getData -> processData -> bindevent -> report -> xxx

方法之间线性跳转,你大致也能感受那样代码弊端。随着页面逻辑更是复杂,那条”进程线“也会越来越长,并且越来越绕。加之缺少专业约束,其余项目成员遵照各自供给,在”进度线“加插各自逻辑,最后这些页面包车型大巴逻辑变得难以有限支撑。

新萄京娱乐场.2959.com 3

支付要求敬小慎微,生怕影响“进程线”后边符合规律逻辑。并且每便加插或修改都以bug泛滥,无不令产品有关人口无不提心吊胆。

 页面结构模块化

依照上面包车型地铁面向进程的标题,行行业内部也有无数消除方案,而我们集团也计算出1套成熟的消除方案:Abstractjs,页面结构模块化。我们能够把大家的页面想象为1个乐高机器人,要求不一样零件组装,如下图,如若页面划分为tabContainer,listContainer和imgsContainer多个模块。最后把这几个模块add到终极的pageModel里面,最终选取rock方法让页面运行起来。

新萄京娱乐场.2959.com 4
(原经过线示例图)

新萄京娱乐场.2959.com 5
(页面结构化示例图)

上面是伪代码的贯彻

JavaScript

require([
‘Tmpl!../tmpl/list.html’,’Tmpl!../tmpl/imgs.html’,’lib/qqapi’,’module/refresh’,’module/page’
], function(listTmpl, imgsTmpl, QQapi, Refresh, Page ){ var
tabContainer = new RenderModel({ renderContainer: ‘#tabWrap’, data: {},
renderTmpl: “<li soda-repeat=’item in
data.tabs’>{{item}}</li>”, event: function(){ // tab’s event }
}); var listContainer = new ScrollModel({ scrollEl: $.os.ios ?
$(‘#Page’) : window, renderContainer: ‘#listWrap’, renderTmpl:
listTmpl, cgiName: ‘/cgi-bin/index-list?num=一’, processData:
function(data) { //… }, event: function(){ // listElement’s event },
error: function(data) { Page.show(‘数据再次来到至极[‘ + data.retcode +
‘]’); } }); var imgsContainer = new renderModel({ renderContainer:
‘#imgsWrap’, renderTmpl: listTmpl, cgiName: ‘/cgi-bin/getPics’,
processData: function(data) { //… }, event: function(){ //
imgsElement’s event }, complete: function(data) { QQapi.report(); } });
var page = new PageModel();
page.add([tabContainer,listContainer,imgsContainer]); page.rock(); });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
require([
    ‘Tmpl!../tmpl/list.html’,’Tmpl!../tmpl/imgs.html’,’lib/qqapi’,’module/refresh’,’module/page’
], function(listTmpl, imgsTmpl, QQapi, Refresh, Page ){
 
    var tabContainer = new RenderModel({
        renderContainer: ‘#tabWrap’,
        data: {},
        renderTmpl: "<li soda-repeat=’item in data.tabs’>{{item}}</li>",
        event: function(){
            // tab’s event
        }
    });
 
    var listContainer = new ScrollModel({
        scrollEl: $.os.ios ? $(‘#Page’) : window,
        renderContainer: ‘#listWrap’,
        renderTmpl: listTmpl,
        cgiName: ‘/cgi-bin/index-list?num=1’,
        processData: function(data) {
            //…
        },
        event: function(){
            // listElement’s event
        },
        error: function(data) {
            Page.show(‘数据返回异常[‘ + data.retcode + ‘]’);
        }
    });
 
    var imgsContainer = new renderModel({
        renderContainer: ‘#imgsWrap’,
        renderTmpl: listTmpl,
        cgiName: ‘/cgi-bin/getPics’,
        processData: function(data) {
            //…
        },
        event: function(){
            // imgsElement’s event
        },
        complete: function(data) {
           QQapi.report();
        }
    });
 
    var page = new PageModel();
    page.add([tabContainer,listContainer,imgsContainer]);
    page.rock();
 
});

咱俩把那些常用的央求CGI,处理多少,事件绑定,上报,容错处理等一层层逻辑格局,以页面块为单位封装成三个Model模块。

那样的一个空洞层Model,大家得以清楚地来看该页面块,请求的CGI是怎样,绑定了何等风云,做了什么上报,出错怎么处理。新增的代码就应有放置在相应的模块上相应的处境方法(preload,process,event,complete…),杜绝了过去的无规则乱增代码的编慕与著述。并且,遵照不一样工作逻辑封装区别类别的Model,如列表滚动的ScrollModel,滑块作用的SliderModel等等,能够开展中度封装,集中优化。

今日依照Model的页面结构开垦,已经包罗一点”组件化“的意味。各种Model都含有各自的数额,模板,逻辑。已经算是3个完好的功用单元。但离开真正的WebComponent照旧有1段距离,至少满意不断小编的”理想目录结构“。

 WebComponents 标准

咱俩想起一下行使2个datapicker的jquery的插件,所急需的步奏:

  1. 引进插件js

  2. 引进插件所需的css(借使有)

  3. copy 组件的所需的html片段

  4. 丰裕代码触发组件运行

日前的“组件”基本上只好达到是有个别成效单元上的聚众。他的能源都以松散地分散在三种资源文件中,而且组件成效域揭发在大局意义域下,缺少内聚性很轻易就会跟别的零件产生争论,如最简便易行的css命名争持。对于那种“组件”,还不比上面包车型地铁页面结构模块化。

于是乎W3C按耐不住了,制定二个WebComponents标准,为组件化的前景教导了明路。

下边以较为轻便的方法介绍这份正经,力求大家能够相当慢精晓达成组件化的剧情。(对那壹部分打探的同室,能够跳过这一小节)

一. <template>模板能力

模板那东西交大学家最纯熟可是了,二零一八年见的较多的模板品质大战artTemplate,juicer,tmpl,underscoretemplate等等。而前天又有mustachejs无逻辑模板引擎等新入选手。可是我们有未有想过,这么基础的能力,原生HTML⑤是不协助的(T_T)。

最近天WebComponent将要提供原生的模板能力

XHTML

<template id=”datapcikerTmpl”>
<div>我是原生的沙盘</div> </template>

1
2
3
<template id="datapcikerTmpl">
<div>我是原生的模板</div>
</template>

template标签内定义了myTmpl的沙盘,须求利用的时候将要innerHTML= document.querySelector('#myTmpl').content;能够看看这一个原生的沙盘够原始,模板占位符等效果都不曾,对于动态数据渲染模板能力只能自力更新。

二. ShadowDom 封装组件独立的内部结构

ShadowDom能够驾驭为壹份有单独功能域的html片段。那几个html片段的CSS环境和主文书档案隔绝的,各自笔者保护持内部的独立性。也多亏ShadowDom的单独个性,使得组件化成为了只怕。

JavaScript

var wrap = document.querySelector(‘#wrap’); var shadow =
wrap.createShadowRoot(); shadow.innerHTML = ‘<p>you can not see me
</p>’

1
2
3
var wrap = document.querySelector(‘#wrap’);
var shadow = wrap.createShadowRoot();
shadow.innerHTML = ‘<p>you can not see me </p>’

在实际dom节点上选拔createShadowRoot方法就能够生成其ShadowDom。就像是在整份Html的房间里面,新建了3个shadow的屋子。房间外的人都不明了房间内有哪些,保持shadowDom的独立性。

叁. 自定义原生标签

第二接触Angularjs的directive指令功用,设定好组件的逻辑后,一个<Datepicker
/>就能引进整个组件。如此狂炫耀炸碉堡天的成效,实在令人拍手叫好,跃地三尺。

JavaScript

var tmpl = document.querySelector(‘#datapickerTmpl’); var
datapickerProto = Object.create(HTMLElement.prototype); //
设置把大家模板内容大家的shadowDom datapickerProto.createdCallback =
function() { var root = this.createShadowRoot();
root.appendChild(document.importNode(tmpl.content, true)); }; var
datapicker = docuemnt.registerElement(‘datapicker’,{ prototype:
datapickerProto });

1
2
3
4
5
6
7
8
9
10
11
12
var tmpl = document.querySelector(‘#datapickerTmpl’);
var datapickerProto = Object.create(HTMLElement.prototype);
 
// 设置把我们模板内容我们的shadowDom
datapickerProto.createdCallback = function() {
    var root = this.createShadowRoot();
    root.appendChild(document.importNode(tmpl.content, true));
};
 
var datapicker = docuemnt.registerElement(‘datapicker’,{
    prototype: datapickerProto
});

Object.create格局持续HTMLElement.prototype,得到贰个新的prototype。当解析器发现大家在文书档案中标记它将检查是还是不是二个名叫createdCallback的诀窍。假使找到那几个措施它将及时运转它,所以大家把克隆模板的内容来创制的ShadowDom。

最后,registerElement的方法传递大家的prototype来注册自定义标签。

上面的代码开端略显复杂了,把前边多个力量“模板”“shadowDom”结合,形成组件的在那之中逻辑。最终经过registerElement的措施注册组件。之后能够手舞足蹈地<datapicker></datapicker>的选拔。

四. imports化解组件间的依赖

XHTML

<link rel=”import” href=”datapciker.html”>

1
<link rel="import" href="datapciker.html">

这几个类php最常用的html导入功用,HTML原生也能支撑了。

WebComponents标准内容大概到此地,是的,笔者那边未有何德姆o,也并没有实践经验分享。由于webComponents新特征,基本三巳了高版本的Chrome帮衬外,别的浏览器的支撑度甚少。纵然有polymer扶助拉动webcompoents的仓库储存在,不过polymer本身的渴求版本也是可怜高(IE10+)。所以明天的顶梁柱并不是她。

大家简要来回想一下WebCompoents的肆部分机能:

一 .<template>定义组件的HTML模板能力

  1. Shadow Dom封装组件的内部结构,并且保持其独立性

  2. Custom Element 对外提供组件的标签,实现自定义标签

  3. import化解组件结合和依靠加载

 组件化实践方案

法定的正式看完了,大家思虑一下。1份真正成熟笃定的组件化方案,须求具备的力量。

“财富高内聚”—— 组件财富内部高内聚,组件能源由本人加载控制

“成效域独立”—— 内部结构密封,不与全局或任何零件发生震慑

“自定义标签”—— 定义组件的选拔方式

“可交互结合”—— 组件正在有力的地方,组件间组装整合

“接口规范化”—— 组件接口有统一规范,或然是生命周期的军管

村办觉得,模板能力是基础能力,跟是或不是组件化未有强联系,所以并未有提议一个大点。

既然如此是进行,现阶段WebComponent的匡助度还不成熟,不能够作为方案的手腕。而除此以外一套以高质量虚拟Dom为切入点的组件框架React,在facebook的造势下,社区获取了大力发展。其它一名骨干Webpack,负责化解组件能源内聚,同时跟React万分切合形成互补。

所以【Webpack】+【React】将会是那套方案的焦点技术。

不清楚您今后是“又是react+webpack”感到失望新萄京娱乐场.2959.com 6,依然“太好了是react+webpack”不用再学三遍新框架的快乐新萄京娱乐场.2959.com 7。无论怎么样下边包车型客车始末不会让您失望的。

壹,组件生命周期

新萄京娱乐场.2959.com 8

React天生正是强制性组件化的,所以能够从根天性上消除面向进程代码所推动的难为。React组件本身有生命周期方法,能够满意“接口规范化”能力点。并且跟“页面结构模块化”的所封装抽离的多少个艺术能挨个对应。其余react的jsx自带模板功用,把html页面片直接写在render方法内,组件内聚性尤其严苛。

出于React编写的JSX是会先生成虚拟Dom的,要求时机才真正插入到Dom树。使用React必供给驾驭组件的生命周期,其生命周期三个状态:

Mount: 插入Dom

Update: 更新Dom

Unmount: 拔出Dom

mount那单词翻译扩充,嵌入等。我倒是建议“插入”更加好掌握。插入!拔出!插入!拔出!默念3次,懂了没?别少看黄段子的能力,

新萄京娱乐场.2959.com 9

零件状态正是: 插入-> 更新 ->拔出。

然后每一种组件状态会有两种处理函数,壹前1后,will函数和did函数。

componentWillMount()  准备插入前

componentDidlMount()  插入后

componentWillUpdate() 准备更新前

componentDidUpdate()  更新后

componentWillUnmount() 准备拔出前

因为拔出后基本都以贤者形态(作者说的是组件),所以并没有DidUnmount这几个方法。

除此以外React其它三个基本:数据模型props和state,对应着也有自个状态方法

getInitialState()     获取初始化state。

getDefaultProps() 获取暗许props。对于那个没有父组件传递的props,通过该办法设置暗中认可的props

componentWillReceiveProps()  已插入的机件收到新的props时调用

还有1个新鲜意况的处理函数,用于优化处理

shouldComponentUpdate():判断组件是或不是要求update调用

累加最重点的render方法,React本人带的方法刚刚好1一个。对于初学者的话是比较为难消化。但骨子里getInitialStatecomponentDidMountrender多少个情形方法都能成功大多数组件,不必惧怕。

再次回到组件化的核心。

三个页面结构模块化的组件,能独立包装整个组件的进度线

新萄京娱乐场.2959.com 10

我们换算成React生命周期方法:

新萄京娱乐场.2959.com 11

 

组件的状态方法流中,有两点要求新鲜表达:

1,二回渲染:

鉴于React的虚构Dom本性,组件的render函数不需协调触发,根据props和state的变动自个通过差别算法,得出最优的渲染。

伸手CGI1般都是异步,所以自然带来一回渲染。只是空数据渲染的时候,有望会被React优化掉。当数码回来,通过setState,触发一遍render

 

2,componentWiillMount与componentDidMount的差别

和超越5分之3React的课程文章不均等,ajax请求笔者指出在威尔Mount的点子内进行,而不是组件早先化成功现在的DidMount。那样能在“空数据渲染”阶段在此以前请求数据,尽早地缩减一遍渲染的时光。

willMount只会执行2回,万分适合做init的事情。

didMount也只会履行2次,并且那时候真实的Dom已经形成,格外适合事件绑定和complete类的逻辑。

 

 2,JSX极难看,不过组件内聚的严重性!

WebComponents的正式之一,需求模板能力。本是认为是我们耳熟能详的模版能力,但React中的JSX那样的怪人如故让人议论纷纭。React还一直不火起来的时候,我们就曾经在天涯论坛上尖锐地捉弄了“JSX写的代码那TM的丑”。那实在只是德姆o阶段JSX,等到实战的大型项目中的JSX,包蕴多处境多数据多事件的时候,你会意识………….JSX写的代码还是极难看。

新萄京娱乐场.2959.com 12
(固然用sublime-babel等插件高亮,逻辑和渲染耦合壹起,阅读性还是略差)

干什么大家会以为丑?因为我们已经经对“视图-样式-逻辑”分离的做法潜移默化。

依照维护性和可读性,甚至质量,大家都不建议直接在Dom上面绑定事件仍旧直接写style属性。大家会在JS写事件代理,在CSS上写上classname,html上的正是明显的Dom结构。大家很好地保障着MVC的设计形式,壹切安好。直到JSX把她们都夹杂在协同,所守护的技术栈受到入侵,难免有着抗拒。

 

只是从组件化的指标来看,那种高内聚的做法未尝不可。

上边包车型大巴代码,在此之前的“逻辑视图分离”格局,我们须求去找相应的js文件,相应的event函数体内,找到td-info的class所绑定的风云。

相对而言起JSX的万丈内聚,全体事件逻辑正是在笔者jsx文件内,绑定的正是自个儿的showInfo方法。组件化的性状能立时浮现出来。

(注意:就算写法上我们好像是HTML的内联事件处理器,不过在React底层并未实际赋值类似onClick属性,内层照旧采用类似事件代理的不二秘籍,高效地体贴着事件处理器)

再来看1段style的jsx。其实jsx未有对体制有硬性规定,大家完全可遵守在此之前的定义class的逻辑。任何壹段样式都应当用class来定义。在jsx你也全然能够如此做。可是由于组件的独立性,作者提议部分只有“二回性”的样式直接利用style赋值越来越好。减弱冗余的class。

XHTML

<div className=”list” style={{background: “#ddd”}}> {list_html}
</div>

1
2
3
<div className="list" style={{background: "#ddd"}}>
   {list_html}
</div>

或许JSX内部有担当繁琐的逻辑样式,可JSX的自定义标签能力,组件的黑盒性立马能体会出来,是还是不是1念之差美好了重重。

JavaScript

render: function(){ return ( <div> <Menus
bannerNums={this.state.list.length}></Menus> <TableList
data={this.state.list}></TableList> </div> ); }

1
2
3
4
5
6
7
8
render: function(){
    return (
      <div>
         <Menus bannerNums={this.state.list.length}></Menus>
         <TableList data={this.state.list}></TableList>
      </div>
   );
}

虽说JSX本质上是为着虚拟Dom而准备的,但那种逻辑和视图中度合壹对于组件化未尝不是一件善事。

 

上学完React那么些组件化框架后,看看组件化能力点的到位情形

“能源高内聚”—— (3三%)  html与js内聚

“成效域独立”—— (二分一)  js的成效域独立

“自定义标签”—— (百分之百)jsx

“可互相结合”—— (5/10)  可整合,但贫乏有效的加载格局

“接口规范化”—— (百分之百)组件生命周期方法

 

Webpack 财富组件化

对此组件化的能源独立性,一般的模块加载工具和构建流程视乎变得劳累。组件化的创设筑工程程化,不再是从前大家广阔的,css合二,js合叁,而是体验在组件间的信赖于加载关系。webpack正好适合须要点,一方面填补组件化能力点,另1方扶助大家周详组件化的总体创设环境。

第3要表澳优点是,webpack是3个模块加载打包工具,用于管理你的模块能源依赖打包难点。那跟我们耳熟能详的requirejs模块加载工具,和grunt/gulp营造筑工程具的定义,多多少少有个别出入又有点雷同。

新萄京娱乐场.2959.com 13

第3webpak对于CommonJS与英特尔同时协理,满意大家模块/组件的加载方式。

JavaScript

require(“module”); require(“../file.js”); exports.doStuff = function()
{}; module.exports = someValue;

1
2
3
4
require("module");
require("../file.js");
exports.doStuff = function() {};
module.exports = someValue;

JavaScript

define(“mymodule”, [“dep1”, “dep2”], function(d1, d2) { return
someExportedValue; });

1
2
3
define("mymodule", ["dep1", "dep2"], function(d1, d2) {
    return someExportedValue;
});

理所当然最有力的,最卓绝的,当然是模块打包成效。那多亏那一功力,补充了组件化能源依赖,以及完整工程化的能力

基于webpack的筹划理念,全数财富都以“模块”,webpack内部贯彻了1套财富加运载飞机制,能够把想css,图片等财富等有依靠关系的“模块”加载。那跟大家使用requirejs那种只有处理js大大区别。而那套加运载飞机制,通过一个个loader来完成。

 

JavaScript

// webpack.config.js module.exports = { entry: { entry: ‘./index.jsx’,
}, output: { path: __dirname, filename: ‘[name].min.js’ }, module:
{ loaders: [ {test: /\.css$/, loader: ‘style!css’ }, {test:
/\.(jsx|js)?$/, loader: ‘jsx?harmony’, exclude: /node_modules/},
{test: /\.(png|jpg|jpeg)$/, loader: ‘url-loader?limit=10240’} ] } };

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// webpack.config.js
module.exports = {
    entry: {
     entry: ‘./index.jsx’,
    },
    output: {
        path: __dirname,
        filename: ‘[name].min.js’
    },
    module: {
        loaders: [
            {test: /\.css$/, loader: ‘style!css’ },
            {test: /\.(jsx|js)?$/, loader: ‘jsx?harmony’, exclude: /node_modules/},
            {test: /\.(png|jpg|jpeg)$/, loader: ‘url-loader?limit=10240’}
        ]
    }
};

上边一份轻便的webpack配置文件,留意loaders的布局,数组内1个object配置为一种模块财富的加运载飞机制。test的正则为同盟文件规则,loader的为相配到文件将由哪些加载器处理,八个总括机之间用相隔,处理顺序从右到左。

 

style!css,css文件通过css-loader(处理css),再到style-loader(inline到html)的加工处理流。

jsx文件通过jsx-loader编写翻译,‘?’开启加载参数,harmony帮衬ES陆的语法。

图片财富通过url-loader加载器,配置参数limit,控制少于十KB的图样将会base6四化。

 能源文件怎样被require?

JavaScript

// 加载组件自个儿css require(‘./slider.css’); // 加载组件正视的模块 var
Clip = require(‘./clipitem.js’); // 加载图片财富 var spinnerImg =
require(‘./loading.png’);

1
2
3
4
5
6
// 加载组件自身css
require(‘./slider.css’);
// 加载组件依赖的模块
var Clip = require(‘./clipitem.js’);
// 加载图片资源
var spinnerImg = require(‘./loading.png’);

在webpack的js文件中大家除了require大家如常的js文件,css和png等静态文件也能够被require进来。大家由此webpack命令,编写翻译之后,看看输出结果什么:

JavaScript

webpackJsonp([0], { /* 0 */ /***/ function(module, exports,
__webpack_require__) { // 加载组件本人css
__webpack_require__(1); // 加载组件信赖的模块 var Clip =
__webpack_require__(伍); // 加载图片能源 var spinnerImg =
__webpack_require__(6); /***/ }, /* 1 */ /***/
function(module, exports, __webpack_require__) { /***/ }, /* 2
*/ /***/ function(module, exports, __webpack_require__) {
exports = module.exports = __webpack_require__(3)();
exports.push([module.id, “.slider-wrap{\r\n position: relative;\r\n
width: 100%;\r\n margin: 50px;\r\n background:
#fff;\r\n}\r\n\r\n.slider-wrap li{\r\n text-align:
center;\r\n line-height: 20px;\r\n}”, “”]); /***/ }, /* 3 */
/***/ function(module, exports) { /***/ }, /* 4 *新萄京娱乐场.2959.com ,/ /***/
function(module, exports, __webpack_require__) { /***/ }, /* 5
*/ /***/ function(module, exports) { console.log(‘hello, here is
clipitem.js’) ; /***/ }, /* 6 */ /***/ function(module, exports)
{ module.exports = “data:image/png;base64,iVBORw0KGg……” /***/ }
]);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
webpackJsonp([0], {
/* 0 */
/***/ function(module, exports, __webpack_require__) {
          // 加载组件自身css
          __webpack_require__(1);
          // 加载组件依赖的模块
          var Clip = __webpack_require__(5);
          // 加载图片资源
          var spinnerImg = __webpack_require__(6);
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
 
/***/ },
/* 2 */
/***/ function(module, exports, __webpack_require__) {
          exports = module.exports = __webpack_require__(3)();
          exports.push([module.id, ".slider-wrap{\r\n position: relative;\r\n width: 100%;\r\n margin: 50px;\r\n background: #fff;\r\n}\r\n\r\n.slider-wrap li{\r\n text-align: center;\r\n line-height: 20px;\r\n}", ""]);
 
/***/ },
/* 3 */
/***/ function(module, exports) {
 
/***/ },
 
/* 4 */
/***/ function(module, exports, __webpack_require__) {
/***/ },
 
/* 5 */
/***/ function(module, exports) {
          console.log(‘hello, here is clipitem.js’) ;
/***/ },
/* 6 */
/***/ function(module, exports) {
          module.exports = "data:image/png;base64,iVBORw0KGg……"
/***/ }
]);

webpack编译之后,输出文件视乎乱糟糟的,但实际每3个能源都被封装在多个函数体内,并且以编号的款型标记(注释)。这么些模块,由webpack的__webpack_require__里头方法加载。入口文件为编号0的函数index.js,能够看来__webpack_require__加载别的编号的模块。

css文件在号码一,由于采用css-loader和style-loader,编号一-4都以处理css。在那之中编号二我们能够看大家的css的string体。最后会以内联的方法插入到html中。

图形文件在号码陆,能够看出exports出base64化的图样。

 组件一体输出

JavaScript

// 加载组件本人css require(‘./slider.css’); // 加载组件依赖的模块 var
React = require(‘react’); var Clip = require(‘../ui/clipitem.jsx’); //
加载图片能源 var spinnerImg = require(‘./loading.png’); var Slider =
React.createClass({ getInitialState: function() { // … },
componentDidMount: function(){ // … }, render: function() { return (
<div> <Clip data={this.props.imgs} /> <img
className=”loading” src={spinnerImg} /> </div> ); } });
module.exports = Slider;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 加载组件自身css
require(‘./slider.css’);
// 加载组件依赖的模块
var React = require(‘react’);
var Clip = require(‘../ui/clipitem.jsx’);
// 加载图片资源
var spinnerImg = require(‘./loading.png’);
var Slider = React.createClass({
    getInitialState: function() {
        // …
    },
    componentDidMount: function(){
        // …
    },
    render: function() {
        return (
            <div>
               <Clip data={this.props.imgs} />
               <img className="loading" src={spinnerImg} />
            </div>
        );
    }
});
module.exports = Slider;

要是说,react使到html和js合为1体。

那便是说充裕webpack,两者结合壹起的话。js,css,png(base6四),html
全数web能源都能合成2个JS文件。那多亏那套方案的为主所在:零件独立1体化。假设要引用三个组件,仅仅require('./slider.js') 就能够完成。

 

加盟webpack的模块加载器之后,大家组件的加载难点,内聚难点也都成功地消除掉

“能源高内聚”—— (百分百) 全体财富得以一js输出

“可相互结合”—— (百分之百)  可组合可凭借加载

 

 CSS模块化实践

很欢愉,你能阅读到此处。方今大家的零部件完结度12分的高,财富内聚,易于组合,功效域独立互不污染。。。。等等新萄京娱乐场.2959.com 14,视乎CSS模块的完毕度有不足。

那正是说方今组件完结度来看,CSS效用域其实是全局性的,并非组件内部独立。下一步,大家要做得正是什么样让我们组件内部的CSS功效域独立。

那儿或者有人马上跳出,大喊一句“德玛西亚!”,哦不,应该是“用sass啊傻逼!”。不过品种组件化之后,组件的内部封装已经很好了,其内部dom结构和css趋向简单,独立,甚至是破碎的。LESS和SASS的一体式样式框架的规划,他的嵌套,变量,include,函数等丰裕的成效对于全体大型项指标体制管理拾贰分有效。但对于一个成效单壹组件内部样式,视乎就变的有点争持。“无法为了框架而框架,合适才是最棒的”。视乎原生的css能力已经知足组件的体裁需要,唯独正是下边的css成效域难点。

 

那边小编付出思量的方案:
classname随便写,保持原生的法子。编写翻译阶段,依据组件在项目路线的唯1性,由【组件classname+组件唯1途径】打成md5,生成全局唯1性classname。正当笔者要写二个loader达成本身的想法的时候,发现歪果仁已经早在先走一步了。。。。

那里具体方案参考小编此前博客的译文:

事先大家谈论过JS的模块。以后透过Webpack被加载的CSS财富叫做“CSS模块”?笔者觉着照旧有标题标。未来style-loader插件的兑现精神上只是创建link[rel=stylesheet]要素插入到document中。那种表现和平时引进JS模块格外例外。引进另贰个JS模块是调用它所提供的接口,但引进一个CSS却并不“调用”CSS。所以引进CSS自身对于JS程序来说并不存在“模块化”意义,纯粹只是表明了一种能源依赖——即该器件所要完成的功用还亟需一些asset。

所以,这位歪果仁还扩充了“CSS模块化”的定义,除了上边的大家要求有的成效域外,还有不少效用,那里不详述。具体参考原作 

丰盛赞的一点,正是cssmodules已经被css-loader收纳。所以大家不须要依赖额外的loader,基本的css-loader开启参数modules就能够

JavaScript

//webpack.config.js … module: { loaders: [ {test: /\.css$/, loader:
‘style!css?modules&localIdentName=[local]__[name]_[hash:base64:5]’
}, ] } ….

1
2
3
4
5
6
7
8
//webpack.config.js
…  
    module: {
        loaders: [
            {test: /\.css$/, loader: ‘style!css?modules&localIdentName=[local]__[name]_[hash:base64:5]’ },
        ]  
    }
….

modules参数代表开启css-modules功能,loaclIdentName为设置我们编译后的css名字,为了便于debug,我们把classname(local)和零部件名字(name)输出。当然能够在最终输出的本子为了节约提交,仅仅使用hash值就可以。此外在react中的用法差不多如下。

JavaScript

var styles = require(‘./banner.css’); var Banner = new
React.createClass({ … render: function(){ return ( <div> <div
className={styles.classA}></div> </div> ) } });

1
2
3
4
5
6
7
8
9
10
11
var styles = require(‘./banner.css’);
var Banner = new React.createClass({
    …
    render: function(){
        return (
            <div>
                <div className={styles.classA}></div>
            </div>
        )
    }
});

最终那里关于出于对CSS一些心想,

关于css-modules的别的功效,小编并不打算采纳。在个中分享【大家竭尽所能地让CSS变得复杂】中提起:

大家项目中山大学部的CSS都不会像boostrap那样需求变量来设置,身为壹线开采者的大家大体能够感受到:设计师们改版UI,相对不是简简单单的换个色或改个间距,而是面目一新的全新UI,那相对不是1个变量所能解决的”维护性“。

反倒项目实战进程中,真正要化解的是:在本子迭代进度中那一个淘汰掉的逾期CSS,大量地堆放在品种个中。我们像极了家中的欧巴酱不舍得丢掉没用的东西,因为那可是我们运用sass或less编写出具有莫斯中国科学技术大学学的可维护性的,肯定有复用的1天。

那一个堆积的晚点CSS(or
sass)之间又有一些正视,1部分过期失效了,壹部分又被新的体制复用了,导致没人敢动这个历史样式。结果现网项目迭代还带着大批量两年前没用的样式文件。

组件化之后,css的格局同样被改动了。大概postcss才是你今后手上最适合的工具,而不在是sass。

 

到那边,大家到底把组件化最终3个难点也解决了。

“效用域独立”—— (百分之百) 就好像shadowDom功用域独立

 

到此处,我们能够开一瓶8二年的Pepsi-Cola,好好庆祝一下。不是吗?

新萄京娱乐场.2959.com 15

 

 组件化之路还在三番五次

webpack和react还有好多新格外重大的性状和意义,介于本文仅仅围绕着组件化的为大旨,没有各类演说。别的,配搭gulp/grunt补充webpack创设能力,webpack的codeSplitting,react的零件通讯难点,开荒与生产条件安排等等,都以成套大型项目方案的所必须的,限于篇幅难点。能够等等笔者更新下篇,或大家可以自动查阅。

可是,不得不再安利一下react-hotloader神器。热加载的支出格局相对是下一代前端开辟必备。严厉说,如若未有了热加载,笔者会很泼辣地抛弃那套方案,尽管那套方案再怎么好好,小编都讨厌react须求五~陆s的编写翻译时间。可是hotloader能够在自身不刷新页面包车型客车景观下,动态修改代码,而且不单单是样式,连逻辑也是即时生效。

新萄京娱乐场.2959.com 16

如上在form表单内。使用热加载,表单不需求再度填写,修改submit的逻辑马上见效。这样的支出功用真不是升高仅仅二个程度。必须安利一下。

 

莫不你意识,使用组件化方案现在,整个技术栈都被更新了一番。学习开销也不少,并且可以预言到,基于组件化的前端还会过多相差的难点,例如品质优化方案须要再次思量,甚至最大旨的零件可复用性不自然高。前面非常长一段时间,供给咱们不住锻练与优化,研究最优的前端组件化之道。

最少我们得以想象,不再担心自身写的代码跟有个别什么人哪个人顶牛,不再为找某段逻辑在多少个公文和方式间不停,不再copy一片片逻辑然后改改。大家每一趟编写都以可选拔,可结合,独立且内聚的组件。而各种页面将会由二个个嵌套组合的零部件,彼此独立却互相作用。

 

对于那样的前端未来,有所期待,不是很行吗

至此,谢谢你的开卷。

1 赞 6 收藏 1
评论

新萄京娱乐场.2959.com 17

一、什么是webpack:webpack是一款模块加载兼打包工具,它可以将js、jsx、coffee、样式sass、less,图片等作为模块来采用和拍卖。
2、优势:1、以commonJS的样式来书写脚本,对速龙、CMD的帮助也很完美,方便旧项指标动员搬迁。贰、能被模块化的接连不断是JS了。3、能代替部分grunt/gulp的工作,例如打包,压缩混淆,图片转base6四等。叁、扩大性强,插件机制完善,扶助React热拔插(react-hot-loader)
三、安装和布置:
1、安装:直接利用npm来进展安装
$ npm install webpack -g
将借助写入package.json包
$ npm init
$ npm install webpack –save-dev
2、配置:
各种体系必须配备一个webpack.config.js,作用仿佛gulpfile.js/Gruntfile.js,1个布局项,告诉webpack要做哪些。
示例:
var webpack = require(‘webpack’);
var commonsPlugin = new
webpack.optimize.CommonsChunkPlugin(‘common.js’);
module.exports = {
//插件项
plugins: [commonsPlugin],
//页面入口文件配置
entry: {
index : ‘./src/js/page/index.js’
},
//入口文件输出配置
output: {
path: ‘dist/js/page’,
filename: ‘[name].js’
},
module: {
//加载器配置
loaders: [
{ test: /.css$/, loader: ‘style-loader!css-loader’ },
{ test: /.js$/, loader: ‘jsx-loader?harmony’ },
{ test: /.scss$/, loader: ‘style!css!sass?sourceMap’},
{ test: /.(png|jpg)$/, loader: ‘url-loader?limit=8192’}
]
},
//其它化解方案布署
resolve: {
root: ‘E:/github/flux-example/src’, //绝对路线
extensions: [”, ‘.js’, ‘.json’, ‘.scss’],
alias: {
AppStore : ‘js/stores/AppStores.js’,
ActionType : ‘js/actions/ActionType.js’,
AppAction : ‘js/actions/AppAction.js’
}
}
};
(1)plugins是插件项,那里运用了二个CommonsChunkPlugin的插件,它用于提取八个入口文件的共用脚本有的,然后生成2个common.js来方便多页面之间的复用。
(二)entry是页面包车型客车进口文件配置,output是应和的输出项配置
{
entry: {
page1: “./page1”,
//支持数组格局,将加载数组中的全体模块,但以最终二个模块作为出口
page2: [“./entry1”, “./entry2”]
},
output: {
path: “dist/js/page”,
filename: “[name].bundle.js”
}
}
该代码会生成八个page1.bundle.js和page贰.bundle.js,并存放在./dist/js/page文件夹下。
(3)module.loaders,告知webpack每1种文件都亟需哪些加载器来处理
module: {
//加载器配置
loaders: [
//.css 文件使用 style-loader 和 css-loader 来处理
{ test: /.css$/, loader: ‘style-loader!css-loader’ },
//.js 文件使用 jsx-loader 来编写翻译处理
{ test: /.js$/, loader: ‘jsx-loader?harmony’ },
//.scss 文件使用 style-loader、css-loader 和 sass-loader 来编写翻译处理
{ test: /.scss$/, loader: ‘style!css!sass?sourceMap’},
//图片文件使用 url-loader 来拍卖,小于8kb的向来转为base6四
{ test: /.(png|jpg)$/, loader: ‘url-loader?limit=8192’}
]
}
-loader能够不写,三个loader之间用“!”连接起来。全部的加载器都急需通过npm来加载。
譬如说最终3个url-loader,它会将样式中援引到的图片转为模块来拍卖。使用前开始展览设置:
$ npm install url-loader -save-dev
配备音讯的参数:“?limit=81九二”表示将具有小于捌kb的图纸都转为base6四情势(抢先八kb的才使用url-loader来映射到文件,不然转为data
url格局)
(4)resolve配置,
resolve: {
//查找module的话从那里开首查找
root: ‘E:/github/flux-example/src’, //相对路线
//自动扩充文件后缀名,意味着大家require模块可以简轻松单不写后缀名
extensions: [”, ‘.js’, ‘.json’, ‘.scss’],
//模块小名定义,方便后续直接引用小名,无须多写长长的地址
alias: {
AppStore : ‘js/stores/AppStores.js’,//后续直接 require(‘AppStore’)
就能够
ActionType : ‘js/actions/ActionType.js’,
AppAction : ‘js/actions/AppAction.js’
}
}
4、运营webpack,直接实施:
$ webpack –display-error-details
末端的参数
“-display-error-details”推荐加上,方便出错开上下班时间能通晓到更详实的音信。别的主要参数:
$ webpack –config XXX.js
//使用另一份配置文件(比如webpack.config二.js)来打包
$ webpack –watch //监听变动并活动打包
$ webpack -p //压缩混淆脚本,这几个那些特别主要!
$ webpack -d //生成map映射文件,告知哪些模块被最终包装到哪个地方了
-p是很主要的参数,曾经1个未压缩的 700kb 的文书,压缩后一向降到
180kb(主假若样式那块一句就把持一行脚本,导致未压缩脚本变得非常的大)。
5、模块引入:
一、在HTML页面引进:引进webpack最后生成的台本就能够:
<!DOCTYPE html>
<html>
<head lang=”en”>
<meta charset=”UTF-8″>
<title>demo</title>
</head>
<body>
<script src=”dist/js/page/common.js”></script>
<script src=”dist/js/page/index.js”></script>
</body>
</html>
能够见到我们连样式都无须引进,究竟脚本执行时会动态生成style并标签打到head里。
二、JS引进:各脚本模块能够应用common.js来书写,并能够间接引进未经编写翻译的模块,比如:jsx,coffee,sass,只要在webpack.config.js中布局好了相应的加载器就行。
编写翻译页面包车型客车输入文件:
require(‘../../css/reset.scss’); //加载起初化样式
require(‘../../css/allComponent.scss’); //加载组件样式
var React = require(‘react’);
var AppWrap = require(‘../component/AppWrap’); //加载组件
var createRedux = require(‘redux’).createRedux;
var Provider = require(‘redux/react’).Provider;
var stores = require(‘AppStore’);
var redux = createRedux(stores);
var App = React.createClass({
render: function() {
return (
<Provider redux={redux}>
{function() { return <AppWrap />; }}
</Provider>
);
}
});
React.render(
<App />, document.body
);

发表评论

电子邮件地址不会被公开。 必填项已用*标注