webpack使用了解,致咱们肯定组件化的Web

by admin on 2019年2月6日

致大家必然组件化的Web

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

原稿出处:
AlloyTeam   

那篇小说将从两年前的五回技术争议起来。争论的聚焦就是下图的三个目录分层结构。我说按模块划分好,他说您傻逼啊,当然是按资源划分。

必发88 1 《=》必发88 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

方法之间线性跳转,你大约也能感受那样代码弊端。随着页面逻辑更是复杂,那条”进程线“也会愈加长,并且愈来愈绕。加之缺少专业约束,其余类型成员依照各自须求,在”进度线“加插各自逻辑,最后那个页面的逻辑变得难以维护。

必发88 3

开发须求兢兢业业,生怕影响“过程线”前面正常逻辑。并且每五遍加插或改动都是bug泛滥,无不令产品有关人士一律悲天悯人。

 页面结构模块化

据悉下边的面向进度的标题,行业内也有不少缓解方案,而我辈组织也总括出一套成熟的化解方案:Abstractjs,页面结构模块化。大家可以把大家的页面想象为一个乐高机器人,需求差异零件组装,如下图,即使页面划分为tabContainer,listContainer和imgsContainer多个模块。最终把那些模块add到末了的pageModel里面,最后利用rock方法让页面启动起来。

必发88 4
(原经过线示例图)

必发88 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依旧有一段距离,至少满意不断我的”理想目录结构“。

webpack使用了解,致咱们肯定组件化的Web。 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”感到失望必发88 6,依然“太好了是react+webpack”不用再学三回新框架的开心必发88 7。无论如何上面的内容不会让您失望的。

一,组件生命周期

必发88 8

React天生就是强制性组件化的,所以可以从根本性上化解面向进度代码所带来的辛劳。React组件自身有生命周期方法,能够满意“接口规范化”能力点。并且跟“页面结构模块化”的所封装抽离的多少个措施能挨个对应。别的react的jsx自带模板成效,把html页面片直接写在render方法内,组件内聚性尤其严密。

鉴于React编写的JSX是会先生成虚拟Dom的,需求时机才真正插入到Dom树。使用React必要求领悟组件的生命周期,其生命周期三个情景:

Mount: 插入Dom

Update: 更新Dom

Unmount: 拔出Dom

mount那单词翻译扩充,嵌入等。我倒是提议“插入”更好了解。插入!拔出!插入!拔出!默念两回,懂了没?别少看黄段子的力量,

必发88 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八个状态方法都能成就一大半零部件,不必惧怕。

回来组件化的主旨。

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

必发88 10

咱俩换算成React生命周期方法:

必发88 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写的代码照旧很丑。

必发88 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正好合乎需要点,一方面填补组件化能力点,另一方协理我们健全组件化的完好构建环境。

首先要表明一点是,webpack是一个模块加载打包工具,用于管理你的模块资源看重打包难题。那跟大家耳熟能详的requirejs模块加载工具,和grunt/gulp构建工具的定义,多多少少有些出入又有点雷同。

必发88 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_webpack使用了解,致咱们肯定组件化的Web。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模块化实践

很欣喜,你能读书到此地。近来大家的零部件完结度相当的高,资源内聚,易于组合,作用域独立互不污染。。。。等等必发88 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年的7-Up,好好庆祝一下。不是吗?

必发88 15

 

 组件化之路还在此起彼伏

webpack和react还有很多新卓殊重要的特征和效益,介于本文仅仅围绕着组件化的为主导,没有种种演讲。其余,配搭gulp/grunt补充webpack打造能力,webpack的codeSplitting,react的零部件通讯难题,开发与生产环境布署等等,都是全体大型项目方案的所不可不的,限于篇幅难点。可以等等我更新下篇,或我们可以自动查阅。

只是,不得不再安利一下react-hotloader神器。热加载的开发方式相对是下一代前端开发必备。严俊说,一经没有了热加载,我会很坚决地遗弃那套方案,纵然那套方案再怎么好好,我都讨厌react要求5~6s的编译时间。但是hotloader可以在自我不刷新页面的意况下,动态修改代码,而且不单单是样式,连逻辑也是即时生效。

必发88 16

如上在form表单内。使用热加载,表单不须求再度填写,修改submit的逻辑马上见效。那样的开销功能真不是增长仅仅一个程度。必须安利一下。

 

或者你发现,使用组件化方案以后,整个技术栈都被更新了一番。学习费用也不少,并且可以预言到,基于组件化的前端还会众多相差的标题,例如性能优化方案须要重新考虑,甚至最中央的组件可复用性不必然高。前面很长一段时间,要求大家不停锻练与优化,探求最优的前端组件化之道。

起码大家可以想像,不再担心自己写的代码跟某个何人什么人冲突,不再为找某段逻辑在七个文本和形式间持续,不再copy一片片逻辑然后改改。大家每一次编写都是可采用,可构成,独立且内聚的零部件。而各类页面将会由一个个嵌套组合的机件,相互独立却互相功效。

 

对此如此的前端将来,有所指望,不是很好呢

从那之后,感谢你的翻阅。

1 赞 6 收藏 1
评论

必发88 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模块可以省略不写后缀名
必发88,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、自定义公共模块提取:
在小说初步大家使用了 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安装到项目标依靠中,那样就足以行使项目本地版本的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地图