前端自动化 模块化开发

前端自动化 模块化开发

# Grunt

为何Grunt

####在前端开发的过程当中,咱们常常会作一些跟功能、代码无关的重复的事情,好比复制、粘贴、压缩等等,咱们须要有一个前端自动化的工具。

什么是Grunt

###免费的小秘书 Grunt官网

怎么用Grunt

  • 前提:node npm
  • 安装grunt命令行工具 npm install -g grunt-cli
  • 在工做目录安装grunt npm install grunt --save-dev
  • 编辑Gruntfile.js文件
  • 在命令行执行grunt命令

关于Gruntfile.js的内容

格式以下,三步上篮:javascript

module.exports=function(grunt){//包裹函数,全部代码都在这里
    grunt.initConfig({});//1配置任务内容
    grunt.loadNpmTasks();//2加载插件
    grunt.registerTask();//3注册任务
}

initconfig——配置
能够有多个插件名,每一个的插件名-加载插件名-注册任务中执行的插件名字要一致。
每一个插件名能够有多个任务描述,默认所有执行,也能够指定执行某些任务。css

grunt.initConfig({
    插件名1: {
        任务描述1: {
            //描述xxx
        },
        任务描述2: {
            //描述xxx2
        }
    },
    插件名2: {
        任务描述3: {
            //描述xxx3
        }
    }
});
好比:
uglify: {
    main: {
        //描述
        src:    '1.js',//源文件
        dest:   '1.min.js'//目标文件
    }
}

loadNpmTasks——引入插件html

grunt.loadNpmTasks('grunt-contrib-uglify');
关于grunt的插件。。。

registerTask——注册任务前端

grunt.registerTask('default', ['uglify']);

关于执行grunt命令

执行的是registerTask注册的任务java

Tips:

  • 插件基本都能自动建立文件夹
  • 重复执行grunt的话,已经存在的文件会被覆盖,不报错,不在后面添加。
  • 通配符 *号 代指全部
  • 通配符 **号 代指全部,包括没有
  • cwd 描述想要做为当前文件夹的文件夹路径
  • expand,分开成一个个的文件,uglify能够压缩文件到一个文件,cssmin不能够
  • ext参数,设置后缀名
  • grunt中的模板 <%= grunt.template.today("yyyy-mm-dd HH-MM-ss") %>, 也能够放一个常量json进来能够在模板中使用,避免重复写,也便于更改
    结合<%= %>使用模板
  • grunt输出 grunt > log.txt
  • concat 链接起来,不压缩,生成的是一个文件【注意: 顺序未知】
  • grunt.file上面有基于nodeJs的fs包装好的操做文件的方法,好比:grunt.file.readJSON()一般用来读取json文件,直接转化为可用的json
  • copy 带文件夹层级复制,复制多个文件时,要有expand,不然会报错
  • watch —— 监测,(自动化)

AMD和CMD

WHY——模块化编程 vs 原始代码

转自阮一峰的博客:最先的时候,全部Javascript代码都写在一个文件里面,只要加载这一个文件就够了。后来,代码愈来愈多,一个文件不够了,必须分红多个文件,依次加载。下面的网页代码,相信不少人都见过。node

<script src="1.js"></script>
<script src="2.js"></script>
<script src="3.js"></script>
<script src="4.js"></script>
<script src="5.js"></script>
<script src="6.js"></script>

这段代码依次加载多个js文件。随着代码愈来愈多,当依赖关系很复杂的时候,代码的编写和维护都会变得困难。就算是代码做者本人,在后期维护起来也会愈来愈吃力,更不敢想多人合做了。jquery

在前端开发过程当中,常常会出现一个单文件几千行甚至近万行的状况。这种大文件,对协做开发、后续维护、性能调优等都不利。模块化开发初衷是帮助前端开发工程师将大文件拆分红小文件,能保持小颗粒度的模块化开发,同时不须要过多考虑依赖关系,让依赖管理轻松自如,将更多精力聚焦在代码自己的逻辑上。git

HOW——AMD和CMD之争

先分开介绍,再对比
CMD seaJs 玉伯
玉伯(王保平),淘宝前端类库 KISSY、前端模块化开发框架SeaJS、前端基础类库Arale的创始人。
玉伯github


CMD规范的定义

  • 懒加载——Execution must be lazy.
  • 一个模块就是一个文件,代码的书写格式以下:define(factory);
  • define 是一个全局函数,用来定义模块。
  • define 接受 factory 参数,factory 能够是一个函数,也能够是一个对象或字符串。npm

    • factory 为对象、字符串时,表示模块的接口就是该对象、字符串
    • factory 为函数时,表示是模块的构造方法。执行该构造方法,能够获得模块向外提供的接口。factory 方法在执行时,默认会传入三个参数:require、exports 和 module:

      define(function(require, exports, module) {//参数的顺序必须是这样的
        // 模块代码
        //require是获取其余模块的函数
        //exports用来输出当前模块
        //module用来输出当前模块
        //exports 仅仅是 module.exports 的一个引用。在 factory 内部给 exports 从新赋值时,并不会改变 module.exports 的值。所以给 exports 赋值是无效的,不能用来更改模块接口。
      });
  • 常用的 API 只有 define, require, exports, module.exports而已,简单明了

seaJs的用法

最简单的seaJs案例

//主html
<!doctype html>
<html>
    <head>
        <script src="../sea-modules/seajs/seajs/2.2.0/sea.js"></script>
        <script>
            seajs.use("main");//main是main.js,是用define定义的模块
        </script>
    </head>
    <body>
    页面内容
    </body>
