必赢的网址登录 > Web前端 > 那样就能够运用项目本地版本的webpack,争辨的集

原标题:那样就能够运用项目本地版本的webpack,争辨的集

浏览次数:194 时间:2019-10-01

致大家一定组件化的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) { 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(); 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>的选用。

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本人带的章程刚刚好12个。对于初学者的话是比较难以消化吸收。但实际getInitialStatecomponentDidMountrender八个情景方法都能造成大多数零件,不必惧怕。

回来组件化的宗旨。

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

必赢的网址登录 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正好相符须求点,一方面填补组件化本领点,另一方帮忙我们周全组件化的完全塑造情况。

率先要说Bellamy(Bellamy)点是,webpack是三个模块加载打包工具,用于管理你的模块财富信赖打包问题。那跟大家耳闻则诵的requirejs模块加载工具,和grunt/gulp创设筑工程具的概念,多多少少有些出入又有些雷同。

必赢的网址登录 13

先是webpak对于CommonJS与AMD同不时候补助,满意我们模块/组件的加载格局。

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{rn position: relative;rn width: 100%;rn margin: 50px;rn background: #fff;rn}rnrn.slider-wrap li{rn text-align: center;rn 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{rn position: relative;rn width: 100%;rn margin: 50px;rn background: #fff;rn}rnrn.slider-wrap li{rn text-align: center;rn line-height: 20px;rn}", ""]);
 
/***/ },
/* 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'); // 加载组件正视的模块 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合为一体。

那正是说丰盛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年的7-Up,好好庆祝一下。不是啊?

必赢的网址登录 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)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)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格局)
(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
);

*安装

其他:
1、shimming :
在 速龙/CMD 中,我们要求对不切合规范的模块(比方一些一直回到全局变量的插件)实行shim 管理,那时候大家要求动用 exports-loader 来协助:
{ test: require.resolve(“./src/js/tool/swipe.js”), loader: “exports?swipe”}
从此以往在剧本中须求援用该模块的时候,这么简单地来使用就能够了:
require(‘./tool/swipe.js’);
swipe();
2、自定义公共模块提取:
在篇章初步我们使用了 CommonsChunkPlugin 插件来提取八个页面之间的集人体模型块,并将该模块打包为 common.js 。
但一时候大家目的在于能尤其个性化一些,我们可以那样布署:
var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin");
module.exports = {
entry: {
p1: "./page1",
p2: "./page2",
p3: "./page3",
ap1: "./admin/page1",
ap2: "./admin/page2"
},
output: {
filename: "[name]那样就能够运用项目本地版本的webpack,争辨的集中正是下图的七个目录分层结构。.js"
},
plugins: [
new CommonsChunkPlugin("admin-commons.js", ["ap1", "ap2"]),
new CommonsChunkPlugin("commons.js", ["p1", "p2", "admin-commons.js"])
]
};
// <script>s required:
// page1.html: commons.js, p1.js
// page2.html: commons.js, p2.js
// page3.html: p3.js
// admin-page1.html: commons.js, admin-commons.js, ap1.js
// admin-page2.html: commons.js, admin-commons.js, ap2.js
3、独立包装样式:
有时大概希望项指标样式能毫无被打包到脚本中,而是独立出来作为.css,然后在页面中以标签引进。那时候大家需求extract-text-webpack-plugin 来扶持:
var webpack = require('webpack');
var commonsPlugin = new webpack.optimize.CommonsChunkPlugin('common.js');
var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
plugins: [commonsPlugin, new ExtractTextPlugin("[name].css")],
entry: {
//...省略其余配置
最终 webpack 试行后会乖乖地把体制文件提抽取来:
4、使用CDN远程文件:
神跡大家期望有个别模块走CDN并以<script>的款式挂载到页面上来加载,但又愿意能在 webpack 的模块中运用上。
此时大家能够在配置文件里使用 externals 属性来帮衬:
{
externals: {
// require("jquery") 是引用自外界模块的
// 对应全局变量 jQuery
"jquery": "jQuery"
}
}
亟需专心的是,得保障 CDN 文件必得在 webpack 打包文件引进在此以前先引进。
咱俩倒也能够选拔 script.js 在剧本中来加载大家的模块:
var $script = require("scriptjs");
$script("//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js", function() {
$('body').html('It works!')
});
5、与grunt/gulp相结合:
gulp.task("webpack", function(callback) {
// run webpack
webpack({
// configuration
}, function(err, stats) {
if(err) throw new gutil.PluginError("webpack", err);
gutil.log("[webpack]", stats.toString({
// output options
}));
callback();
});
});
理所必然大家只要求把安插写到 webpack({ … }) 中去就可以,无须再写 webpack.config.js 了。

进入到你的类型 将webpack安装到品种的依据中,那样就足以动用项目本地版本的webpack
npm install webpack@1.12.x--save-dev(这种格式是设置钦定版本)

npm install webpack --save-dev

npm i webpack-dev-server --save

npm install react --save

npm install babel-loader babel-core babel-preset-es2015 babel-preset-react --save-dev

npm i react-dom --save

*目录

index.html
js / 你的js文件
dist / 你打包的文书(也等于您JS目录下的文书打包后的文本)
手动打包方法

手动打包: webpack 源文件路线 打包路径(webpack ./entry.js ./bundle.js)//这里是从未布署webpack.config.js
$ webpack --watch //监听变动并自行打包 监视webpack.config.js 的改变$ webpack -p //压缩混淆脚本,这几个可怜特别首要!

*注意事项

页面要引进打包后的路径的JS文件

*loader理解

是模块和财富的转变器,它本身是三个函数,接受源文件作为参数,重返调换的结果。那样,大家就能够透过 require 来加载任何项目标模块或文件,比如CoffeeScriptJSXLESS图片

*爆出模块

module.exports = "It works from content.js.";//nodejs中的暴光格局

export default Girls;//ES6

*引进模块

import MyModule from './modules/MyModule.js';//es6

var MyModule = require('./MyModule.js');//commonjs

webpack require 一切
require("./content.js"); // 添加content.js

*加载CSS

安装css-loader : npm install css-loader style-loader
require("style!css!
../css/main.css")//加载CSS style!css!是宣称这些模块是CSS style!css!能够不写 在loaders里面配备消息就可以

import "../css/main.css";//ES6引进形式

*陈设文件

webpack.config.js 以下是骨干配备
单个入口文件
var path = require('path');

module.exports = {

entry: "./js/entry.js",

output: {

path: './dist',

    publicPath: './dist/',

    filename: "bundle.js"

},

module: {

    loaders: [

        { test: /.css$/, loader: "style!css" }

    ]

}

};

三个输入文件

var path = require('path');

module.exports = {

entry: {

    page1:["./js/entry.js","./js/double.js"]

},

output: {

path: './dist',

    publicPath: './dist/',

    filename: "bundle.js"

},

module: {

    loaders: [

        { test: /.css$/, loader: "style!css" }

    ]

}

};

加载器配置

此地供给在output模块里面安装publicPath否则CSS背景图片等出口有失常态

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'} ] },

entry: {
page1: "./page1",//单个文件形式援助数组格局,将加载数组中的全体模块,但以最终八个模块作为出口
page2: ["./entry1", "./entry2"]
},//数组格局 即使运用下边你的写法 不能够用上边的这种
output: {
path: "dist/js/page",
filename: "[name].bundle.js"
}

*揭破模块使用案例

var index={//那是增添content.js
main:function(){
var html="1111111";
return html;
}
}
module.exports=index;

//那是在另贰个文本
var index=require("./content.js"); // 添加content.js

document.getElementById("box").innerHTML=index.main();

*npm install --save 与 npm install --save-dev 的区别

贰个位居package.json 的dependencies , 三个身处devDependencies里面

扩展:

在package.json 设置它的scripts npm run build===webpack(这里是运作打包)

{ "scripts": { "build": "webpack", "dev": "webpack-dev-server --devtool eval --progress --colors --hot --content-base build" }}

webpack-dev-server 自动监听(此时还无法活动刷新浏览器)ctrl+C退出服务

npm i webpack-dev-server --save
npm run dev 在http://localhost:8080监听文件修改
"dev": "webpack-dev-server --devtool eval --progress --colors --hot --content-base build"

webpack-dev-server

  • 在 localhost:8080 创设一个 Web 服务器
    --devtool eval
  • 为你的代码创制源地址。当有另外报错的时候能够让您越是可信赖地稳住到文件和行号
    --progress
  • 呈现合併代码过程
    --colors
  • Yay,命令行中显示颜色!
    --content-base build
  • 针对设置的输出目录

设若急需浏览器自动刷新你供给在配备中追加三个入口点。
webpack.config.js
**entry: [ 'webpack/hot/dev-server', 'webpack-dev-server/client?http://localhost:8080', path.resolve(__dirname, 'app/main.js') ],

**

本文由必赢的网址登录发布于Web前端,转载请注明出处:那样就能够运用项目本地版本的webpack,争辨的集

关键词:

上一篇:必赢的网址登录更为贴切,老司机如有宝贵意见

下一篇:没有了