Grunt 实例之 构建 seajs 项目

Seajs 是时下比较热的一款模块加载框架,除了能实现代码模块按需自动加载、增加代码的可复用性之外,还能够培养我们的模块化低耦合开发思维。爱折(zhuang)腾(bi)的人值得一试。

摆脱 seajs 提供的 spm 构建工具 而改用 Grunt 去构建,这个过程是曲折的,艰辛的,没点折腾的耐心估计不成,在这里要感谢优秀的导师 海龙,被我抓住讲了 1个小时,分享了他在折腾时遇到的问题,让我走少了很多弯路(海龙哥自己摸这个 Grunt 配 Seajs,摸了 1个星期,我听完后折腾一天就搞明白了,在站巨人的肩膀 果然就是不一样)。

如果已经对 Seajs 十分理解的童鞋 可以直接 滚到最后看第二部分内容,而对 Seajs 一知半懂的 最好继续慢慢往下看,基础没打好,爬得再快一样会掉下来,还不懂自己错在哪。

What is Seajs

看了不少站点使用seajs,但仅仅仅限于异步加载js(没错,就仅仅是异步加载一个 js文件,里面还是完完全全是普通的js代码),而非 Seajs 所推崇的 匿名模块代码,这样也叫熟练使用 Seajs (择选自不少应聘者简历上的技能说明) 也是醉了。

回顾下我爱抚 Seajs 的经过,在这里,让我来说说 我所理解的 Seajs。

这里是 Seajs 的站点 http://seajs.org/

在粗略看过下大致的使用方法之后,我就随手搞了个demo试试。

demo 目录结构如下:

demo_00
|
+ css
| + hellosea.css
|
+ js
| + lib
| | + jquery-1.11.0.min.js
| | + sea.js
| |
| + hellosea
|   + page.js
|   + util.js
|
+ html
  + hellosea.html

html部分:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Grunt seajs demo</title>
<link rel="stylesheet" href="../css/hellosea.css">
</head>
<body>
<div id="box" class="box"></div>
</body>
<script src="http://www.jackness.org/wp-content/themes/JStyle/images/default/blank.png" _src="../js/lib/sea.js"></script>
<script>
// seajs 的简单配置
seajs.config({
  base: "../js/lib/",
  alias: {
    "jquery": "jquery-1.11.0.min.js"
  }
});

seajs.use("../js/hellosea/page.js");

</script>
</html>

page.js 部分

define(function(require, exports, module) {

  var util = require('./util'),
    $ = require('jquery');
  setInterval(function() {
    $('#box').css('background-color',util.randomColor());
  }, 1500);

});

demo地址: http://www.jackness.org/lab/2015/seajs/demo_00/html/hellosea.html

打开 demo,很好果然 万事起头难,报错了

grunt_seajs_img01

调试了一下,原来是 这句问题

$ = require('jquery');

require 返回 null,恩,赶紧去看看官网怎么说。 看来是因为 Seajs 本身的约定: ID 和路径匹配原则

ID 和路径匹配原则

所谓 ID 和路径匹配原则 是指,使用 seajs.use 或 require 进行引用的文件,如果是具名模块(即定义了 ID 的模块),会把 ID 和 seajs.use 的路径名进行匹配,如果一致,则正确执行模块返回结果。反之,则返回 null。

举个例子来消化下,就拿 require(‘jquery’) 做例子吧

要让 require(‘jquery’) 正确返回 有 2种形式:

1 种是 通过 在 jquery里面定义匿名模块,即

define(function(require,exports,module){
  //.. do something
  module.exports = jQuery;
}

另一种就是在js文件里面定义具名模块。在例子里面,我们在页面上是这样定义的:

<!-- html code  -->
<script>
// seajs 的简单配置
seajs.config({
  base: "../js/lib/",
  alias: {
    "jquery": "jquery-1.11.0.min.js"
  }
});

</script>

根据 路径即 id原则,我们需要在 jquery 文件里面这样定义:

define('jquery-1.11.0.min', [], function(require,exports,module){
  return $;
});

然后我们看看例子里的 jquery 是怎么写的, 在底部找到相关代码

"function"==typeof define&&define("jquery/jquery/1.10.1/jquery",[],function(){return x}))

这里定义了 jquery文件的 id 为 “jquery/jquery/1.10.1/jquery”, 但是我们页面请求的 id 为 “jquery-1.11.0.min”, id 对不上,所以模块匹配不到,返回 null。

