- 前提:node npm
- 安装grunt命令行工具 npm install -g grunt-cli
- 在工做目录安装grunt npm install grunt --save-dev
- 编辑Gruntfile.js文件
- 在命令行执行grunt命令
格式以下,三步上篮:
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');
registerTask——注册任务
前端
grunt.registerTask('default', ['uglify']);
执行的是registerTask注册的任务java
- 插件基本都能自动建立文件夹
- 重复执行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 —— 监测,(自动化)
转自阮一峰的博客:最先的时候,全部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
先分开介绍,再对比
CMD seaJs 玉伯
玉伯(王保平),淘宝前端类库 KISSY、前端模块化开发框架SeaJS、前端基础类库Arale的创始人。
github
- 懒加载——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案例
//主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
- 全称 Asynchronous Module Definition——异步模块定义规范。
- 模块和模块的依赖能够被异步加载。
- 模块的依赖被异步加载完成之后,工厂函数才会执行。
- define 是一个全局函数,用来定义模块。
define 能够接受多种格式的参数,不过一般能够是:
- define(依赖的数组,工厂函数);
- define(工厂函数);
- define(一个对象);
- 一个模块就是一个文件
最简单的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文件。
共同点:
- 都是模块加载器,倡导模块化开发理念
- 核心价值是让 JavaScript 的模块化开发变得简单天然
不一样点:
- RequireJS是异步加载模块,SeaJs是同步加载模块
- RequireJS是提早声明并加载依赖,SeaJs是按需加载依赖模块
咱们目前使用的是 RequireJS。