美文网首页前端微说集
前端模块化的四种规范

前端模块化的四种规范

作者: zzglovecoding | 来源:发表于2020-06-19 00:54 被阅读0次

    前言:前端模块化出现的缘由和实现的一些弊端

    出现的缘由

    为什么会出现前端模块化呢,要想实现功能的复用,就需要把代码引入重复利用,如果不使用模块化,我们之前会使用的方法有哪些呢?
    1.直接定义全局function的方式,那么会出现函数命名污染的情况,并且各个部分之间的关系也看不出来。
    2.在命名空间(name space)中定义方法,定义一个obj = {function1() {},function2(){}};这样有个问题就是函数内部的成员可以被随意修改,很不安全。
    3.通过IIFE模式,也就是函数自调用闭包的方式,暴露给window,但是如果存在模块之间的依赖,就会很麻烦。
    4.IIFE增强模式:引入依赖。为了解决上面的问题,就出现了IIFE增强模式,说白了就是传参把其他的模块给传进去,就出现了先后顺序很重要的问题,如果前面的都还没挂载到window上面,此时运行后面的js代码肯定就是undefined。
    因此,为了解决1.命名污染。2.提升代码的维护性。3.更好的分离代码,实现按需加载。4提高代码的复用性等,我们需要采用模块化规范,这里就介绍比较常用的四种模块化的规范,分别是commonJS,AMD,CMD和ES6四种。

    一、commonJS

    1.commonJS-node

    node.js原生就支持commonJS的规范,所以在node.js中可以直接使用,不需要引入其他的包了。commonJS是在服务端跑的,所以都是读的本地磁盘中的内容,不存在异步的问题,所以require过来就直接可以用,因为是同步的,所以会有阻塞的情况,但是在浏览器端,一般这些js文件也就是模块,很多是通过网络请求过来的,是异步的所以使用commonJS就不是那么合适。
    语法就是exports和require两个。

    1.1exports可以一起导出,也可以分开导出,require直接导入

    module1.png

    上面是module1内部的代码,可以module.exports = {}的方式,exports就是一个对象


    module2.png

    上面是module2的内部代码,exports对象也可以是一个方法

    module3.png

    上面是module3的内部代码,通过exports.foo和exports.bar的方式分开添加

    app.png

    上面是app.js的内部代码,可以看到直接通过require('路径')的方式把模块直接给引入过来了,非常方便

    1.2 关于package.json

    package.png

    package.json是通过npm.init初始化的时候就产生的记录本包的详细信息的文件,包含了name(这个name不能包含中文,也不能有大写,在老版本的npm的时候,不具有自动转小写的功能),version以及author等内容,并且通过npm install uniq -save(运行时依赖,这里的save在npm5之后,不加save也默认就是save)或者npm install uniq --save-dev(开发时依赖),在dependencies中记录

    1.3 执行app.js

    因为是在node环境中执行,当前webStorm执行也是用的node,不是在浏览器环境中,无论通过node app.js还是右键执行app.js都可以完成。

    1.4 commonJS的不足

    既然commonJS已经这么方便了,为啥会出现AMD和CMD以及ES6的后续的规范呢,就是因为commonJS是在node中实现的,也就是node环境中可以支持require和exports,但是在浏览器环境中,是不支持的,所以要想在浏览器端使用commonJS的规范的话,就必须使用browserify这种第三方包把代码给转换成浏览器端支持的代码,后面将写commonJS在浏览器端的实现。

    2.commonJS-Browserify

    由于前文中提到的commonJS规范在浏览器端无法适用的情况,我们需要引入一个第三方包也就是Browserify,把原本只能在node环境中跑的代码给转换成浏览器端可以使用的代码。
    browserify的安装(必须全局和局部都安装):
    ①、全局安装
    npm install browserify -g
    ②、局部安装
    npm install broserify --save-dev
    安装完成之后,运行browserify js/src/app.js -o js/dist/bundle.js


    browserify.png

    上述指令中的-o,代表的是output,后面js/dist/bundle.js就是输出的目标位置,没有dist目录的话会自动创建,而且这个命令运行之后,命令行不会有什么打印,不代表没执行成功。(这里其他module1,module2这些都没有变,和前面1当中的代码是一样的,只是在浏览器中执行了)


    script标签引入.png
    在html中通过script标签引入那个bundle.js就可以了,接下来在浏览器中执行。
    浏览器中执行结果.png
    上图就是在浏览器环境中执行的结果,如果script的标签src引入的不是这个bundle,直接是app.js的话,require这种语法,浏览器根本就不认识,就会出现下面的这个情况。
    不用browserify打包.png

    二、AMD规范

    AMD(Asynchronous Module Definition异步模块定义)规范相比于CMD来说应用得更加广泛一些。AMD是专门用于浏览器端的,模块的加载是异步的。
    AMD规范是通过Require.js实现的,所以需要下载Require.js文件。
    基本语法:
    ①、定义暴露模块:如果是定义没有依赖的模块
    define(function(){
    return 模块
    })
    如果是定义有依赖的模块
    define(['module1','module2'],function(module1,module2) {
    return 模块
    })
    ②、引入使用模块
    requirejs(['module1','module2'],function(m1,m2) {
    使用m1/m2
    })

    2.1没有AMD时候的模块化实现方式

    alert .png dataService.png app.png html.png

    如上图所示,在js文件夹中创建了alert和dataService两个模块,这些模块之间都是通过IIFE也就是立即执行函数来把模块内的方法暴露给window对象的,三者之间存在依赖关系,必须按照先后顺序加入script标签,先dataService,后alert再app.js这三个加载顺序,这就是没有AMD的时候的执行方法,就是暴露给window,但这样的缺陷是非常明显的,就是模块之间的依赖必须要手动去定好,不然一定会存在undefined的情况。

    2.2 采用AMD-RequireJS的方式实现模块化

    html.png

    上图是使用require.js来实现的方式,就是script标签的scr是require.js,但是有一个主js的入口,就是data-main属性,里面指定了主文件的入口。


    main.png

    上图就是main.js的代码。里面是一个立即执行函数,因为他不需要再向外暴露接口,直接就使用requirejs方法,把需要的模块名字传入,然后后面回调函数进行使用就可以了。


    alerter.png
    上面是alerter,他引入了dataService模块和jquery(必须小写)模块,回调函数中,就使用了其他的模块。
    dataService.png
    这个dataService,是不需要依赖其他模块的,所以没有传前面的数组,直接定义好,然后暴露接口就可以了。
    层级目录.png

    上面是层级目录,记得libs下面有这个require.js


    requirejs配置.png
    这个部分就是requirejs的配置,必须配置,否则根本不知道你数组里头引入,或者定义的时候,那个模块到底是谁,后面映射了路径。shim用来解决那些不支持AMD规范的js包的,就比如angular,本来就是不支持的,你配置了path也没用,配置shim就可以了,上面也可以配置baseUrl。

    三、CMD规范

    CMD规范用的相对少一些,是阿里开发的,但现在卖给外国人了,使用起来的语法有点像CommonJS和AMD的结合版,SeaJS实现了CMD规范,所以需要下载这个seajs。
    使用语法:
    ①、定义没有依赖的模块
    define(function(require,exports,module) {
    exports.xxx = value;
    module.exports = value;
    //这个和commonJS很像,关键就是那个exports对象
    })
    ②、定义有依赖的模块
    define(function(require,exports,module) {
    var module2 = require('./module2');
    require.async('./module3',function(m3) {
    ///使用module3,是异步的,到时候module3拿到了就给回调直接执行
    })
    exports.xxx = value
    })
    ③、引入使用模块
    define(function(require) {
    var m1 = require('./module1')
    var m4 = require('./module4')
    //执行...
    })


    html.png

    上图是html里面的使用方法,先引入sea.js,然后seajs.use一下main.js。


    mainjs.png
    main.js里面因为只是在使用,所以不需要加后面的exports和module,当然你开心也可以加上。
    里面的引入方式,还是一样的,就是require就可以了,很像commonjs。
    module1.png
    上面是module1,接下来以此就是四个module。
    module2.png module3.png

    上面是module3和2,都是一个没有依赖的。


    module4.png

    上面是module4,依赖了2和3。前面mainjs引入了module1和4,执行后发现异步调用的3被放在后面了,说明确实异步了,结果就是1243。


    7575.png
    上面是seajs的位置,不要忘记。
    对比CMD和AMD可以发现,AMD的依赖是前置的,在一个数组里头,直接就先加载了再执行后面的代码,而CMD的依赖是后置的,只有需要的时候,才会去执行模块的加载。

    四、ES6

    ES6需要安装一些加载插件:babel-cli,babel-preset-es2015和browserify,babel-cli主要是实现命令行,执行babel指令可以运行,后面那个babel-preset-es2015才是把ES6转成ES5的工具,babel不仅可以完成es6转es5,还能转其他的,转啥就下载啥,所以这里就需要下载这个babel-preset-es2015。
    1.npm install babel-cli browserify -g
    全局安装babel-cli这样我们在任何地方都可以执行babel命令了,browserify我们前面已经安装过了,现在也安装一下吧,反正也不吃亏。
    2.npm install babel-preset-es2015 --save-dev
    这个很明显是开发时候的依赖,转了到时候运行的时候就不需要再转了嘛。
    3.定义.babelrc
    不要忘记前面那个. (点),在根目录里面新建一个.babelrc,加了点的时候,webstorm自动把它识别为json文件了。babelrc也能在package.json里面配置
    {
    "name":'pname',
    "babel": {
    //config
    }
    }


    配置babelrc.png

    我们这里直接在根目录配置babelrc,rc代表的是run control运行控制。
    4.编写模块之间的依赖
    5.编译
    因为前面写的js文件,首先浏览器根本就不认识ES6的语法,因此需要babel来转成es5,另外,需要把它弄到浏览器环境中能执行,所以必须browserify
    5.1、babel js/src -d js/lib
    -d就是目标是js/lib文件夹
    -d前面就是需要编译的整个文件夹路径,里头都需要编译


    babel命令.png

    5.2 browserify js/lib/main.js -o js/dist/bundle.js
    这个就是把他弄到服务器端跑的工具
    上面两两步编译之后,浏览器就能够识别并运行了。


    成功1.png 成功2.png

    6.默认暴露的写法(补充)

    默认暴露的module3.png
    成功3.png

    1.值得注意的一点:package.json中name的值,不要取跟github上常用包一样的名字,否则会死活无法下载下来。
    2.安装babel必须安装babel-cli,cli就是command line interface也就是命令行接口,比如node里面的npm为啥可以执行,是因为里面就有cli,存了各种命令,但是babel自身没有,所以需要手动下载。
    3.npm install jquery@1指定下载jquery1里面的最新版本,默认包就是import $ from 'jquery'不需要加路径名,而且也是默认暴露的

    相关文章

      网友评论

        本文标题:前端模块化的四种规范

        本文链接:https://www.haomeiwen.com/subject/abnpxktx.html