基于路径即id原则,有 2种修改方式:

  • 1. 修改 jquery 源码,把 define(“jquery/jquery/1.10.1/jquery”,[],function(){return x})) 改为 define(“jquery-1.11.0.min”,[],function(){return x}))
  • 2. 调整 jquery 目录路径,使 jquery/jquery/1.10.1/jquery 具名模块生效

我选择 第二种方式来修复,调整 jqeruy目录结构, 顺便 把 seajs 也跟着改

调整后的目录结构为

demo_00
|
+ css
| + hellosea.css
|
+ js
| + lib
| | + jquery
| | | + jquery
| | |   + 1.10.1
| | |     + jquery.js
| | |     
| | + sea
| |   + sea
| |     + 2.2.0
| |       + sea.js
| |       
| + hellosea
|   + page.js
|   + util.js
|   
+ html
  + hellosea.html

demo地址: http://www.jackness.org/lab/2015/seajs/demo_01/html/hellosea.html

至于为什么要使用 jquery/jquery/1.10.1/jquery.js 这种结构,多了 1层的 jquery,而不直接使用 jquery/1.10.1/jquery.js,其实是因为考虑到扩展。拿jquery来举例,如果有个 基于jquery的日历控件 calendar.js 根据 推荐的结构 就可以这样放置:

js
+ lib
| + jquery
| | + jquery
| | | + 1.10.1
| | |   + jquery.js
| | |   
| | + calendar   
| |   + 1.0.0
| |     + calendar.js   
| + ...
| 
+ ...

这样一看就知道 日历控件是基于 jquery 开发出来的了。

回到我们的例子上, 我们看到函数能成功运行固然开心,但是一打开 页面请求信息栏一看,简直吓尿了,所有的js 都进行了请求。为了模块化,代价是请求数的暴增,这样seajs的价值何在,还能好好玩耍吗,还不如不用?

grunt_seajs_img02

恩,我们 继续看看 官网,在一篇 为什么要有约定和构建工具 文章 里 找到了答案。

不想请求那么多个文件, 答案就是把文件进行合并。 那么 问题来了。

如何将模块合并在 1个 js 里面

继续拿 上面的 demo 来做例子,jquery 属于 js库,而seajs属于页面加载的必备文件,当然就不必合并了,那么剩下的我们就有必要进行合并了,即 page.js、util.js

调整下目录结构,我们在 js/hellosea/ 下面 创建一个文件夹 【dist】 是用来放合并之后的文件,即产出目录;创建一个文件夹 【src】 用来放置我们的开发源文件:

js
+ lib
| + jquery
| | + jquery
| |   + 1.10.1
| |     + jquery.js
| |
| + sea
|   + sea
|     + 2.2.0
|       + sea.js
| 
+ hellosea
  + dist
  | + page.min.js
  |
  + src
    + page.js
    + util.js

我们首先将 html 上面的 seajs.use 所用的文件 指向 产出目录,即:

// seajs 的简单配置
seajs.config({
  base: "../js/lib/",
  alias: {
    "jquery": "jquery/jquery/1.10.1/jquery.js"
  }
});

seajs.use("../js/hellosea/dist/page.min.js");

我们再看看 page.js、util.js 这2个文件

page.js

define(function(require, exports, module) {

  var util = require('./util'),
    $ = require('jquery');
  setInterval(function() {
    $('#box').css('background-color',util.randomColor());
  }, 1500);

});

util.js

define(function(require,exports,module){
  var util = {};
  var colorRange = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'];
  util.randomColor = function(){
    return '#' +
      colorRange[Math.floor(Math.random() * 16)] +
      colorRange[Math.floor(Math.random() * 16)] +
      colorRange[Math.floor(Math.random() * 16)] +
      colorRange[Math.floor(Math.random() * 16)] +
      colorRange[Math.floor(Math.random() * 16)] +
      colorRange[Math.floor(Math.random() * 16)];
  };
  module.exports = util;
});

这两个文件里面都是通过匿名函数的方式创建的,根据文章的意思,我们如果想将他们合并在一个文件里面,就要在合并文件里面将这 2个 文件中的匿名函数 变为 具名函数, 并且遵守路径即id原则

我们把 hellosea/js/src/page.js 中的代码修改为具名函数:

