争论的聚焦就是下图的两个目录分层结构,这样

致大家确定组件化的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标准内容大约到这里,是的,笔者那边未有何样Demo,也绝非实践经验分享。由于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正好适合须求点,一方面填补组件化工夫点,另一方帮衬大家周详组件化的全部营造情状。

先是要申圣元点是,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的为相配到文件将由什么加载器管理,三个Computer之间用相隔,管理顺序从右到左。

 

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;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......" /***/ } ]);

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年的Sprite,好好庆祝一下。不是吧?

图片 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
);

npm i react-dom --save

$ webpack-dev-server --content-base ./
--content-base ./ 参数表示将当前目录作为 server 根目录。 命令运转过后,会在 8080 端口运营多少个 http 服务,通过拜会http://localhost:8080/index.html 能够访问 index.html 内容。

开荒遭遇

当项目日益变大,webpack 的编写翻译时间会变长,能够因此参数让编写翻译的出口内容满含进程和颜料。

$ webpack --progress --colors

一经不想每回修改模块后都重复编写翻译,那么能够运转监听方式。开启监听情势后,未有成形的模块会在编写翻译后缓存到内部存储器中,而不会每一趟都被再度编写翻译,所以监听情势的全部进程是一点也不慢的。

$ webpack --progress --colors --watch

自然,使用webpack-dev-server开拓服务是贰个越来越好的选项。它将要localhost:8080 运行二个 express 静态能源 web 服务器,何况会以监听情势自动运营webpack,在浏览器张开http://localhost:8080/或http://localhost:8080/webpack-dev-server/能够浏览项目中的页面和编写翻译后的能源输出,况且通过一个socket.io 服务实时监听它们的变型并自行刷新页面。

# 安装

$ npm install webpack-dev-server -g

# 运行

$ webpack-dev-server --progress --colors

其他:
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].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 依赖
// --save-dev 代表将依靠增多到 package.json 中的 'devDependencies' 对象中
$ npm install webpack --save-dev

部署文件

Webpack 在实行的时候,除了在命令行传入参数,还足以由此点名的布署文件来实施。暗许情形下,会寻觅当前目录的webpack.config.js文件,这些文件是贰个node.js 模块,再次来到多少个 json 格式的安顿音讯目的,大概经过--config选项来内定布置文件。

承接我们的案例,在根目录成立package.json来加多 webpack 特殊要求的依据:

{

     "name":"webpack-example",

     "version":"1.0.0",

     "description":"A simple webpack example.",

    "main":"bundle.js",

     "scripts": {"test":"echo "Error: no test specified" && exit 1"},

     "keywords": ["webpack"],

     "author":"zhaoda",

     "license":"MIT",

     "devDependencies": {

           "css-loader":"^0.21.0",

           "style-loader":"^0.13.0",

           "webpack":"^1.12.2"

     }

}

# 若无写入权限,请尝试如下代码改变权限

chflags -R nouchg .

sudo chmod775package.json

别忘了运行npm install。

下一场创设二个配备文件webpack.config.js:

var webpack =require('webpack')

module.exports = { 

     entry:'./entry.js',  

     output: {   path: __dirname,    filename:'bundle.js'},

     module: {    loaders: [      {test:/.css$/, loader:'style-loader!css-loader'}    ]  }

}

再者简化entry.js中的style.css加载形式:

require('./style.css')

最终运转webpack,能够看出 webpack 通过配备文件推行的结果和上一章节由此命令行webpack entry.js bundle.js --module-bind 'css=style-loader!css-loader'施行的结果是同一的。

    publicPath: './dist/',

    filename: "bundle.js"

},

module: {

    loaders: [

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

    ]

}

新增加 loader 能够在 webpack.config.js 的 module.loaders 数组中新扩大四个loader 配置。

UMD

Universal Module Definition标准类似于包容CommonJS 和 英特尔 的语法糖,是模块定义的跨平台建设方案。

npm i webpack-dev-server --save

webpack-dev-server 还提供了模块热加载的措施,在不刷新浏览器的基准下,应用新型的代码更新,启动webpack-dev-server 的时候加多 --inline --hot 参数就足以体会。

AMD 规范

