【亚洲必赢官网】webpack使用掌握,致我们终将组件化的Web

致我们必将组件化的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原生也能帮忙了。

【亚洲必赢官网】webpack使用掌握,致我们终将组件化的Web。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请求我提出在威尔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正好合乎必要点,一方面填补组件化能力点,另一方支持大家健全组件化的完整构建环境。

先是要申澳优(Aptamil)点是,webpack是一个模块加载打包工具,用于管理你的模块资源珍惜打包问题。那跟我们耳熟能详的requirejs模块加载工具,和grunt/gulp构建工具的定义,多多少少有些出入又有点雷同。

亚洲必赢官网 13

第一webpak对于CommonJS与英特尔同时援救,满意大家模块/组件的加载格局。

JavaScript

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

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

JavaScript

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

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

理所当然最有力的,最出色的,当然是模块打包功用。这正是这一效应,补充了组件化资源器重,以及完整工程化的能力

据悉webpack的设计意见,所有资源都是“模块”,webpack内部贯彻了一套资源加载机制,可以把想css,图片等资源等有依靠关系的“模块”加载。那跟大家采取requirejs那种只有处理js大大不同。而那套加载机制,通过一个个loader来落成。

 

JavaScript

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

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

上边一份不难的webpack配置文件,留意loaders的安插,数组内一个object配置为一种模块资源的加载机制。test的正则为同盟文件规则,loader的为匹配到文件将由什么加载器处理,多个电脑之间用相隔,处理顺序从右到左。

 

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

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

图片资源通过url-loader加载器,配置参数limit,控制少于10KB的图片将会base64化。

 资源文件如何被require?

JavaScript

// 加载组件自身css require(‘./slider.css’); // 加载组件爱戴的模块 var
Clip = require(‘./clipitem.js’); // 加载图片资源 var spinnerImg =
require(‘./loading.png’);

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

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

JavaScript

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

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

webpack编译之后,输出文件视乎乱糟糟的,但事实上每一个资源都被封装在一个函数体内,并且以编号的款型标记(注释)。这么些模块,由webpack的__webpack_require__其间方法加载。入口文件为编号0的函数index.js,可以看到__webpack_require__加载其他编号的模块。

css文件在号码1,由于采纳css-loader和style-loader,编号1-4都是拍卖css。其中编号2大家得以看大家的css的string体。最后会以内联的艺术插入到html中。

图片文件在数码6,可以看出exports出base64化的图片。

 组件一体输出

JavaScript

// 加载组件自身css require(‘./slider.css’); // 加载组件看重的模块 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年的七喜,好好庆祝一下。不是啊?

亚洲必赢官网 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是插件项,那里运用了一个康芒斯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地图