define('../js/hellosea/src/page', ['./util', 'jquery'], function(require, exports, module) {

  var util = require('./util'),
    $ = require('jquery');
  setInterval(function() {
    $('#box').css('background-color',util.randomColor());
  }, 1500);

});

第二个参数是 我们把函数中有依赖其他文件的 文件 id(路径)抽出来放到这里面。Seajs 这样设定的原因是:这样 Sea.js 就不需要通过 factory.toString() 和正则匹配的方式来获取依赖,直接从第二个参数中就可以拿到依赖数组

同理 我们把 hellosea/js/src/util.js 也修改为具名函数:

define('../js/hellosea/src/util', [], function(require, exports, module) {
  var util = {};
  var colorRange = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];

  util.randomColor = function() {
    return '#' +
      colorRange[Math.floor(Math.random() * 16)] +
      colorRange[Math.floor(Math.random() * 16)] +
      colorRange[Math.floor(Math.random() * 16)] +
      colorRange[Math.floor(Math.random() * 16)] +
      colorRange[Math.floor(Math.random() * 16)] +
      colorRange[Math.floor(Math.random() * 16)];
  };

  module.exports = util;
});

然后 我们把 hellosea/js/src/page.js 这入口文件里的代码拷贝到 hellosea/js/dist/page.min.js。 根据路径即 id原则,我们把 id 改一下:

define('../js/hellosea/dist/page.min', ['./util', 'jquery'], function(require, exports, module) {

  var util = require('./util'),
    $ = require('jquery');
  setInterval(function() {
    $('#box').css('background-color',util.randomColor());
  }, 1500);

});

然后 再把 hellosea/js/src/util.js 的代码考到 hellosea/js/dist/page.min.js 的下面。

运行一下代码,发现有个地方错了:

grunt_seajs_img03

原因是 找不到 ../js/hellosea/dist/util.js 这个文件。

在 ‘../js/hellosea/dist/page.min’ 模块里面 请求的 ‘./util’ 是不存在的, 因为根据文件自身路径 这请求最终是指向 ‘../js/hellosea/dist/util.js’, 而我们需要他指向的是 ‘../js/hellosea/src/util.js’, 也就是 下面 util 模块的 id。

所以我们要把路径调整到正确的位置:

define('../js/hellosea/dist/page.min', ['../src/util', 'jquery'], function(require, exports, module) {

  var util = require('../src/util'),
    $ = require('jquery');
  setInterval(function() {
    $('#box').css('background-color',util.randomColor());
  }, 1500);

});

这就是 seajs 的工作、运行原理了。了解清楚原理,我们就可以更好地理解构建工具的工作方式。接下来我们说说 seajs的 构建工具。

使用 Grunt 作为 seajs的 构建工具

如真像上面说的,我们的每次修改代码、编写代码、调试代码 都需要我们手工一个个文件地进行合并、调整、压缩,如此繁琐的操作估计各个程序大大就算耐性再高都会被玩坏,更别说效率了。所以,代我们完成这样些操作的 构建工具 应运而生。

seajs 官网 提供了 seajs特供的构建工具 spm

操作虽然简单,但是需要遵守的规则也更多了,其中包括 文件路径。

这文件路径 如果是在全新的一个项目里面搞还好,但是如果是针对旧项目的seajs改造,目录架构改动之大以至于估计没开始你就已经选择放弃了。

所以这里介绍的是更具自由的 Grunt 来作为 seajs的 构建工具

根据我上面说的 seajs 工作原理,我们其实想让构建工具完成的是以下的几个事情

  1. 将入口文件拷贝到 产出目录
  2. 创建一个临时目录
  3. 将需要合并的js文件转为具名函数,并保持独立地保存在这个临时目录
  4. 将临时目录下独立的具名函数文件 合并为 1个 js 文件
  5. 将这个合并的 js 文件 拷贝到 我们的输出目录
  6. 压缩 这个 合并后的 文件
  7. 将这个临时目录删除

seajs 提供以下 grunt 的插件来 构建 项目

  • grunt-cmd-transport(用于将匿名函数转为 具名函数)
  • grunt-cmd-concat(根据文件中的 id 自动 拷贝对应目录文件的内容到 同一文件下)

所以 我的 package.js 这样配置

{
  "name": "helloSeajs",
  "version": "1.0.0",
  "author": "jackness Lau",
  "devDependencies": {
    "grunt": "0.4.1",
    "grunt-cmd-transport": "0.1.1",
    "grunt-cmd-concat": "0.1.0",
    "grunt-contrib-uglify": "0.2.0",
    "grunt-contrib-clean": "0.4.0"
  }
}

