【美高梅开户网址】致大家肯定组件化的Web,webpack使用精晓

致我们必然组件化的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自身带的法门刚刚好10个。对于初学者的话是相比为难消化。但事实上getInitialStatecomponentDidMountrender多个状态方法都能到位大多数零部件,不必惧怕。

回到组件化的要旨。

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

美高梅开户网址 10

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

美高梅开户网址 11

 

组件的景况方法流中,有两点要求独特表明:

1,二次渲染:

鉴于React的杜撰Dom特性,组件的render函数不需协调触发,按照props和state的变动自个通过差别算法,得出最优的渲染。

伸手CGI一般都是异步,所以毫无疑问带来二次渲染。只是空数据渲染的时候,有可能会被React优化掉。当数码回来,通过setState,触发二次render

 

2,componentWiillMount与componentDidMount的差别

和大部分React的教程小说不均等,ajax请求我指出在威·尔(W·ill)Mount的措施内举行,而不是组件早先化成功之后的DidMount。那样能在“空数据渲染”阶段从前请求数据,尽早地裁减二次渲染的时间。

willMount只会执行四次,格外适合做init的工作。

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

 

 二,JSX很丑,可是组件内聚的最首要!

WebComponents的规范之一,必要模板能力。本是认为是大家耳熟能详的模版能力,但React中的JSX那样的怪人如故令人议论纷繁。React还尚无火起来的时候,大家就曾经在博客园上尖锐地吐槽了“JSX写的代码那TM的丑”。那实际上只是Demo阶段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内聚

“成效域独立”—— (50%)  js的功效域独立

“自定义标签”—— (100%)jsx

“可相互结合”—— (50%)  可组成,但缺少使得的加载情势

“接口规范化”—— (100%)组件生命周期方法

 

Webpack 资源组件化

对于组件化的资源独立性,一般的模块加载工具和构建流程视乎变得辛勤。组件化的构建工程化,不再是事先大家广阔的,css合二,js合三,而是体验在组件间的依赖于加载关系。webpack正好适合须要点,一方面填补组件化能力点,另一方匡助咱们周密组件化的全部构建环境。

率先要表圣元(Meadjohnson)点是,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([【美高梅开户网址】致大家肯定组件化的Web,webpack使用精晓。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’); // 加载组件器重的模块 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的模块加载器之后,大家组件的加载问题,内聚问题也都成功地解决掉

“资源高内聚”—— (100%) 所有资源得以一js出口

“可彼此结合”—— (100%)  可组合可依靠加载

 

 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。

 

到此地,大家算是把组件化最终一个问题也化解了。

“作用域独立”—— (100%) 似乎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是插件项,那里运用了一个康芒斯(Commons)ChunkPlugin的插件,它用来提取八个入口文件的共用脚本有的,然后生成一个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
);

*安装

webpack 介绍

其他:
1、shimming :
在 速龙/CMD
中,大家必要对不符合规范的模块(比如有的直接再次回到全局变量的插件)举行shim 处理,这时候大家必要运用 exports-loader 来救助:
{ test: require.resolve(“./src/js/tool/swipe.js”), loader:
“exports?swipe”}
从此将来在本子中须求引用该模块的时候,这么不难地来使用就足以了:
require(‘./tool/swipe.js’);
swipe();
2、自定义公共模块提取:
在篇章初步大家利用了 康芒斯ChunkPlugin
插件来领取多个页面之间的公物模块,并将该模块打包为 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安装到花色的依赖中,那样就可以动用项目本地版本的webpack
npm install webpack@1.12.x–save-dev(那种格式是安装指定版本)

webpack 是什么

npm install webpack –save-dev

为什么引入新的卷入工具

npm i webpack-dev-server –save

webpack 大旨情想

npm install react –save

webpack 安装

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

webpack 使用

npm i react-dom –save

一声令下行调用

*目录

陈设文件

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

webpack 配置参数

手动打包: webpack 源文件路径 打包路径(webpack ./entry.js
./bundle.js)//这里是不曾配备webpack.config.js
$ webpack –watch //监听变动并机关打包 监视webpack.config.js 的改观$
webpack -p //压缩混淆脚本,那些足够可怜关键!

美高梅开户网址 ,entry 和 output

*注意事项

纯净入口

页面要引入打包后的门道的JS文件

多少个入口

*loader理解

四个包装目的

