致大家一定会将组件化的Web

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

原稿出处:
AlloyTeam   

那篇小说将从两年前的一回能力纠纷起来。争论的聚集正是下图的七个目录分层构造。小编说按模块划分好,他说你傻逼啊,当然是按能源划分。

图片 1 《=》图片 2

”按模块划分“目录布局,把当前模块下的全部逻辑和能源都放一块了,那对于四人独立开垦和有限援助个人模块不是很好呢?当然了,那争辩的结果是自己婴儿地改回主流的”按能源划分“的目录构造。因为,未有产生JS模块化和能源模块化,仅仅物理地方上的模块划分是还未意思的,只会追加创设的资本而已。

即使他说得好有道理笔者无话可说,但是本身心不甘,等待她如今端组件化成熟了,再来世界第一回大战!

这几天天便是自身频频正义的光阴!只是那个时候不行跟你撕逼的人不在。

模块化的欠缺

模块一般指能够独立拆分且通用的代码单元。由于JavaScript语言本人未有内置的模块机制(ES6有了!!),大家日常会使用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

方法之间线性跳转,你大致也能体会那样代码缺陷。随着页面逻辑更是复杂,那条”进程线“也会非常长,并且越来越绕。加之紧缺专门的学业节制,别的品种成员依据各自要求,在”进度线“加插各自逻辑,最后那么些页面包车型大巴逻辑变得难以保证。

图片 3

支付需求严慎,生怕影响“进程线”前面寻常逻辑。並且每一回加插或涂改都以bug泛滥,无不令成品有关人口无不心惊胆战。

 页面布局模块化

根据上边的面向进度的主题素材,行当内也许有超级多消除方案,而我们团队也总计出大器晚成套成熟的缓慢解决方案:Abstractjs,页面架构模块化。大家得以把大家的页面想象为一个乐高机器人,要求分歧零器件组装,如下图,假诺页面划分为tabContainer,listContainer和imgsContainer多个模块。最后把这一个模块add到结尾的pageModel里面,最终使用rock方法让页面运营起来。

图片 4
(原经过线示例图)