下面说说作为核心的 grunt-cmd-transport、grunt-cmd-concat 这 2个插件的使用配置

grunt-cmd-transport 介绍

这插件 用于将文件中定义的匿名函数转为 具名函数。配置如下:

grunt.initConfig({
  transport: {
    hellosea: {
      options: {
        // 是否采用相对地址
        relative: true,
        // 生成具名函数的id的格式 默认值为 {{family}}/{{name}}/{{version}}/{{filename}}
        format: '../js/hellosea/{{filename}}' 
      },
      files: [{
        // 相对路径地址
        'cwd':'js/hellosea/',
        // 需要生成具名函数的文件集合
        'src':['dist/hellosea.js','src/util.js'],
        // 生成存放的文件目录。里面的目录结构与 src 里各个文件名带有的目录结构保持一致
        'dest':'.build'
      }]
    }
  },
});

grunt-cmd-concat 介绍

这插件 用于根据文件中的 id 自动 拷贝对应目录文件的内容到 同一文件下。配置如下:

grunt.initConfig({
  concat:{
    hellosea: {
      options: {
        // 相对路径地址
        relative: true
      },
      files: {
        // 合并后的文件地址
        'js/hellosea/dist/hellosea.js': ['.build/dist/hellosea.js']
      }
    }
  }
});

我们在上面demo 的基础上进行 构建工具改造

demo压缩包地址 http://www.jackness.org/lab/2015/seajs/demo_03.zip

解压压缩包之后 我们 先 npm install 一下

npm install

以下是 Gruntfile.js 内容:

module.exports = function(grunt) {
  grunt.initConfig({
    /**
     * step 1:
     * 将入口文件拷贝到 产出目录
     */
    copy: {
      hellosea:{
        files:{
          "js/hellosea/dist/hellosea.js":["js/hellosea/src/hellosea.js"]
        }
      }
    },
    /**
     * step 2:
     * 创建一个临时目录
     * 将需要合并的js文件转为具名函数,并保持独立地保存在这个临时目录
     */ 
    transport: {
      hellosea: {
        options: {
          // 是否采用相对地址
          relative: true,
          // 生成具名函数的id的格式 默认值为 {{family}}/{{name}}/{{version}}/{{filename}}
          format: '../js/hellosea/{{filename}}' 
        },
        files: [{
          // 相对路径地址
          'cwd':'js/hellosea/',
          // 需要生成具名函数的文件集合
          'src':['dist/hellosea.js','src/util.js'],
          // 生成存放的文件目录。里面的目录结构与 src 里各个文件名带有的目录结构保持一致
          'dest':'.build'
        }]
      }
    },
    /**
     * step 3:
     * 将临时目录下独立的具名函数文件 合并为 1个 js 文件
     * 将这个合并的 js 文件 拷贝到 我们的输出目录
     */
    concat: {
      hellosea: {
        options: {
          // 是否采用相对地址
          relative: true
        },
        files: {
          // 合并后的文件地址
          'js/hellosea/dist/hellosea.js': ['.build/dist/hellosea.js']
        }
      }
    },
    /**
     * step 4:
     * 压缩 这个 合并后的 文件
     */
    uglify: {
      hellosea: {
        files: {
          'js/hellosea/dist/hellosea.js': ['js/hellosea/dist/hellosea.js'] //对dist/application.js进行压缩,之后存入dist/application.js文件
        }
      }
    },
    /**
     * step 5:
     * 将这个临时目录删除
     */
    clean: {
      build: ['.build']
    }
  });
  grunt.loadNpmTasks('grunt-cmd-transport');
  grunt.loadNpmTasks('grunt-cmd-concat');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.registerTask('default', ['copy','transport', 'concat', 'uglify', 'clean']);
  grunt.registerTask('build', function(name,step){
    switch(step){
      case "1":
        grunt.task.run('copy:' + name);
        break;
      case "2":
        grunt.task.run('transport:' + name);
        break;
      case "3":
        grunt.task.run('concat:' + name);
        break;
      case "4":
        grunt.task.run('uglify:' + name);
        break;
      case "5":
        grunt.task.run('clean:' + name);
        break;
      default:
        grunt.task.run(['copy:' + name,  'transport:' + name, 'concat:' + name, 'uglify:' + name, 'clean'])
        break;
    }
  });
};

