利用webpack实现js/css模块化开发

什么是模块化开发?

对前端工程化的参考资料:https://github.com/fouber/blo...
前端的工程化构建开发不只仅停留在‘压缩’、‘校验’、‘合并’,模块化构建可使项目的扩展性、代码的复用性和可维护性大大提升。在解决基本的开发效率和运行效率以后,前端团队要思考维护效率。模块化是当前前端最流行的开发手段。
模块化是一种处理复杂系统分解为更好的管理模块的方式。它能够经过不一样的组件设定不一样的功能,把一个问题分解成多个小的独立的、相互做用的组件。感受就像是在拼图。
模块化的好处:
提升代码的重用率
提升开发效率、减小沟通成本
下降耦合
更好实现代码的快速迭代
便于代码的维护javascript

一、css模块化

css模块化开发基本都是在less、sass、stylus等预处理器的import/mixin特性支持下实现的。css

二、js模块化

js模块化方案有AMD/CommonJS/ES6 Module等
使用webpack模块的各类方式的依赖关系:
一、ES2015 import语句
二、CommonJS require()语句
三、AMD define 和 require语句
四、css/sass/less文件的 @import 语句
五、样式 (url(...)) 或 HTML文件(<img src=...>) 中的图片连接(image url)
webpack的优点
一、支持CommonJS 和 AMD 模块。
二、支持模块加载器和插件机制,可对模块灵活定制。babel-loader支持ES6
三、能够经过配置,打包成多个文件。有效的利用浏览器的缓存。
四、将样式文件和图片等静态资源视为模块进行打包。配合loader加载器,对资源进行处理。前端

下面介绍javascript模块化编程:

1、原始写法
模块是实现特定功能的一组方法。java

function m1(){
    //''''
}

function m2(){
    //''''
}

上面的函数m1()和m2(),组成一个模块。使用的时候,直接调用就ok了。
这种作法的缺点就是污染了全局变量,没法保证不与其余模块发生变量名冲突,并且模块成员之间看不出直接联系。
2、对象的写法
将模块写成一个对象,全部的模块成员都在这个对象里。node

var module = new Object({
        _count : 0,
        m1: function(){
            console.log(this._count)
        },
        m2:function(){
            console.log(this)
        }
    })
    module.m1()
    module._count = 5
    module.m2()

上面的函数m1()和m2(),都封装在module对象里。使用的时候直接调用这个对象的属性。jquery

module.m1();
输出:0

可是这样的写法会暴露全部的模块成员,内部状态会被外部状态改写,好比:webpack

module._count = 5
module.m1()
输出:5

3、当即执行函数
使用当即执行函数能够达到不暴露私有成员的目的。git

var module_1 = (function(){
        var _count = 1;
        var m1 = function(){
            console.log(_count)
        };
        var m2 = function(){
            console.log(this)
        };
        return {
            m1:m1,
            m2:m2
        }
    })();
    module_1.m1()
    module_1.m2()

使用上面的写法,外部代码没法读取内部的_count变量。github

介绍如何规范的使用模块

JavaScript模块规范共有两种:CommonJS 和 AMD。
为何要有模块?
有了模块,咱们就能够方便的使用别人的代码,想要什么功能,就加载什么模块。
1、CommonJS
用于服务端模块化编程:
一个文件就是一个模块,require方法用来加载模块,该方法读取一个文件并执行,最后返回文件内部的module.exports对象;
require是默认读取 .js 文件,因此require(模块名)能够不写后缀;
同步加载,因为服务端加载的模块通常在本地,因此能够这样;可是客户端若是一个模块过大就会致使页面“假死”;

node.js的项目,将JavaScript语言用于服务器编程,在浏览器环境下,没有模块也是能够的。但在服务器端,必定要有模块,与操做系统和其余应用程序互动,否侧就无法编程。
node.js的模块系统,就是参考CommonJS规范实现的。在CommonJS中,有一个全局性的方法require(),用于加载模块。假定有一个数学math.js,就能够像下面这样加载。web

var math = require('math');

而后,就能够调用模块提供的方法;

var math = require('math');
math.add(2,3); //5

module.exports属性表示当前模块对外输出的接口,其余模块文件加载该模块,实际上就是读取module.exports变量;为了方便用exports,exports指向module.exports;即exports = module.exports = {};
exports.xxx至关于在导出的对象上添加属性,该属性对调用模块可见;
exports = 至关于给exports从新赋值,这样就切断了和module.exports的关联,调用模块就不能访问exports的对象及其属性。
在浏览器环境:
CommonJS不使用于浏览器环境。若是在浏览器中运行,会有一个大问题;