AMD(异步模块定义)是为浏览器情况设计的,因为 CommonJS 模块系统是手拉手加载的,当前浏览器意况还不曾未雨绸缪好同步加载模块的规范化。

英特尔 定义了一套 JavaScript 模块依赖异步加载规范,来消除协同加载的主题材料。

模块通过define函数定义在闭包中,格式如下:

define(id?:String, dependencies?:String[], factory:Function|Object);

id是模块的名字,它是可选的参数。

dependencies钦定了所要依赖的模块列表,它是多少个数组,也是可选的参数,每一个依赖的模块的出口将作为参数二遍传入factory中。若无一些名dependencies,那么它的私下认可值是["require", "exports", "module"]。

define(function(require, exports, module){})

factory是最终一个参数,它包裹了模块的具体贯彻,它是三个函数或许指标。要是是函数,那么它的重回值正是模块的输出接口或值。

一些用例:

概念三个名称叫myModule的模块,它依赖jQuery模块:

define('myModule', ['jquery'],function($){// $ 是 jquery 模块的出口$('body').text('hello world');});// 使用define(['myModule'],function(myModule){});

留神:在 webpack 中,模块名独有部分成效域,在 Require.js 中模块名是全局成效域,能够在大局引用。

概念四个并未有id值的匿超级模特块,平时作为利用的启航函数:

define(['jquery'],function($){    $('body').text('hello world');});

借助多少个模块的定义:

define(['jquery','./math.js'],function($, math){// $ 和 math 一次传入 factory$('body').text('hello world');});

模块输出:

define(['jquery'],function($){varHelloWorldize =function(selector){       

 $(selector).text('hello world');    };// HelloWorldize 是该模块输出的对外接口returnHelloWorldize;});

在模块定义内部引用依赖:

define(function(require){var$ =require('jquery');    $('body').text('hello world');});

扩展:

首先步:npm install 信赖模块

那些已部分模块化学工业具并无法很好的完成如下的目的:

将依赖树拆分成按需加载的块

起初化加载的耗费时间尽量少

各样静态能源都足以看成模块

将第三方库整合成模块的力量

能够自定义打包逻辑的力量

适合大连串,无论是单页还是多页的 Web 应用

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 是什么

怎么重复造轮子

市情桐月经存在的模块管理和包裹工具并不切合大型的花色,越发单页面 Web 应用程序。最急不可待的由来是什么样在四个大规模的代码库中,维护各个模块财富的分开和存放,维护它们之间的注重关系,而且无缝的将它们构成到一道生成适合浏览器端央求加载的静态能源。

此地要求在output模块里面安装publicPath不然CSS背景图片等输出有题目

// eg css loader
$ npm install css-loader style-loader --save-dev
其次步:修改配置

ES6 模块

EcmaScript6 规范扩展了 JavaScript 语言层面包车型客车模块连串定义。ES6 模块的统一计划观念,是尽量的静态化,使得编写翻译时就会明确模块的看重性关系,以及输入和输出的变量。CommonJS 和 英特尔 模块,都只辛亏运转时规定那些事物。

import"jquery";exportfunctiondoStuff(){}module"localModule"{}

优点:

轻松实行静态深入分析

面向今后的 EcmaScript 标准

缺点:

原生浏览器端还不曾兑现该专门的职业

斩新的命令字,新版的 Node.js才支撑

path: './dist',

在上头的 jsx 配置中,大家将 React 和 ReactDOM 一同打包进了类别代码。为了兑现职业代码和第三方代码的分别,大家得以采纳
CommonsChunkPlugin 插件.

AMD

Asynchronous Module Definition行业内部其实独有贰个着重接口define(id?, dependencies?, factory),它要在证明模块的时候钦赐全部的依赖dependencies,何况还要作为形参传到factory中,对于依附的模块提前实施,依赖前置。

define("module", ["dep1","dep2"],function(d1, d2){returnsomeExportedValue;});require(["module","../file"],function(module, file){/* ... */});

优点:

切合在浏览器遇到中异步加载模块

能够相互加载多个模块

缺点:

拉长了开荒开支,代码的阅读和书写比较困难,模块定义格局的语义不顺遂

不切合通用的模块化思维方法,是一种迁就的兑现

加载器配置

电动刷新

Loader

Webpack 本身只可以管理 JavaScript 模块,就算要管理任何品类的文件,就须要使用 loader 进行调换。

Loader 能够精晓为是模块和能源的转变器,它本人是二个函数,接受源文件作为参数,再次回到调换的结果。这样,大家就足以通过require来加载任何类型的模块或文件,例如CoffeeScript、 JSX、 LESS 或图表。

先来拜谒 loader 有哪些特征?

Loader 能够由此管Doug局链式调用,各类 loader 能够把能源调换来狂妄格式并传递给下贰个 loader ,不过最后二个 loader 务必再次回到 JavaScript。

Loader 能够一齐或异步试行。

Loader 运行在 node.js 情状中,所以能够做别的或许的事体。

Loader 尚可参数,以此来传递配置项给 loader。

Loader 能够透过文件扩张名(或正则表达式)绑定给差别品种的公文。

Loader 能够经过npm发表和装置。

除此而外通过package.json的main钦命,常常的模块也得以导出一个 loader 来利用。

Loader 能够访谈安插。

插件能够让 loader 具有愈来愈多特点。

Loader 能够分发出附加的随机文件。

Loader 本人也是运作在 node.js 意况中的 JavaScript 模块,它一般会回去二个函数。大比相当多景色下,大家因此 npm 来保管 loader,但是你也得以在类型中和煦写 loader 模块。

根据规矩,而非必须,loader 一般以xxx-loader的方法命名,xxx代表了那个loader 要做的转变职能,比方json-loader。

在援引 loader 的时候能够选择人名json-loader,恐怕采纳短名json。那些命名法则和寻觅优先级依次在 webpack 的resolveLoader.moduleTemplatesapi 中定义。

Default: ["*-webpack-loader", "*-web-loader", "*-loader", "*"]

Loader 能够在require()援用模块的时候加多,也可以在 webpack 全局配置中开展绑定,还是能透过命令行的点子选拔。

接上一节的事例,大家要在页面中引进多个 CSS 文件 style.css,首页将 style.css 也作为是二个模块,然后用css-loader来读取它,再用style-loader把它插入到页面中。

/* style.css */

body{background:yellow; }

修改 entry.js:

require("!style-loader!css-loader!./style.css")// 载入 style.css

document.write('It works.')

document.write(require('./module.js'))

安装 loader:

npm install css-loader style-loader

重复编写翻译打包,刷新页面,就能够观察鲜蓝的页面背景了。

一旦每便requireCSS 文件的时候都要写 loader 前缀,是一件很麻烦的事体。大家能够依据模块类型(扩大名)来机关绑定供给的 loader。

将 entry.js 中的require("!style!css!./style.css")修改为require("./style.css"),然后实践:

$ webpack entry.js bundle.js --module-bind'css=style-loader!css-loader'# 有个别条件下恐怕须求选择双引号$ webpack entry.js bundle.js --module-bind"css=style-loader!css-loader"

鲜明,那三种采纳 loader 的不二诀要,效果是一律的。

*注意事项

{
entry: [String | Array | Object], // 入口模块
output: {
path: String, // 输出路线
filename: String // 输有名称或称谓 pattern
publicPath: String // 钦定静态财富的岗位
... // 其余计划
}
}
单一入口

Webpack 的特点

Webpack 和别的模块化学工业具备怎么着界别吧?

代码拆分

Webpack 有三种集人体模型块重视的格局,同步和异步。异步依赖作为分割点,产生一个新的块。在优化了依据树后,每一个异步区块都当做多个文书被包裹。

Loader

Webpack 自身只好管理原生的 JavaScript 模块,可是 loader 转变器能够将各种类型的财富转换来 JavaScript 模块。这样,任何财富都足以改为 Webpack 能够管理的模块。

智能分析

Webpack 有一个智能分析器,大约能够拍卖其余第三方库,无论它们的模块方式是 CommonJS、 英特尔 照旧普通的 JS 文件。以至在加载正视的时候,允许利用动态表达式require("./templates/" + name + ".jade")。

插件系统

Webpack 还应该有贰个作用丰富的插件系统。大大多剧情成效都是基于这一个插件系统运行的,仍是能够支付和动用开源的 Webpack 插件,来满足五光十色的急需。

连忙运维

Webpack 使用异步 I/O 和家家户户缓存进步运营功效,这使得 Webpack 能够以让人出乎意料的速度迅猛增量编写翻译。

entry: {

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

},

output: {

亟待集成一些第三方库

安装

首先要安装Node.js, Node.js 自带了软件包管理器 npm,Webpack 须要 Node.js v0.6 以上帮助,提议使用新型版 Node.js。

用 npm 安装 Webpack:

$ npm install webpack -g

此刻 Webpack 已经安装到了全局景况下,能够经过命令行webpack -h试试。

平日大家会将 Webpack 安装到项指标借助中,这样就足以利用项目本地版本的 Webpack。

# 步入项目目录# 明确已经有 package.json,没有就因此 npm init 创立# 安装 webpack 依赖

$ npm install webpack --save-dev

Webpack 前段时间有七个主版本,八个是在 master 主干的稳固版,三个是在 webpack-2 分支的测验版,测量试验版拥有点实验性意义而且和牢固版不合作,在标准项目中应当选取牢固版。

# 查看 webpack 版本音信

$ npm info webpack

# 安装钦点版本的 webpack

$ npm install webpack@1.12.x --save-dev

假设必要使用 Webpack 开垦工具,要独自安装:

$ npm install webpack-dev-server --save-dev

*安装

loader 定义

故障管理

Webpack 的计划比较复杂,很容出现谬误,上边是部分司空眼惯的故障处理手腕。

相似情况下,webpack 假使出标题,会打字与印刷一些粗略的错误新闻,比方模块没有找到。我们仍是能够透过参数--display-error-details来打字与印刷错误实际情况。

$ webpack --display-error-details

Hash: a40fbc6d852c51fceadbVersion: webpack1.12.2Time:586ms    Asset    Size  Chunks            Chunk Namesbundle.js12.1kB0[emitted]  main  [0] ./entry.js153bytes {0} [built] [1error]  [5] ./module.js43bytes {0} [built]    +4hidden modulesERRORin./entry.jsModule not found: Error: Cannot resolve'file'or'directory'./badpathmodulein/Users/zhaoda/data/projects/webpack-handbook/examplesresolve file  /Users/zhaoda/data/projects/webpack-handbook/examples/badpathmodule doesn't exist

/Users/zhaoda/data/projects/webpack-handbook/examples/badpathmodule.webpack.js doesn't exist  /Users/zhaoda/data/projects/webpack-handbook/examples/badpathmodule.js doesn't exist

/Users/zhaoda/data/projects/webpack-handbook/examples/badpathmodule.web.js doesn't exist  /Users/zhaoda/data/projects/webpack-handbook/examples/badpathmodule.json doesn't exist

resolve directory

/Users/zhaoda/data/projects/webpack-handbook/examples/badpathmodule doesn't exist (directory default file)  /Users/zhaoda/data/projects/webpack-handbook/examples/badpathmodule/package.json doesn't exist (directory description file)

[/Users/zhaoda/data/projects/webpack-handbook/examples/badpathmodule]

[/Users/zhaoda/data/projects/webpack-handbook/examples/badpathmodule.webpack.js]

[/Users/zhaoda/data/projects/webpack-handbook/examples/badpathmodule.js]

[/Users/zhaoda/data/projects/webpack-handbook/examples/badpathmodule.web.js]

[/Users/zhaoda/data/projects/webpack-handbook/examples/badpathmodule.json]

@ ./entry.js 3:0-26

Webpack 的安顿提供了resolve和resolveLoader参数来安装模块剖析的拍卖细节,resolve用来布署应用层的模块(要被打包的模块)分析,resolveLoader用来配置loader模块的深入分析。

当引进通过 npm 安装的 node.js 模块时,可能出现找不到依靠的失实。Node.js 模块的凭仗分析算法相当的粗略,是通过查阅模块的每一层父目录中的node_modules文件夹来询问重视的。当出现Node.js 模块依赖查找未果的时候,可以尝尝设置resolve.fallback和resolveLoader.fallback来化解难点。

module.exports = {  

             resolve: { fallback: path.join(__dirname,"node_modules") }, 

             resolveLoader: { fallback: path.join(__dirname,"node_modules") }

};

Webpack 中提到路线配置最佳应用绝对路线,提议通过path.resolve(__dirname, "app/folder")或path.join(__dirname, "app", "folder")的章程来安顿,以合营 Windows 景况。

npm install webpack --save-dev

// },
/
1 /
/
/ function(module, exports) {

CMD

Common Module Definition规范和 速龙 很相似,尽量保持简单,并与 CommonJS 和 Node.js 的 Modules 规范保险了不小的包容性。

define(function(require, exports, module){var$ =require('jquery');varSpinning =require('./spinning');  exports.doSomething = ...module.exports = ...})

优点:

信赖就近,延迟实践

能够很轻巧在 Node.js 中运营

缺点:

依据 SPM 打包,模块的加载逻辑偏重

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

{
entry: ['./src/index.js', './vendor/bootstrap.min.js'],
output: {
path: './dist',
filename: "index.js"
}
}
提起底的出口结果如:

插件

插件能够成功更加多 loader 不能够达成的功效。

插件的运用相似是在 webpack 的配置消息plugins选项中内定。

Webpack 自己内置了有个别常用的插件,还足以经过 npm 安装第三方插件。

接下去,大家使用贰个最简便易行的BannerPlugin内置插件来实施插件的布局和周转,那一个插件的功力是给输出的文件尾部加多注释音讯。

修改webpack.config.js,添加plugins:

var webpack =require('webpack')

module.exports = {  

     entry:'./entry.js',  

     output: {    path: __dirname,    filename:'bundle.js'},

     module: {    loaders: [      {test:/.css$/, loader:'style-loader!css-loader'}    ]  },  

     plugins: [newwebpack.BannerPlugin('This file is created by zhaoda')  ]

}

然后运维webpack,张开bundle.js,能够看看文件尾部出现了大家钦命的讲明音讯:

/*! This file is created by zhaoda *//******/(function(modules){// webpackBootstrap/******/// The module cache/******/varinstalledModules = {};// 后边代码省略

var path = require('path');

地点的例子中都是包装出贰个 index.js 文件,如果项目有多个页面,那么供给打包出五个文件,webpack 能够用对象的艺术配置四个包裹文件

希望的模块系统

能够相称各个模块风格,尽量能够运用已某个代码,不止只是 JavaScript 模块化,还会有 CSS、图片、字体等能源也须求模块化。

前端模块加载

前端模块要在顾客端中进行,所以她们须求增量加载到浏览器中。

模块的加载和传导,大家第一能体会理解三种极端的艺术,一种是各类模块文件都独立供给,另一种是把富有模块打包成二个文件然后只诉求三回。总之,各样模块都倡导单独的伏乞造成了哀告次数过多,导致应用运维速度慢;叁遍呼吁加载全体模块导致流量浪费、初阶化过程慢。那三种办法都不是好的缓和方案,它们过于不难无情。

分块传输,按需实行懒加载,在实质上用到一些模块的时候再增量更新,才是比较合理的模块加载方案。

要贯彻模块的按需加载,就需求五个对全部代码库中的模块进行静态深入分析、编写翻译打包的长河。

享有财富都以模块

在地点的解析进程中,我们关系的模块仅仅是指JavaScript模块文件。可是,在前端开拓进程中还波及到样式、图片、字体、HTML 模板等等众多的能源。这个财富还有可能会以各类方言的样式存在,比方coffeescript、 less、 sass、众多的模板库、多语言体系(i18n)等等。

纵然她们都能够作为模块,而且都得以透过require的点子来加载,将拉动优雅的费用体验,举例:

require("./style.css");require("./style.less");require("./template.jade");require("./image.png");

那么哪些形成让require能加载各样能源呢?

静态解析

在编写翻译的时候,要对全部代码举行静态深入分析,深入分析出种种模块的品类和它们凭仗关系,然后将差别品种的模块提交给适配的加载器来管理。比方一个用 LESS 写的体制模块,可以先用 LESS 加载器将它转成贰个CSS 模块,在经过 CSS 模块把他插入到页面的价签中实施。Webpack 便是在如此的必要中冒出。

并且,为了能采取已经存在的种种框架、库和曾经写好的文书,大家还亟需一个模块加载的十三分计策,来制止重写全体的模块。

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

$ webpack --config webpack.config.prod.js
在本章深刻 webpack 小节中会更加的多的介绍生产情形中的优化

CommonJS 规范

CommonJS 是以在浏览器意况之外营造 JavaScript 生态系统为指标而发生的类型,比方在服务器和桌面意况中。

本条类型最先河是由 Mozilla 的工程师 凯文 Dangoor 在二零一零年7月创建的,当时的名字是 ServerJS。

自身在此间描述的并非贰个手艺难题,而是一件重大的业务,让我们走到联合来做决定,迈出第一步,来树立四个越来越大更酷的东西。 —— 凯文 Dangoor'sWhat Server Side JavaScript needs

二〇一〇年3月,这些项目改名字为 CommonJS,以呈现其 API 的更加宽泛实用性。CommonJS 是一套规范,它的始建和把关是开放的。这一个专门的学业已经有不知凡几本子和求实完毕。CommonJS 并非属于 ECMAScript TC39 小组的劳作,但 TC39 中的一些分子参加 CommonJS 的创建。2012年7月,Node.js 的包管理器 NPM 的作者 Isaac Z. Schlueter 说CommonJS 已经不符合时机,Node.js 的基业开拓者现已舍弃了该标准。

CommonJS 标准是为了缓慢解决 JavaScript 的功效域难题而定义的模块情势,能够使各种模块它自身的命名空间中奉行。该标准的严重性内容是,模块必得透过module.exports导出对外的变量或接口,通过require()来导入别的模块的出口到当前模块效能域中。

三个直观的例子:

// moduleA.jsmodule.exports =function(value){returnvalue *2;}

// moduleB.jsvarmultiplyBy2 =require('./moduleA');varresult = multiplyBy2(4);

CommonJS 是一只加载模块,但骨子里也可以有浏览器端的贯彻,其规律是现将全体模块都定义好并由此id索引,那样就能够一本万利的在浏览器蒙受中解析了,能够参见require1k和tiny-browser-require的源码来理解其深入分析(resolve)的进程。

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

何以引进新的包裹工具

使用

率先创建一个静态页面 index.html 和二个 JS 入口文件 entry.js:

// entry.js

document.write('It works.')

然后编写翻译 entry.js 并封装到 bundle.js:

$ webpack entry.js bundle.js

包裹进程会来得日志:

Hash: e964f90ec65eb2c29bb9

Version: webpack 1.12.2

Time: 54ms

Asset    Size  Chunks            Chunk Names

bundle.js  1.42 kB      0  [emitted]  main

[0] ./entry.js 27 bytes {0} [built]

用浏览器展开index.html将会看出It works.。

接下去增加一个模块module.js并修改入口entry.js:

// module.js

module.exports ='It works from module.js.'

// entry.js

document.write('It works.')

document.write(require('./module.js'))// 加多模块

重新打包webpack entry.js bundle.js后刷新页面来看变化It works.It works from module.js.

Hash: 279c7601d5d08396e751

Version: webpack 1.12.2

Time: 63ms

Asset    Size  Chunks            Chunk Names

bundle.js  1.57 kB      0  [emitted]  main

[0] ./entry.js 66 bytes {0} [built]

[1] ./module.js 43 bytes {0} [built]

Webpack 会深入分析入口文件,深入分析富含重视关系的各种文件。那个文件(模块)都打包到 bundle.js 。Webpack 会给各种模块分配一个独一的 id 并通过那几个 id 索引和做客模块。在页面运营时,会施夷光行 entry.js 中的代码,另外模块会在运行require的时候再实践。

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

// babel 相关的模块
$ npm install babel-loader babel-preset-es2015 babel-preset-stage-0 babel-preset-react babel-polyfill --save-dev

现状

文本只可以遵照的书写顺序举行加载

开垦人士必须主观化解模块和代码库的依赖性关系

在大型项目中各类能源难以管理,长时间堆成堆的主题素材变成代码库混乱不堪

CommonJS

劳动器端的 Node.js 服从CommonJS规范,该标准的宗旨理想是允许模块通过require方法来一块加载所要注重的别的模块,然后通过exports或module.exports来导出供给揭穿的接口。

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

优点:

劳务器端模块便于重用

NPM中已经有邻近20万个能够运用模块包

简单的说并轻巧选择

缺点:

共同的模块加载格局不吻合在浏览器环境中,同步意味着阻塞加载,浏览器财富是异步加载的

不可能非阻塞的相互加载三个模块

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

webpack 配置参数

什么是 Webpack

Webpack 是二个模块打包器。它将基于模块的注重关系张开静态解析,然后将这么些模块遵照钦点的法规改变对应的静态财富。

图片 18

叁个坐落package.json 的dependencies , 三个坐落devDependencies里面

var Hello = React.createClass({
render: function render() {
return <div>Hello {this.props.name}</div>;
}
});

Webpack 普通话指南

Webpack是立即最热门的前端财富模块化管理和包装工具。它能够将多数松懈的模块根据重视和法则打包成符合生产条件计划的前端能源。还足以将按需加载的模块进行代码分隔,等到实际要求的时候再异步加载。通过loader的调换,任何款式的财富都得以视作模块,比如CommonJs 模块、 英特尔 模块、 ES6 模块、CSS、图片、 JSON、Coffeescript、 LESS 等。

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

plugins: [
new webpack.optimize.CommonsChunkPlugin(
/* chunkName= /"vendor",
/
filename= */"vendor.bundle.js", Infinity),
// 要求手动增添 HotModuleReplacementPlugin , 命令行的法子会自行抬高
new webpack.HotModuleReplacementPlugin()
],
devServer: {
hot: true,
inline: true
}
不加参数直接实践 webpack-dev-server

*加载CSS

  • 第五步:Develop Server 工具 (可选)

webpack-dev-server

修改 webpack.config.js 添加:

*loader理解

webpack 在此以前的卷入工具工具功效单一,只可以成功一定的职务,然则 web 前端工程是错综相连的,二个 webapp 对于专门的学业代码的渴求大概有:

跻身到您的种类将webpack安装到项目标信赖中,这样就可以运用项目本地版本的webpack
npm install webpack@1.12.x--save-dev(这种格式是安装钦点版本)

修改 webpack.config.js

module.exports = {

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello React!</title>
</head>
<body>
<div id="AppRoot"></div>
<script src="dist/index.js"></script>
</body>
</html>
index.js 内容为:

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

output: {

配备文件

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

生育情状 build 用如下命令:

module.exports = {

第二步:webpack-cli

**

现行反革命我们早已足以运用 webpack 来打包基于 CommonJs 的 Javascript 模块了,不过还无法解析 JSX 语法和 Es6 语法。上边大家将利用 Babel 让 webpack 能够分析 Es6 和 Babel

*目录

entry 和 output

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

配备文件

entry: {
page1: "./page1",//单个文件情势支持数组方式,将加载数组中的全数模块,但以最后二个模块作为出口
page2: ["./entry1", "./entry2"]
},//数组方式 假使使用上面你的写法 无法用上边的这种
output: {
path: "dist/js/page",
filename: "[name].bundle.js"
}

src/index.js 内容改为:

是模块和能源的调换器,它自身是一个函数,接受源文件作为参数,重回调换的结果。那样,大家就能够通过 require 来加载任何项指标模块或文件,例如CoffeeScriptJSXLESS图片

webpack 开采景况与生育意况

    publicPath: './dist/',

    filename: "bundle.js"

},

module: {

    loaders: [

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

    ]

}

运用被放到了贰个 iframe 内部,页面顶端能够显得打包进程音讯

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

基于那些效应能够完成广大自定义的安插。

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

webpack develop server

};

// -g 参数表示全局安装
$ npm install webpack -g
其三步:新建空前端项目

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

扶助多少个 bundler 输出 -> 解决代码分块难题

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

webpack 是三个模块打包工具,输入为包括信赖关系的模块集,输出为包装合併的前端静态能源。在上一节的前端工程化中,已经介绍过,webpack 是同偶然候帮忙 速龙 和 CommonJs 的模块定义方式,不独有如此,webpack 能够将其余前端能源视为模块,如 css,图片,文本。

webpack.config.js 以下是中央配置
单个入口文件
var path = require('path');

Node.js 安装好以往,展开命令行终端,通过 npm 命令安装:

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

2.2.4 webpack 配置

本文由必威发布于必威-前端,转载请注明出处:争论的聚焦就是下图的两个目录分层结构,这样

相关阅读