是模块和资源的转换器,它本身是一个函数,接受源文件作为参数,重回转换的结果。那样,大家就足以通过
require 来加载任何类型的模块或文件,比如CoffeeScriptJSX
LESS图片

webpack 支持 Jsx 和 Es6

*揭露模块

webpack loaders

module.exports = “It works from content.js.”;//nodejs中的暴露形式

loader 定义

export default Girls;//ES6

loader 功能

*引入模块

loader 配置

import MyModule from ‘./modules/MyModule.js’;//es6

使用 loader

var MyModule = require(‘./MyModule.js’);//commonjs

webpack 开发环境与生育环境

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

webpack 分割 vendor 代码和使用工作代码

*加载CSS

webpack develop server

安装css-loader : npm install css-loader style-loader
require(“style!css!
../css/main.css”)//加载CSS style!css!是声称这几个模块是CSS
style!css!能够不写 在loaders里面配备音讯即可

安装 webpack-dev-server

import “../css/main.css”;//ES6引入情势

启动 webpack-dev-server

*安顿文件

代码监控

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

自动刷新

module.exports = {

热加载 (hot module replacement)

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

output: {

在 webpack.config.js 中配置 webpack develop server

path: ‘./dist’,

2.2.1 webpack 介绍

    publicPath: './dist/',

    filename: "bundle.js"

},

module: {

    loaders: [

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

    ]

}

webpack 是什么

};

webpack is a module bundler. webpack takes modules with dependencies and
generates static assets representing those modules

多少个入口文件

webpack
是一个模块打包工具,输入为带有爱抚关系的模块集,输出为包装合并的前端静态资源。在上一节的前端工程化中,已经介绍过,webpack
是同时协助 英特尔 和 CommonJs 的模块定义形式,不仅如此,webpack
能够将其余前端资源视为模块,如 css,图片,文本。

var path = require(‘path’);

何以要引入新的包装工具

module.exports = {

在 webpack 出现以前,已经有了部分包装工具,如 Browserify,
那为什么不优化那一个工具,而是重复造轮子?

entry: {

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

},

output: {

webpack 此前的包装工具工具作用单一,只好完结一定的义务,可是 web
前端工程是纵横交错的,一个 webapp 对于事情代码的必要或者有:

path: ‘./dist’,

代码可以分块,达成按需加载

    publicPath: './dist/',

    filename: "bundle.js"

},

module: {

    loaders: [

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

    ]

}

首屏加载时间要尽量裁减

};

须求集成一些第三方库

加载器配置

对于模块打包工具,单一的支撑 CommonJs
的打包在大型项目中是不够用的,为了满意一个大型项目标前端必要,那么一个装进工具应该包蕴部分那么些功效:

那里必要在output模块里面安装publicPath否则CSS背景图片等出口有问题

支撑七个 bundler 输出 -> 解决代码分块问题

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;

webpack 的出现正式为了解决那几个题材,在 webpack 中,提供了一下这几个职能:

//那是在另一个文书
var index=require(“./content.js”); // 添加content.js

代码分块: webpack
有两序列型的模块信赖,一种是一起的,一种是异步的。在包装的历程中得以将代码输出为代码块(chunk),代码块可以落成按需加载。
异步加载的代码块通过分割点(spliting point)来确定。

document.getElementById(“box”).innerHTML=index.main();

Loaders: Webpack 本身只会处理
Javascript,为了兑现将其他资源也定义为模块,并转化为 Javascript,
Webpack 定义 loaders , 不相同的 loader 可以将相应的资源转化为 Javascript
模块。

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

智能的模块解析: webpack
可以很简单将第三方库转化为模块集成到花色代码中,模块的依靠可以用表明式的措施(那在其余包裹工具中是不曾扶助的),那种模块看重叫做动态模块着重。

一个位于package.json 的dependencies , 一个位于devDependencies里面

插件系统: webpack
的可定制化在于其插件系统,其自己的居多效果也是因而插件的措施达成,插件系统形成了
webpack 的生态,是的可以行使过多开源的第三方插件。

扩展:

webpack 要旨理想

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

webpack 的多少个为主:

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

万物皆模块:在 webpack 的世界中,除了
Javascript,其余任何资源都能够当作模块的方式引用

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

按需加载: webapp
的优化关键在于代码体积,当使用体积增大,达成代码的按需加载是刚需,这也是
webpack 出现的根本原因

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
基于可定制化的视角构建,通过插件系统,配置文件,可以兑现大型项目标定制必要。

webpack-dev-server