var math = require('math');
math.add(2,3)

在第二行math.add(2,3),在第一行require('math')以后运行,所以必须等math.js加载完毕。若是加载时间很长,整个应用就会停在这里。
这对服务器不是问题,由于全部的模块都存在本地硬盘,能够同步加载完成,等待时间就是硬盘的读取时间。可是,在浏览器,由于模块都在服务器端,等待时间取决于网速的快慢,可能要等很长时间,浏览器处于“假死”状态。
所以,浏览器端的模块,不能采用“同步加载”,只能采用“异步加载”。这就是AMD的产生的背景。

2、AMD
AMD是“Asynchronous Module Definition”的缩写,意思是“异步模块定义”。它采用异步方式加载模块,模块的加载不影响它后面的语句的运行。全部依赖这个模块的语句,都定义在一个回调函数中,等到加载完成以后,这个回到函数才会运行。
AMD也采用require()语句加载模块,可是不一样于CommonJS,它要求两个参数,

require([module],callback);

第一个参数[module],是一个数组,里面的成员就是要加载的模块,第二个参数callback,则是加载成功以后的回调函数。若是将前面的代码改写成AMD形式,就是下面的形式:

require(['math'],function(math){
    math.add(2,3);
})

math.add()与math模块加载不是同步的,浏览器不会发生‘假死’。因此AMD比较适合浏览器环境。

3、require.js的用法:
require.js(前端模块化管理的工具库)实现js文件的异步加载,避免网页失去响应;管理模块之间的依赖性,便于代码的编写和维护。
主模块的写法:
main.js称为是“主模块”,意思是整个网页的入口代码。全部的代码都从这开始运行。主模块依赖于其余模块,这时就使用AMD规范定义的require()函数。

//main.js
require(['moduleA','moduleB','moduleC'],function(moduleA, moduleB, moduleC){
//some  code here
});
require()函数接受两个参数。第一个参数是一个数组,表示所依赖的模块,
上例就是['moduleA','moduleB','moduleC'],即主模块依赖这三个模块;
第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。
加载的模块会以参数形式传入该函数,从而在回调函数内部就可使用这些模块。
require()异步加载moduleA,moduleB和moduleC,浏览器不会失去响应;它指定的回调函数,只有前面的模块都加载成功后,才会运行,解决了依赖的问题。

假定主模块依赖jquery、underscore和backbone三个模块,main.js就能够这样写:

require(['jquery','underscore','backbone'],function($,_,Backbone){

//some code here
})
requery.js是先加载jQuery、underscore和backbone,而后在运行回调函数。主模块的代码就写在回调函数中。

4、模块的加载
主模块的依赖模块是['jquery','underscore','backbone']。默认状况下,require.js假定这三个模块于main.js在同一个目录,文件名分别是jquery.js、
underscore和backbone.js,而后自动加载。
使用require.config()方法,咱们能够对模块的加载行为进行自定义。
require.config()就写在主模块(main.js)的头部。参数就是一个对象,
这个对象的paths属性指定各个模块的加载路径。

require.config({
    paths:{
        "jquery":"jquery.min",
        "underscore":"underscore.min",
        "backbone":"backbone.min"
    }
});
上面的代码路径默认与main.js在同一个目录(js子目录)。若是这些模块在
其余目录,好比js/lib目录,则有两种写法:
一种是逐一指定路径。
require.config({
    paths:{
        "jquery":"lib/jquery.min",
        "underscore":"lib/underscore.min",
        "backbone":"lib/backbone.min"
    }
});
另外一种则是直接改变基目录(baseUrl)
require.config({
    baseUrl:"js/lib",
    paths:{
        "jquery":"jquery.min",
        "underscore":"underscore.min",
        "backbone":"backbone.min"
    }
});
若是某个模块在另外一台主机上,也能够直接指定它的网址,好比,
    require.config({
        path:{
            "jquery":
            "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min"
        }
    })
requiry.js要求,每个模块是一个单独的js文件。这样的话,若是加载多个
模块,就会发出屡次HTTP请求,会影响网页的加载速度。所以,require.js提供一个优化工具,
当模块部署完毕之后,能够用这个工具将多个模块合并在一个文件中,减小http请求。
相关文章
相关标签/搜索