我们执行下任务 看看是否能执行成功

grunt

grunt_seajs_img04

出错, 提示在执行 transport 时报错, 找不到 js/hellosea/dist/util.js 文件。额 但是我们想要的 应该是 js/hellosea/src/util.js 才对, Why?

打开 js/hellosea/src/hellosea.js 文件

define(function(require, exports, module) {

  var util = require('./util'),
    $ = require('jquery');
  setInterval(function() {
    $('#box').css('background-color',util.randomColor());
  }, 1500);
});

恩, 问题应该出在这里了

var util = require('./util'),

想想我们定义构建工具做了什么:

  • 1. 复制 hellosea/src/hellosea.js 文件到 hellosea/dist/hellosea.js
  • 2. 将 hellosea/dist/hellosea.js 转为具名函数

所以这 hellosea/src/hellosea.js 同样用于 hellosea/dist/hellosea.js

所以 require(‘./util’) 变成了相对于 hellosea/dist/hellosea.js 这个文件目录来执行的了,当然找不到了。

因此,我们要对 js/hellosea/src/hellosea.js 这样修改:

js/hellosea/src/hellosea.js 文件

define(function(require, exports, module) {

  var util = require('../src/util'),
    $ = require('jquery');
  setInterval(function() {
    $('#box').css('background-color',util.randomColor());
  }, 1500);
});

修改后的 压缩包: http://www.jackness.org/lab/2015/seajs/demo_04.zip

再执行下 grunt, ok 顺利生成, 文件也顺利合并

http://www.jackness.org/lab/2015/seajs/demo_04/html/hellosea.html

grunt_seajs_img05

grunt_seajs_img06

好是好,但是,问题又来了,线上有问题的话 怎么调试

根据地址进行 发行版 与开发版 的切换

下面是 Seajs 的建议方案:

// seajs 的简单配置
seajs.config({
  base: "../js/lib/",
  alias: {
    "jquery": "jquery/jquery/1.10.1/jquery.js"
  }
});
if(location.href.indexOf("dev=1") != -1){
  seajs.use("../js/hellosea/src/hellosea");
} else {
  seajs.use("../js/hellosea/dist/hellosea");
}

在确定没问题的情况下,上线时候可以将开发版部分代码去掉

// seajs 的简单配置
seajs.config({
  base: "../js/lib/",
  alias: {
    "jquery": "jquery/jquery/1.10.1/jquery.js"
  }
});

seajs.use("../js/hellosea/dist/hellosea");

恩,好像已经讲完可以投入使用的感觉,我又有个问题了,如果我想将非本项目的一个 通用 js 也合并在一起呢,情况会不会一样?

对非本项目的 js 进行 seajs 构建

同样,在上面 demo的 基础上 增加一个 通用头部的调用。 目录结构如下

demo
+ css
|
+ html
|
+ js
  + lib
  | + jquery
  | | + jquery
  | |   + 1.10.1
  | |     + jquery.js
  | |
  | + sea
  |   + sea
  |     + 2.2.0
  |       + sea.js
  | 
  + hellosea
  | + dist
  | | + hellosea.js
  | |
  | + src
  |   + hellosea.js
  |   + util.js
  |  
  + common
    + head.js

hellosea.js 增加一个 头部js的引用:

define(function(require, exports, module) {

  require('../../common/head');
  var util = require('../src/util'),
    $ = require('jquery');
  setInterval(function() {
    $('#box').css('background-color',util.randomColor());
  }, 1500);

});

Gruntfile.js 代码中也增加对 ‘../../common/head’ 的处理:

module.exports = function(grunt) {
  grunt.initConfig({
    ...
    /**
     * step 2:
     * 创建一个临时目录
     * 将需要合并的js文件转为具名函数,并保持独立地保存在这个临时目录
     */ 
    transport: {
      hellosea: {
        options: {
          // 是否采用相对地址
          relative: true,
          // 生成具名函数的id的格式 默认值为 {{family}}/{{name}}/{{version}}/{{filename}}
          format: '../js/hellosea/{{filename}}' 
        },
        files: [{
          // 相对路径地址
          'cwd':'js/hellosea/',
          // 需要生成具名函数的文件集合
          'src':['dist/hellosea.js','src/util.js', '../../common/head.js'],
          // 生成存放的文件目录。里面的目录结构与 src 里各个文件名带有的目录结构保持一致
          'dest':'.build'
        }]
      }
    },
    ...
  });
  ...
};