2.2.2 安装配置

  • 在 localhost:8080 建立一个 Web 服务器
    –devtool eval
  • 为您的代码成立源地址。当有任何报错的时候可以让你尤其精确地定位到文件和行号
    –progress
  • 显示合并代码进度
    –colors
  • Yay,命令行中突显颜色!
    –content-base build
  • 针对设置的输出目录

第一步:Node.js

即使须要浏览器自动刷新你必要在配置中伸张一个入口点。
webpack.config.js
**entry: [ ‘webpack/hot/dev-server’,
‘webpack-dev-server/client?http://localhost:8080’,
path.resolve(__dirname, ‘app/main.js’) ],

webpack 是 Node 达成,首先需求到 Node.js 下载安装最新版本的 Node.js

**

第二步:webpack-cli

Node.js 安装好之后,打开命令行终端,通过 npm 命令安装:

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

为了采用 webpack,先新建一个空前端项目,创设一个索引,目录结构如下:

.
├── index.html // 入口 HTML
├── dist // dist 目录放置编译过后的公文文件
└── src // src 目录放置源文件
└── index.js // 入口 js
其中 html 内容:

<!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 内容为:

alert(‘hello world webpack’);
第四步:在项目中设置 webpack

// 开端化 package.json, 依照提醒填写 package.json 的有关新闻
$ npm init

// 下载 webpack 依赖
// –save-dev 表示将依靠添加到 package.json 中的 ‘devDependencies’
对象中
$ npm install webpack –save-dev

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

dev server 可以兑现一个基于 node + express 的前端 server

$ npm install webpack-dev-server –save-dev
2.2.3 webpack 使用

指令行调用

在事先创造的目录下执行:

$ webpack src/index.js dist/index.js
实施成功未来会油可是生如下音讯:

Hash: 9a8e7e83864a07c0842f
Version: webpack 1.13.1
Time: 37ms
Asset Size Chunks Chunk Names
index.js 1.42 kB 0 [emitted] main
[0] ./src/index.js 29 bytes {0} [built]
可以查看 dist/index.js 的编译结果:

/******/ (function(modules) { // webpackBootstrap
// ………. UMD 定义内容
/******/ })
/************************************************************************/
/******/ ([
/* 0 /
/
**/ function(module, exports) {
// index.js 的内容被打包进去
alert(‘hello world webpack’);

/***/ }
/******/ ]);
在浏览器中开辟 index.html :

配备文件

以命令执行的措施需求填写很长的参数,所以 webpack
提供了经过安顿的格局举行,在项目目录下创建 webpack.config.js 如下:

var webpack = require(‘webpack’)
module.exports = {
entry: ‘./src/index.js’,
output: {
path: ‘./dist/’,
filename: ‘index.js’
}
}
执行:

$ webpack
会和透过命令执行有平等的输出

2.2.4 webpack 配置

entry 和 output

webpack 的布署中至关紧要的五个布局 key 是,entry 和 output。

{
entry: [String | Array | Object], // 入口模块
output: {
path: String, // 输出路径
filename: String // 输有名称或称谓 pattern
publicPath: String // 指定静态资源的地点
… // 其余安插
}
}
纯净入口

一经唯有一个输入文件,可以有如下两种配备方式

// 第一种 String
{
entry: ‘./src/index.js’,
output: {
path: ‘./dist/’,
filename: ‘index.js’
}
}

// 第二种 Array
{
entry: [‘./src/index.js’],
output: {
path: ‘./dist/’,
filename: ‘index.js’
}
}

// 第三种 Object
{
entry: {
index: ‘./src/index.js’,
},
output: {
path: ‘./dist/’,
filename: ‘index.js’
}
}
多少个输入文件

当存在多少个输入时 ,可以应用 Array 的主意,比如凭借第三方库 bootstrap
,最后 bootstrap 会被追加到打包好的 index.js 中,数组中的最后一个会被
export。

{
entry: [‘./src/index.js’, ‘./vendor/bootstrap.min.js’],
output: {
path: ‘./dist’,
filename: “index.js”
}
}
最后的输出结果如:

/******/ ([
/* 0 /
/
**/ function(module, exports, webpack_require) {

__webpack_require__(1);

// export 最后一个
module.exports = __webpack_require__(2);

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

alert('hello world webpack');

// },
/
2 /
/
/ function(module, exports) {
// bootstrap 的始末被追加到模块中
console.log(‘bootstrap file’);

/***/ }
/******/ ])
多个包裹目的

位置的例子中都是包装出一个 index.js
文件,即使项目有八个页面,那么须求打包出多少个文件,webpack
可以用对象的艺术配置四个包裹文件

{
entry: {
index: ‘./src/index.js’,
a: ‘./src/a.js’
},
output: {
path: ‘./dist/’,
filename: ‘[name].js’
}
}
最终会卷入出:

.
├── a.js
└── index.js
文件名称 pattern

[name] entry 对应的称号

[hash] webpack 命令执行结果展现的 Hash 值

[chunkhash] chunk 的 hash

为了让编译的结果名称是唯一的,可以利用 hash 。

2.2.5 webpack 支持 Jsx

今昔大家早已可以动用 webpack 来打包基于 CommonJs 的 Javascript
模块了,但是还没办法解析 JSX 语法和 Es6 语法。上边大家将应用 Babel 让
webpack 可以分析 Es6 和 Babel

先是步:npm install 看重模块

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

// react 相关的模块
$ npm install react react-dom –save
第二步:webpack.config.js 中添加 babel loader 配置

{
entry: {
index: ‘./src/index.js’,
a: ‘./src/a.js’
},
output: {
path: ‘./dist/’,
filename: ‘[name].js’
},
module: {
loaders: [{
test: /.js$/,
exclude: /node_modules/,
loader: ‘babel’,
query: {
presets: [‘es2015’, ‘stage-0’, ‘react’]
}
}]
}
}
第三步: 修改 index.js 为 React 的语法

src/index.js 内容改为:

Es6 的知识在后头的章节中助教,近日大家暂时以 Es5
的主意来写,不过配置已经协助了 Es6 的编译,通晓 Es6 的读者也可以直接写
Es6

// 通过 require 的情势重视 React,ReactDOM
var React = require(‘react’);
var ReactDOM = require(‘react-dom’);

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

ReactDOM.render(
<Hello name=”World” />,
document.getElementById(‘AppRoot’)
);
第四步:运行 webpack

$ webpack
履行结果:

Hash: ae2a037c191c18195b6a
Version: webpack 1.13.1
Time: 1016ms
Asset Size Chunks Chunk Names
a.js 1.42 kB 0 [emitted] a
index.js 700 kB 1 [emitted] index

  • 169 hidden modules
    浏览器中开辟 index.html 会呈现 Hello World

2.2.6 webpack loaders

在配置 JSX 的进度中,使用到了 loader, 后面早已介绍过 webpack
的中央成效包罗 loader,通过 loader 可以将随机资源转化为 javascript
模块。

loader 定义

Loaders are transformations that are applied on a resource file of your
app.
(Loaders 是选取中源码文件的编译转换器)

也就是说在 webpack 中,通过 loader 可以兑现 JSX 、Es6、CoffeeScript
等的更换

loader 功能
loader 管道:在同一体系型的源文件上,可以同时执行七个 loader , loader
的履行措施可以接近管道的艺术,管道实施的不二法门是从右到左的形式loader
可以辅助同步和异步
loader 能够吸纳安排参数

loader 可以经过正则表明式或者文件后缀指定特定类型的源文件

插件可以提需求 loader 越来越多效益

loader 除了做文件转换以外,仍可以够创制额外的文书

loader 配置

增产 loader 可以在 webpack.config.js 的 module.loaders 数组中新增一个
loader 配置。

一个 loader 的布置为:

{
// 通过扩张名称和正则表明式来配独资源文件
test: String ,
// 匹配到的资源会应用 loader, loader 可以为 string 也足以为数组
loader: String | Array
}
惊叹号和数组可以定义 loader 管道:

{
module: {
loaders: [
{ test: /.jade$/, loader: “jade” },
// => .jade 文件应用 “jade” loader

        { test: /\.css$/, loader: "style!css" },
        { test: /\.css$/, loaders: ["style", "css"] },
        // => .css 文件应用  "style" 和 "css" loader  
    ]
}

}
loader 可以安插参数

{
module: {
loaders: [
// => url-loader 配置 mimetype=image/png 参数
{
test: /.png$/,
loader: “url-loader?mimetype=image/png”
}, {
test: /.png$/,
loader: “url-loader”,
query: { mimetype: “image/png” }
}

    ]
}

}
使用 loader

第一步: 安装

loader 和 webpack 一样都是 Node.js 落成,发布到 npm 当中,需求运用
loader 的时候,只要求

$ npm install xx-loader –save-dev

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

{
entry: {
index: ‘./src/index.js’,
a: ‘./src/a.js’
},
output: {
path: ‘./dist/’,
filename: ‘[name].js’
},
module: {
loaders: [{
test: /.js$/,
exclude: /node_modules/,
loader: ‘babel’,
query: {
presets: [‘es2015’, ‘stage-0’, ‘react’]
}
}, {
test: /.css$/,
loader: “style-loader!css-loader”
}]
}
}
第三步:使用

前方大家曾经选择过 jsx loader 了, loader 的利用形式有多种

在配备文件中配备

显示的通过 require 调用

一声令下行调用

展现的调用 require 会伸张模块的耦合度,应尽量防止那种艺术

以 css-loader 为例子,在项目 src 下边创制一个 css

src/style.css

body {
background: red;
color: white;
}
修改 webpack 配置 entry 添加

entry: {
index: [‘./src/index.js’, ‘./src/style.css’]
}
实践 webpack 命令然后打开 index.html 会看到页面背景被改为革命。

最终的编译结果为:

….
function(module, exports, webpack_require) {
exports = module.exports = webpack_require(171)();
exports.push([module.id, “\nbody {\n background: red;\n color:
white;\n}\n”, “”]);
}
….
可以看看 css 被转接为了 javascript, 在页面中不用调用 <link
rel=”stylesheet” href=””> 的主意, 而是使用 inline
的<style>…..</style>

除此以外一种格局是一向 require, 修改 src/index.js:

var css = require(“css!./style.css”);
编译结果一致。

2.2.7 webpack 开发条件与生育环境

前端开发环境一般分为三种,开发环境和转变环境,在付出条件中,可能大家须要日志输出,sourcemap
,错误报告等职能,在扭转环境中,须要做代码压缩,hash
值生成。三种环境在其余的部分安顿上也说不定两样。

因此为了不一样,我们能够创立几个文件:

webpack.config.js // 开发条件

webpack.config.prod.js // 生产条件

生儿育女环境 build 用如下命令:

$ webpack –config webpack.config.prod.js
在本章深入 webpack 小节中会愈来愈多的牵线生产条件中的优化

2.2.8 webpack 插件

webpack 提供插件机制,可以对每趟 build 的结果开展处理。配置 plugin
的法门为在 webpack.config.js 中加上:

{
plugins: [
new BellOnBundlerErrorPlugin()
]
}
plugin 也是一个 npm 模块,安装一个 plugin :

$ npm install bell-on-bundler-error-plugin –save-dev
2.2.9 webpack 分割 vendor 代码和使用工作代码

在上头的 jsx 配置中,大家将 React 和 ReactDOM
一起打包进了项目代码。为了兑现业务代码和第三方代码的分手,我们可以接纳
CommonsChunkPlugin 插件.

修改 webpack.config.js

{
entry: {
index: ‘./src/index.js’,
a: ‘./src/a.js’,
// 第三方包
vendor: [
‘react’,
‘react-dom’
]
},
output: {
path: ‘./dist/’,
filename: ‘[name].js’
},
module: {
loaders: [{
test: /.js$/,
exclude: /node_modules/,
loader: ‘babel’,
query: {
presets: [‘es2015’, ‘stage-0’, ‘react’]
}
}, {
test: /.css$/,
loader: “style-loader!css-loader”
}]
},
plugins: [
new webpack.optimize.CommonsChunkPlugin(/* chunkName= /”vendor”, /
filename= */”vendor.bundle.js”)
]
}
执行 webpack 命令,输出日志:

Hash: f1256dc00b9d4bde8f7f
Version: webpack 1.13.1
Time: 1459ms
Asset Size Chunks Chunk Names
a.js 109 bytes 0 [emitted] a
index.js 10.9 kB 1 [emitted] index
vendor.bundle.js 702 kB 2 [emitted] vendor
[0] multi vendor 40 bytes {2} [built]
[0] multi index 40 bytes {1} [built]

  • 173 hidden modules
    index.js 体积变小了,多出了 vendor.bundle.js

2.2.10 webpack develop server

在前端开发的进程中,寻常须要启动一个服务器,把开发打包好的前端代码放在服务器上,通过访问服务器访问并测试(因为可以稍微情状必要ajax 请求)。 webpack 提供了一个根据 node.js Express 的服务器 –
webpack-dev-server
来援救我们简化服务器的搭建,并提供服务器资源访问的部分概括部署。

安装 webpack-dev-server

$ npm install webpack-dev-server -g
启动 webpack-dev-server

$ webpack-dev-server –content-base ./
–content-base ./ 参数表示将当前目录作为 server 根目录。
命令启动过后,会在 8080 端口启动一个 http
服务,通过拜访http://localhost:8080/index.html
可以访问 index.html 内容。

若是访问提示报错:

Uncaught ReferenceError: webpackJsonp is not defined
原因是 html 中从不引用 vendor.bundle.js, 修改 html :

<script src=”dist/vendor.bundle.js”></script>
<script src=”dist/index.js”></script>
修改 index.html 过后可以看来科学结果

代码监控

webpack-dev-server 除了提供 server 服务以外,
还会监控源文件的修改,若是源文件改变了,会调用 webpack 重新包装

修改 style.css 中的内容为:

body {
background: whitesmoke;
color: #333;
font-size: 100px;
}
可以见见输出以下日志:

[168] ./~/react/lib/renderSubtreeIntoContainer.js 466 bytes {2}
[built]
webpack: bundle is now VALID.
webpack: bundle is now INVALID.
Hash: cc7d7720b1a0fcbef972
Version: webpack 1.13.0
Time: 76ms
chunk {0} a.js (a) 32 bytes {2}

  • 1 hidden modules
    chunk {1} index.js (index) 10.3 kB {2}
    [170] ./~/css-loader!./src/style.css 230 bytes {1} [built]
  • 5 hidden modules
    chunk {2} vendor.bundle.js (vendor) 665 kB
  • 168 hidden modules
    webpack: bundle is now VALID.
    以此时候证实代码已经修改了,可是这么些时候刷新浏览器过后,背景是没有更改的,原因是
    webpack-dev-server 的打包结果是位于内存的,查看 dist/index.js
    的内容实在是从未有过改动的,这怎么访问内存中的打包内容吧?

修改 webpack.config.js 的 output.publicPath:

output: {
path: ‘./dist/’,
filename: ‘[name].js’,
publicPath: ‘/dist’
// webpack-dev-server 启动目录是 /, /dist
目录是包装的目的目录相对于启动目录的门径
},
再一次开动

$ ctrl + c 截止进度
$ webpack-dev-server
修改 style.css 再刷新页面,修改的始末会反映出去。

自动刷新

地方的配置已经能不辱职责自动监控代码,每便修改完代码,刷新浏览器就足以见到最新结果,不过webpack-dev-server 还提供了电动刷新成效,有二种情势。

Iframe 模式

修改访问的门路:
http://localhost:8080/index.html
->
http://localhost:8080/webpack-dev-server/index.html
。那几个时候每一回修改代码,打包完毕将来都会自动刷新页面。

不要求万分陈设,只用修改路径

采取被平放了一个 iframe 内部,页面顶部可以突显打包进程音讯

因为 iframe 的涉嫌,如果选拔有多少个页面,不能看出眼前采取的 url 新闻

inline 模式

开行 webpack-dev-server 的时候添加 –inline 参数

急需添加 –inline 配置参数

不曾顶部新闻提示条,提醒音讯在控制夏洛特表现

热加载 (hot module replacement)

webpack-dev-server
还提供了模块热加载的章程,在不刷新浏览器的规范下,应用新型的代码更新,启动
webpack-dev-server 的时候添加 –inline –hot 参数就可以体会。

$ webpack-dev-server –inline –hot
修改代码在浏览器控制哈博罗内会看到那般的日记输出:

[HMR] Waiting for update signal from WDS…
vendor.bundle.js:670 [WDS] Hot Module Replacement enabled.
2vendor.bundle.js:673 [WDS] App updated. Recompiling…
vendor.bundle.js:738 [WDS] App hot update…
vendor.bundle.js:8152 [HMR] Checking for updates on the server…
vendor.bundle.js:8186 [HMR] Updated modules:
vendor.bundle.js:8188 [HMR] – 245
vendor.bundle.js:8138 [HMR] App is up to date.
在 webpack.config.js 中配置 webpack develop server

修改 webpack.config.js 添加:

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

$ webpack-dev-server
webpack-dev-server 还提供了别的的一对效应, 如:

配置 proxy

访问 node.js API

和水土保持的 node 服务集成

基于那一个成效率够已毕广大自定义的布局。

发表评论

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

网站地图xml地图