图片 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=1’, processData:
function(data卡塔尔 { //… }, event: function(卡塔尔{ // listElement’s event },
error: function(data卡塔尔(英语:State of Qatar) { 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都包括各自的多少,模板,逻辑。已经算是一个整机的效果单元。但间距真正的WebComponent还是有意气风发段间隔,最少满意不断笔者的”理想目录构造“。

 WebComponents 标准

咱俩想起一下行使四个datapicker的jquery的插件,所须要的步奏:

  1. 引进插件js

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

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

  4. 累计代码触发组件运营

眼前的“组件”基本上只好落得是某些意义单元上的会集。他的能源都以松散地分散在三种财富文件中,并且组件作用域暴光在全局意义域下,缺少内聚性比较轻巧就能跟其它零零器件产生冲突,如最简易的css命名矛盾。对于这种“组件”,还比不上上面包车型大巴页面结构模块化。

于是乎W3C按耐不住了,制订一个WebComponents标准,为组件化的前程辅导了明路。

上边以较为轻巧的法门介绍那份正经,力求咱们能够快捷通晓达成组件化的从头到尾的经过。(对那有的询问的同室,能够跳过这一小节)

1. <template>模板技艺

模板那东西北大学家最熟稔然而了,前年见的超多的模版质量大战artTemplate,juicer,tmpl,underscoretemplate等等。这段时间日又有mustachejs无逻辑模板引擎等新入选手。但是大家有未有想过,这么根底的力量,原生HTML5是不援助的(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;能够见到那几个原生的模板够原始,模板占位符等成效都未有,对于动态数据渲染模板技艺只好自力更新。

2. 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的室内面,新建了三个shadow的房子。房间外的人都不精通房间内有哪些,保持shadowDom的独立性。

3. 自定义原生标签

首先接触Angularjs的directive指令效能,设定好组件的逻辑后,二个<Datepicker
/>就会引进整个组件。如此狂炫耀炸碉堡天的机能,实在令人人心大快,跃地三尺。

JavaScript

var tmpl = document.querySelector(‘#datapickerTmpl’卡塔尔(قطر‎; var
datapickerProto = Object.create(HTMLElement.prototype卡塔尔国; //
设置把我们模板内容我们的shadowDom datapickerProto.createdCallback =
function(卡塔尔(قطر‎ { var root = this.createShadowRoot(卡塔尔(英语:State of Qatar);
root.appendChild(document.importNode(tmpl.content, true卡塔尔卡塔尔(英语:State of Qatar); }; 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>的选择。

4. 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的四片段机能:

1 .<template>定义组件的HTML模板才具

  1. Shadow Dom封装组件的内部构造,而且维持其独立性

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

  3. import解决组件结合和依附加载

 组件化实施方案

法定的正式看完了,大家观念一下。大器晚成份真正成熟笃定的组件化方案,供给具有的力量。

“财富高内聚”—— 组件能源内部高内聚,组件财富由本身加载调节

“成效域独立”—— 内部布局密闭,不与大局或任何零部件发生影响

“自定义标签”—— 定义组件的应用方法

“可相互结合”—— 组件正在有力之处,组件间组装整合

“接口标准化”—— 组件接口有统大器晚成标准,也许是生命周期的管住

个人认为,模板技巧是基本功力量,跟是或不是组件化未有强联系,所以未有提议二个大点。

既然是推行,现阶段WebComponent的支撑度还不成熟,不可能充当方案的手段。而除此以外一套以高质量虚构Dom为切入点的组件框架React,在facebook的造势下,社区赢得了大力发展。此外一名骨干Webpack,担负消除组件能源内聚,同一时间跟React非常符合产生互补。

所以【Webpack】+【React】将会是那套方案的主题本事。

不精通您今后是“又是react+webpack”感觉失望图片 6,依旧“太好了是react+webpack”不用再学一回新框架的快乐图片 7。无论怎样下边的从头到尾的经过不会让您大失所望的。

风流倜傥,组件生命周期

图片 8

React天生正是抑遏性组件化的,所以能够从根性子上消除面向进度代码所推动的麻烦。React组件本人有生命周期方法,能够满意“接口标准化”技术点。並且跟“页面构造模块化”的所封装抽离的几个形式能挨个对应。其余react的jsx自带模板成效,把html页面片直接写在render方法内,组件内聚性尤其严密。

出于React编写的JSX是会先生成虚构Dom的,须要时机才真的插入到Dom树。使用React应当要了然组件的生命周期,其生命周期多少个情形:

Mount: 插入Dom

Update: 更新Dom

Unmount: 拔出Dom

mount这单词翻译扩展,嵌入等。我倒是建议“插入”更加好精通。插入!拔出!插入!拔出!默念三遍,懂了没?别少看黄段子的力量,

图片 9

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

然后各个组件状态会有二种管理函数,黄金时代前生龙活虎后,will函数和did函数。

componentWillMount()  构思插入前

componentDidlMount()  插入后

componentWillUpdate() 思量更新前

componentDidUpdate()  更新后

componentWillUnmount() 筹算拔出前

因为拔出后为主都以贤者形态(小编说的是组件),所以并未DidUnmount那些方式。

除此以外React其余叁个主干:数据模型props和state,对应着也许有自个状态方法

getInitialState()     获取开始化state。

getDefaultProps() 获取私下认可props。对于那么些未有父组件传递的props,通过该办法设置暗中同意的props

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

再有二个非常景况的管理函数,用于优化管理

shouldComponentUpdate():推断组件是还是不是必要update调用

加上最关键的render方法,React自己带的点子刚正巧十三个。对于初读书人的话是相比较麻烦消食。但其实getInitialStatecomponentDidMountrender多个景况方法都能完毕超越56%零部件,不必惧怕。

归来组件化的宗旨。

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

图片 10

大家换算成React生命周期方法:

图片 11

 

组件的场合方法流中,有两点须要特不要表明:

1,三遍渲染:

鉴于React的虚构Dom性情,组件的render函数不需协调触发,依照props和state的修正自个通过差距算法,得出最优的渲染。

央求CGI日常都是异步,所以不可否认带给三遍渲染。只是空数据渲染的时候,有十分大希望会被React优化掉。当数码回来,通过setState,触发二遍render

 

2,componentWiillMount与componentDidMount的差别

和大大多React的学科文章不等同,ajax哀告作者建议在WillMount的不二秘诀内施行,并非组件初阶化成功以后的DidMount。那样能在“空数据渲染”阶段以前央浼数据,尽早地收缩一次渲染的时刻。

willMount只会进行一遍,特别切合做init的事情。

didMount也只会实行一回,而且此时真实的Dom已经产生,非常相符事件绑定和complete类的逻辑。

 

 二,JSX好丑,可是组件内聚的第后生可畏!

WebComponents的正规化之意气风发,供给模板技巧。本是感觉是大家纯熟的模板技术,但React中的JSX那样的怪物依旧令人批评纷纷。React还尚无火起来的时候,我们就已经在博客园上尖锐地调侃了“JSX写的代码那TM的丑”。那实际只是德姆o阶段JSX,等到实战的大型项目中的JSX,包涵多情况好些个据多事件的时候,你会开采………….JSX写的代码照旧超级丑。

图片 12
(固然用sublime-babel等插件高亮,逻辑和渲染耦合一齐,阅读性依然略差)

怎么我们会认为丑?因为大家曾经经对“视图-样式-逻辑”分离的做法潜濡默化。

据说维护性和可读性,以至质量,我们都不建议直接在Dom上边绑定事件如故直接写style属性。大家会在JS写事件代理,在CSS上写上classname,html上的正是清晰的Dom构造。大家很好地爱慕着MVC的设计格局,一切虎口脱离危险。直到JSX把她们都夹杂在协同,所守护的本领栈受到侵袭,难免存有抗拒。

 

唯独从组件化的目标来看,这种高内聚的做法未尝不可。

上边包车型客车代码,从前的“逻辑视图抽离”格局,大家须要去找相应的js文件,相应的event函数体内,找到td-info的class所绑定的事件。

相比较起JSX的冲天内聚,所有的事件逻辑就是在我jsx文件内,绑定的正是自个儿的showInfo方法。组件化的风味能登时展现出来。

(注意:即使写法上大家好疑似HTML的内联事件微电脑,然则在React底层并不曾实际赋值近似onClick属性,内层照旧选用肖似事件代理的方法,高效地掩护着事件微处理机)

再来看生机勃勃段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的自定义标签技艺,组件的黑盒性立马能心得出来,是否一下子美好了成都百货上千。

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那一个组件化框架后,看看组件化技能点的完毕意况

“财富高内聚”—— (33%)  html与js内聚

“功效域独立”—— (四分之二)  js的效能域独立

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

“可彼此结合”—— (八分之四)  可组合,但贫乏使得的加载方式

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

 

Webpack 能源组件化

对此组件化的能源独立性,日常的模块加载工具和创设流程视乎变得吃力。组件化的营造筑工程程化,不再是事情未发生前大家常见的,css合二,js合三,而是体验在组件间的依据于加载关系。webpack正巧契合要求点,一方面增加补充组件化本事点,另外一方扶持我们周密组件化的总体构建情形。

先是要申雅培点是,webpack是一个模块加载打包工具,用于管理你的模块财富信赖打包难点。那跟我们熟知的requirejs模块加载工具,和grunt/gulp营造工具的概念,多多少稀有个别出入又有一些相像。

图片 13

先是webpak对于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内部得以完毕了后生可畏套能源加运载飞机制,能够把想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的安顿,数组内三个object配置为意气风发种模块财富的加运载飞机制。test的正则为合营文件法则,loader的为相称到文件将由哪些加载器管理,四个计算机之间用相隔,管理顺序从右到左。

 

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

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

图表财富通过url-loader加载器,配置参数limit,调节少于10KB的图纸将会base64化。

 能源文件怎么样被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__(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……” /***/ }
]);

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编写翻译之后,输出文件视乎乱糟糟的,但事实上每三个财富都被封装在三个函数体内,何况以编号的款型标志(注释)。这一个模块,由webpack的__webpack_require__里头方法加载。入口文件为编号0的函数index.js,能够看来__webpack_require__加载别的编号的模块。

css文件在数码1,由于接纳css-loader和style-loader,编号1-4皆以拍卖css。在那之中编号2大家得以看我们的css的string体。最终会以内联的艺术插入到html中。

图表文件在编号6,可以看出exports出base64化的图片。

 组件蓬蓬勃勃体输出

JavaScript

// 加载组件本身css require(‘./slider.css’卡塔尔(英语:State of Qatar); // 加载组件重视的模块 var
React = require(‘react’卡塔尔; var Clip = require(‘../ui/clipitem.jsx’卡塔尔(英语:State of Qatar); //
加载图片能源 var spinnerImg = require(‘./loading.png’卡塔尔(英语:State of Qatar); var Slider =
React.createClass({ getInitialState: function(卡塔尔(英语:State of Qatar) { // … },
componentDidMount: function(卡塔尔{ // … }, render: function(卡塔尔(قطر‎ { return (
<div> <Clip data={this.props.imgs} /> <img
className=”loading” src={spinnerImg} /> </div> 卡塔尔国; } }卡塔尔(英语:State of Qatar);
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合为紧密。

那正是说丰裕webpack,两个结合一齐的话。js,css,png(base64卡塔尔,html
全部web能源都能合成三个JS文件。那多亏那套方案的为主所在:组件独立风姿洒脱体化。假如要援用叁个组件,仅仅require('./slider.js') 就能够完毕。

 

投入webpack的模块加载器之后,我们组件的加载难点,内聚难题也都家成业就地缓和掉

“财富高内聚”—— (百分百) 全数财富得以风流浪漫js出口

“可交互作用结合”—— (百分之百)  可构成可借助加载

 

 CSS模块化实践

很中意,你能阅读到那边。这几天大家的零器件完结度特其他高,能源内聚,易于组合,功用域独立互不污染。。。。等等图片 14,视乎CSS模块的完毕度有不足。

那正是说近来组件完结度来看,CSS成效域其实是全局性的,实际不是组件内部独立。下一步,我们要做得正是什么样让我们组件内部的CSS作用域独立。

此时可能有人立即跳出,大喊一句“德玛西亚!”,哦不,应该是“用sass啊傻逼!”。可是种类组件化之后,组件的里边封装已经很好了,其里面dom结商谈css趋势轻易,独立,以致是破破烂烂的。LESS和SASS的生龙活虎体式样式框架的陈设性,他的嵌套,变量,include,函数等丰裕的效用对于全部大型项目标样式处理非常管用。但对此两个效用单黄金年代组件内部样式,视乎就变的有些冲突。“不可能为了框架而框架,合适才是最棒的”。视乎原生的css工夫已经满意组件的体裁必要,唯独便是地点的css功能域难题。

 

这里我付诸思忖的方案:
classname随便写,保持原生的艺术。编写翻译阶段,依据组件在品种路径的唯风流洒脱性,由【组件classname+组件独一路线】打成md5,生成全局唯风度翩翩性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,那相对不是三个变量所能消除的”维护性“。

反而项目实战进度中,真正要化解的是:在本子迭代进程中那个淘汰掉的超时CSS,大量地聚成堆在项目当中。大家像极了家中的欧巴酱不舍得遗弃没用的东西,因为那不过大家利用sass或less编写出具备中度的可维护性的,肯定有复用的一天。

这个聚成堆的逾期CSS(or
sass)之间又有大器晚成对信赖,风姿洒脱部分过期失效了,生龙活虎部分又被新的样式复用了,导致没人敢动这一个历史样式。结果现网项目迭代还带着多量七年前没用的体裁文件。

组件化之后,css的方式相同被改动了。恐怕postcss才是你未来手上最符合的工具,而不在是sass。

 

到这里,大家究竟把组件化尾数主题素材也消除了。

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

 

到此处,大家得以开风流倜傥瓶82年的七喜,好好庆祝一下。不是啊?

图片 15

 

 组件化之路还在世襲

webpack和react还恐怕有非常多新比较重大的特征和效果,介于本文仅仅围绕着组件化的为主导,未有各种解说。其它,配搭gulp/grunt补充webpack营造技能,webpack的codeSplitting,react的组件通讯难题,开采与生育情况布署等等,都以全部大型项目方案的所必得的,限于篇幅难点。能够等等笔者更新下篇,或我们可以自动查阅。

可是,一定要再安利一下react-hotloader神器。热加载的花销方式绝对是下一代前端开拓必备。严谨说,若无了热加载,小编会很泼辣地遗弃那套方案,纵然那套方案再怎么完美,笔者都讨厌react须求5~6s的编写翻译时间。不过hotloader能够在作者不刷新页面包车型地铁场馆下,动态改善代码,并且不单单是样式,连逻辑也是即时生效。

图片 16

如上在form表单内。使用热加载,表单无需再度填写,校勘submit的逻辑立时见效。那样的支出功效真不是抓好仅仅一个程度。务必安利一下。

 

莫不你意识,使用组件化方案未来,整个本事栈都被更新了豆蔻梢头番。学费也不少,何况能够预看见,基于组件化的前端还大概会众多不足的主题素材,比如质量优化方案必要重新思考,以致最主旨的组件可复用性不料定高。前边非常长黄金时代段时间,必要我们不断磨砺与优化,探寻最优的前端组件化之道。

足足大家得以想像,不再怀恋本人写的代码跟有个别什么人哪个人冲突,不再为找某段逻辑在多少个文本和章程间持续,不再copy一片片逻辑然后改改。大家每便编写都以可选拔,可组成,独立且内聚的机件。而各样页面将会由壹个个嵌套组合的零件,互相独立却相互影响。

 

对于这么的前端现在,有所期望,不是很可以吗

于今停止,多谢你的开卷。

1 赞 6 收藏 1
评论

图片 17

后生可畏、什么是webpack:webpack是大器晚成款模块加载兼打包工具,它可以将js、jsx、coffee、样式sass、less,图片等作为模块来利用和管理。
二、优势:1、以commonJS的格局来书写脚本,对英特尔、CMD的扶持也很完美,方便旧项指标迁徙。2、能被模块化的穿梭是JS了。3、能替代部分grunt/gulp的职业,举个例子打包,压缩混淆,图片转base64等。3、扩张性强,插件机制康健,帮忙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,三个配备项,告诉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卡塔尔(英语:State of Qatar)plugins是插件项,这里运用了三个CommonsChunkPlugin的插件,它用来提取五个入口文件的公物脚本有的,然后生成三个common.js来便于多页面之间的复用。
(2卡塔尔国entry是页面包车型客车输入文件配置,output是相应的出口项配置
{
entry: {
page1: “./page1”,
//扶助数组情势,将加载数组中的全数模块,但以最终一个模块作为出口
page2: [“./entry1”, “./entry2”]
},
output: {
path: “dist/js/page”,
filename: “[name].bundle.js”
}
}
该代码会生成三个page1.bundle.js和page2.bundle.js,并贮存在./dist/js/page文件夹下。
(3卡塔尔(英语:State of Qatar)module.loaders,告知webpack每大器晚成种文件都亟需怎么着加载器来拍卖
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的直白转为base64
{ test: /.(png|jpg)$/, loader: ‘url-loader?limit=8192’}
]
}
-loader能够不写,八个loader之间用“!”连接起来。全体的加载器都亟需经过npm来加载。
譬喻最终二个url-loader,它会将样式中引用到的图样转为模块来拍卖。使用前行行设置:
$ npm install url-loader -save-dev
布署音讯的参数:“?limit=8192”表示将装有小于8kb的图形都转为base64格局(当先8kb的才使用url-loader来映射到文件,不然转为data
url格局卡塔尔(英语:State of Qatar)
(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’
}
}
四、运营webpack,直接实行:
$ webpack –display-error-details
背后的参数
“-display-error-details”推荐加上,方便出错开上下班时间能理解到更详尽的消息。别的首要参数:
$ webpack –config XXX.js
//使用另豆蔻梢头份配置文件(举个例子webpack.config2.js)来打包
$ webpack –watch //监听变动并活动打包
$ webpack -p //压缩混淆脚本,那一个可怜充足重大!
$ webpack -d //生成map映射文件,告知哪些模块被最后包装到哪儿了
-p是超重大的参数,曾经多个未压缩的 700kb 的公文,压缩后一贯减低到180kb(首假使样式那块一句就私吞后生可畏行脚本,导致未压缩脚本变得相当的大)。
五、模块引进:
1、在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里。
2、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
);

Author

发表评论

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