</html>
//main.js
define(function(require) {
    alert(1);
});
  • 主文件配置参数 seajs.config(); 官方介绍
    seajs.config({//paths 配置能够结合 alias 配置一块儿使用,让模块引用很是方便。 // 设置路径,方便跨目录调用 paths: { 'arale': 'https://a.alipayobjects.com/arale', 'jquery': 'https://a.alipayobjects.com/jquery' }, // 设置别名,方便调用 alias: { 'class': 'arale/class/1.0.0/class', 'jquery': 'jquery/jquery/1.10.1/jquery' } });
  • 主文件使用模块:seajs.use();——头(or衣领)API介绍
    // 加载一个模块 seajs.use('./a'); // 加载一个模块,在加载完成时,执行回调 seajs.use('./a', function(a) { a.doSomething(); }); // 加载多个模块,在加载完成时,执行回调 seajs.use(['./a', './b'], function(a, b) { a.doSomething(); b.doSomething(); });
  • 如何定义模块
    用define来定义模块。Sea.js 推崇一个模块一个文件,遵循统一的写法:
    define(function(require, exports, module) { // 模块代码 // exports 被require的对象上的属性或方法 // 对外提供 foo 属性 // 在外部使用:require(xx).foo exports.foo = 'bar'; // 对外提供 doSomething 方法 // 在外部使用:require(xx).dosomething exports.doSomething = function() {}; //********************// // module.exports 就是被require的对象 module.exports = { name: 'a', doSomething: function() {}; }; });
  • 如何引用模块
    require 用来获取指定模块的接口。
    define(function(require, exports, module) { // 获取模块 a 的接口 var a = require('./a'); // 调用模块 a 的方法 a.doSomething(); });
  • 总结:用define来定义模块,一个模块就是一个文件,在模块里用require来引用其余模块,在主html文件里引入seajs后用seajs.use()来开启js文件。

AMD requireJs

AMD规范的定义

  • 全称 Asynchronous Module Definition——异步模块定义规范。
  • 模块和模块的依赖能够被异步加载。
  • 模块的依赖被异步加载完成之后,工厂函数才会执行。
  • define 是一个全局函数,用来定义模块。
  • define 能够接受多种格式的参数,不过一般能够是:

    • define(依赖的数组,工厂函数);
    • define(工厂函数);
    • define(一个对象);
  • 一个模块就是一个文件

requireJs的用法

最简单的requireJs案例

//主html
<!doctype html>
<html>
    <head>
        <script src="js/require.js"></script>
        <script>
            require(['jquery'], function($){
                alert('jquery loaded');
            });
        </script>
    </head>
    <body>
    页面内容
    </body>
</html>

or:

//主html
<!doctype html>
<html>
    <head>
        <script src="js/require.js" data-main="js/main.js"></script>
    </head>
    <body>
    // 这样写,会异步加载data-main指定的js文件,并把data-main所在的路径做为config配置的baseUrl。若是不想异步,就像上面同样写。
    页面内容
    </body>
</html>
//main.js
require(['jquery'], function($){//会在jquery模块执行完成后,把jquery的输出作为参数传入后面的工厂函数,并执行工厂函数
    alert('jquery loaded');
});
  • 配置: 可使用require.config来设置依赖的模块的名称和对应的路径,也能够在引入require.js以前定义一个名字为require的json。两种方式均可以进行配置。; requireJs配置官方介绍
    <script src="scripts/require.js"></script> <script> require.config({ baseUrl: "/another/path", paths: { "some": "some/v1.0" } }); require( ["some/module", "my/module"], function(someModule, myModule) { //..... } ); </script> 或者是: <script> var require = { baseUrl: "/another/path", paths: { "some": "some/v1.0" } }; </script> <script src="scripts/require.js"></script>
  • 主文件如何使用模块:从上面已经能够看到,不一样于seaJs的使用seajs.use()函数,requireJs使用require()函数来开始执行。
  • 如何定义模块
    用define来定义模块:常见的3种状况

    • define(依赖的数组,工厂函数);

      define(['aModule','bModule'],function(a,b) {
        // 模块代码
        // 这个定义的模块在被调用时,aModule和bModule模块加载完成以后,才会以他们的返回值做为参数执行工厂函数
      });
    • define(工厂函数); 语法糖

      define(function(require, exports, module) {
        // 模块代码
        // 这种方式实际上是requireJs的语法糖,能够在函数里面用变量接受require过来的模块(就像seaJs作的那样),并不真的是同步require那个代码,而是用的Function.prototype.toString()转换成数组里面的格式(怎么转换的我们无论)后异步下载后执行回调。
      });
    • define(一个对象);

      define({
          color: "black",
          size: "12"
      });
  • 如何引用模块
    用require来获取指定模块的接口(常见有2种):

    • require(依赖的数组,工厂函数);

      require(['aModule','bModule'],function(a,b) {
        // 模块代码
        // aModule和bModule模块加载完成以后,才会以他们的返回值做为参数执行工厂函数
      });
      • require(依赖的数组);
      //只是用来作一个头,异步引入js后本身不用再作其余事情
      require(['aModule','bModule']) ;
  • 总结:
    用define来定义模块,一个模块就是一个文件。
    define新模块时用数组提早声明依赖的模块。
    在主html文件里引入requirejs后用require()来开启js文件。

RequireJS 与 SeaJs 的异同

共同点:

  • 都是模块加载器,倡导模块化开发理念
  • 核心价值是让 JavaScript 的模块化开发变得简单天然

不一样点:

  • RequireJS是异步加载模块,SeaJs是同步加载模块
  • RequireJS是提早声明并加载依赖,SeaJs是按需加载依赖模块

咱们目前使用的是 RequireJS。

相关文章
相关标签/搜索