demo 压缩包: http://www.jackness.org/lab/2015/seajs/demo_05.zip

执行 构建 顺利通过

grunt_seajs_img07

打开网页, 确定下有没合并成功, 艾玛 head.js 单独请求了,并没有合并到 /dist/hellosea.js 里面

http://www.jackness.org/lab/2015/seajs/demo_05/html/hellosea.html

grunt_seajs_img08

错在哪里呢? 好吧,我们将构建过程 分开一步步来执行,看看 哪里出错了

grunt_seajs_img09

跑到 步骤 3, 发现有异常了, hellosea/dist/hellosea.js 里面并没有 common/head.js 部分的代码

hellosea/dist/hellosea.js

define("../js/hellosea/dist/hellosea", [ "../../common/head", "jquery", "../src/util" ], function(require, exports, module) {
  require("../../common/head");
  var util = require("../src/util"), $ = require("jquery");
  setInterval(function() {
    $("#box").css("background-color", util.randomColor());
  }, 1500);
});
define("../js/hellosea/src/util", [], function(require, exports, module) {
  var util = {};
  var colorRange = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" ];
  util.randomColor = function() {
    return "#" + colorRange[Math.floor(Math.random() * 16)] + colorRange[Math.floor(Math.random() * 16)] + colorRange[Math.floor(Math.random() * 16)] + colorRange[Math.floor(Math.random() * 16)] + colorRange[Math.floor(Math.random() * 16)] + colorRange[Math.floor(Math.random() * 16)];
  };
  module.exports = util;
});

回到 步骤 2, 当将 ../js/hellosea/dist/hellosea 匿名函数转为 具名函数 并保存 到 .build/dist/hellosea.js 里面的时候,文件代码如下

define("../js/hellosea/dist/hellosea", [ "../../common/head", "jquery", "../src/util" ], function(require, exports, module) {
    require("../../common/head");
    var util = require("../src/util"), $ = require("jquery");
    setInterval(function() {
        $("#box").css("background-color", util.randomColor());
    }, 1500);
});

而步骤 3 是将 此 入口函数里的 引用 所有文件 合并到 一个文件里面,所以,问题就来了。

基于 “.build/dist/hellosea.js” 这个目录 “../../common/head” 这文件不存在, 所以就导致 执行步骤 3之后 head.js 没有合并到 入口函数里面。

这样,我们就出大招吧,将整个 js 目录搬到 .build 目录下!这样就能找到对应的文件了

因此,我在 构建过程中增加了 2个步骤:

module.exports = function(grunt) {
  grunt.initConfig({
    ...
    /**
     * step 2:
     * 创建 .build/js/common 临时目录
     * 将公用 common 目录下的 文件 转为 具名函数,并保存在 .build/js/common 目录下
     * 创建 .build/js/hellosea 临时目录 
     * 将需要合并的js文件转为具名函数,并保持独立地保存在 .build/js/hellosea 临时目录下
     */ 
    transport: {
      common:{
        options: {
          relative: true,
          format: '../js/common/{{filename}}' //生成的id的格式
        },
        files: [{
          'cwd':'js/common/',
          'src':['*.js'],
          'dest':'.build/js/common/'
        }]
      },
      hellosea: {
        options: {
          relative: true,
          format: '../js/hellosea/{{filename}}' //生成的id的格式
        },
        files: [{
          'cwd':'js/hellosea/',
          'src':['dist/hellosea.js', 'src/util.js', '../../common/head.js'],
          'dest':'.build/js/hellosea/'
        }]
      }
    },
    /**
     * step 3:
     * 将.build 目录下的具名函数 入口文件,根据id查找对应的文件,并且 合并为 1个 js 文件
     * 将这个合并的 js 文件 拷贝到 我们的输出目录
     */
    concat: {
      hellosea: {
        options: {
          // relative: true
        },
        files: {
          'js/hellosea/dist/hellosea.js': ['.build/js/hellosea/dist/hellosea.js']
        }
      }
    },
    ...
  });
  ...
};

demo 压缩包: http://www.jackness.org/lab/2015/seajs/demo_06.zip

执行下,打开网页。 ok head.js 归位了。

http://www.jackness.org/lab/2015/seajs/demo_06/html/hellosea.html

grunt_seajs_img10

转自:http://www.tuicool.com/articles/zaUfI3

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值