(四)seajs.config中vars、alias、paths和map的作用,以及util-path路径解析源码

来源:互联网 发布:.com.cn是什么域名 编辑:程序博客网 时间:2024/06/06 04:19

这篇文章主要是学习下seajs.config中vars、alias、paths、map这4个配置参数的作用和使用方式。这4个配置都会影响一个模块最终的url路径。

alias

seajs.config({    base: 'http://www.main.com/base/',    alias: {    'jquery': 'jquery/jquery/1.10.1/jquery',    'app/biz': 'http://path/to/app/biz.js',  }});
define(function(require, exports, module) {   var $ = require('jquery');   //=> 加载的是 http://www.main.com/base/jquery/jquery/1.10.1/jquery.js   var biz = require('app/biz');   //=> 加载的是 http://path/to/app/biz.js});
当模块标识很长,写起来不方便、容易出错的时候,可以使用alias来简化模块标识。在seajs.config中进行一次配置之后,所有js模块都可以用require("jquery")这种简单的方式来加载对应的模块了。使用alias,可以让文件的真实路径与模块调用标识分开,有利于统一维护。

paths

seajs.config({  base: 'http://www.main.com/base/',    // 别名配置  alias: {    'hostA-jquery': 'hostA/jquery/1.10.1/jquery.js',  },  paths: {    'hostA': 'https://www.shenzhen.com/sz''app': 'path/to/app'  }});
define(function(require, exports, module) {   var underscore = require('hostA/underscore');     //=> 加载的是 https://www.shenzhen.com/sz/underscore.js    var jquery = require('hostA-jquery'); //=> 加载的是 https://www.shenzhen.com/sz/jquery/1.10.1/jquery.js    var biz = require('APP/biz');     //=> 加载的是 http://www.main.com/base/path/to/app/biz.js});
当目录层次比较深,或者是跨目录调用模块的时候,可以用path简化模块标识的书写。paths 配置可以结合 alias 配置一起使用,让模块引用非常方便。

vars

seajs.config({  base: 'http://www.main.com/base/',    vars: {    'locale': 'zh-cn'  }});
define(function(require, exports, module) {  var lang = require('i18n/{locale}.js');     //=> 加载的是 http://www.main.com/base/i18n/zh-cn.js});
有些场景下,模块路径在运行时才能确定,这时可以使用 vars 变量来配置。vars配置的是模块标识中的变量值,在模块标识中用 {key} 来表示变量。

map

seajs.config({   base: 'http://www.main.com/base/',     'map': [    [ /(.*?)(\.js)$/i , '$1-debug.js']  ]});
define(function(require, exports, module) {  var a = require('cs/a');     //=> 加载的是 http://www.main.com/base/cs/a-debug.js});
map配置主要用来做调试用途,用来做路径转换、版本号、时间戳等管理。


seajs解析模块的url,就是根据模块标识(到底是相对标识、顶级标识还是普通标识),和上面这4个配置来确定的。相关源码在util-path.js中,下面附上util-path.js中最核心部分的源码,我加了很多注释,应该很容易看懂。如果有兴趣专研,可以用seajs.resolve()来尝试一下。

/** * util-path.js - The utilities for operating path such as id, uri */ // '/'字符是正则表达式常量的边界,所以需要用'\'进行转义var DIRNAME_RE = /[^?#]*\//;// 全局匹配"/./",字符slash和dot都是特殊字符var DOT_RE = /\/\.\//g;// DOUBLE_DOT_RE.test("//../") ==>false// DOUBLE_DOT_RE.test("/as/../") ==>truevar DOUBLE_DOT_RE = /\/[^/]+\/\.\.\//;// MULTI_SLASH_RE.test("c//") ==> true// MULTI_SLASH_RE.test("///") ==> false// MULTI_SLASH_RE.test("://") ==> false// MULTI_SLASH_RE.test("c://") ==> false// "http://asb///ss".match(MULTI_SLASH_RE)[0] ==> "b///"var MULTI_SLASH_RE = /([^:/])\/+\//g;// Extract the directory portion(一部分) of a path// dirname("a/b/c.js?t=123#xx/zz") ==> "a/b/"// ref: http://jsperf.com/regex-vs-split/2function dirname(path) {//如果path不匹配正则,此时方法会报异常//没有使用/g模式,只查找第一个匹配项,match()返回的是数组  return path.match(DIRNAME_RE)[0];}// Canonicalize(规范化) a path// realpath("http://test.com/a//./b/../c") ==> "http://test.com/a/c"function realpath(path) {  // /a/b/./c/./d ==> /a/b/c/d  path = path.replace(DOT_RE, "/");  /*    @author wh1100717    a//b/c ==> a/b/c    a///b/////c ==> a/b/c    DOUBLE_DOT_RE matches a/b/c//../d path correctly only if replace // with / first  */  path = path.replace(MULTI_SLASH_RE, "$1/");//$1代表第一个分组内容  // a/b/c/../../d  ==>  a/b/../d  ==>  a/d  // first replace "/c/../" ,then replace "/b/../" with "/"  while (path.match(DOUBLE_DOT_RE)) {    path = path.replace(DOUBLE_DOT_RE, "/");  }  return path;}// Normalize an id// normalize("path/to/a") ==> "path/to/a.js"// normalize("a/b/c/") ==> "a/b/c"// normalize("a/b/c/?d=1") ===> "a/b/c/?d=1"// NOTICE: substring is faster than negative slice and RegExp// 看懂这个方法后,理解[http://www.zhangxinxu.com/sp/seajs/docs/zh-cn/module-identifier.html#tips]太容易了吧function normalize(path) {  var last = path.length - 1;  var lastC = path.charCodeAt(last);  // If the uri ends with `#`, just return it without '#'  if (lastC === 35 /* "#" */) {    return path.substring(0, last);  }  return (path.substring(last - 2) === ".js" ||      path.indexOf("?") > 0 ||      lastC === 47 /* "/" */) ? path : path + ".js";}// 不能以"/"和":"开头, 结尾必须要是 "/"后面跟着任意字符(数量至少1个)// PATHS_RE.test("dd/")  ==> false// PATHS_RE.test("dd/ss") ==> true// PATHS_RE.test("d:d/ss")==> false// PATHS_RE.test("/aa/ss")==> falsevar PATHS_RE = /^([^/:]+)(\/.+)$/;// 匹配变量// VARS_RE.test("{}") ==>  false// VARS_RE.test("{{}") ===> false// VARS_RE.test("{as}") ===> truevar VARS_RE = /{([^{]+)}/g;// 解析seajs.config({})中的alias配置function parseAlias(id) {  var alias = data.alias;  return alias && isString(alias[id]) ? alias[id] : id;}function parsePaths(id) {  var paths = data.paths;  var m;  // 当id匹配PATHS_RE的时候,m[1]代表第一个分组的内容,m[2]代表第二个分组的内容  // m[0]代表的是匹配的内容(不含分组信息,对我这里来说没有啥用)  if (paths && (m = id.match(PATHS_RE)) && isString(paths[m[1]])) {    id = paths[m[1]] + m[2];  }  return id;}function parseVars(id) {  var vars = data.vars;  if (vars && id.indexOf("{") > -1) {    id = id.replace(VARS_RE, function(m, key) { // m like {name}, key like name      return isString(vars[key]) ? vars[key] : m;    });  }  return id;}// 解析config.map支持正则表达式和函数// map最佳实践:用来做版本号和时间戳管理的/*seajs.config({  map: [    ['.js', '-debug.js']  ]});*//*seajs.config({  'map': [    [ /^(.*\.(?:css|js))(.*)$/i, '$1?20110801']  ]});*/function parseMap(uri) {  var map = data.map;  var ret = uri;  if (map) {    for (var i = 0, len = map.length; i < len; i++) {      var rule = map[i]      ret = isFunction(rule) ?          (rule(uri) || uri) :          uri.replace(rule[0], rule[1]);      // Only apply the first matched rule      if (ret !== uri) break;    }  }  return ret;}// 包含":/" 或者以"//{char}"开头({char}代表任意一个字符)// ABSOLUTE_RE.test("/a") ==>  falsevar ABSOLUTE_RE = /^\/\/.|:\//;// ROOT_DIR_RE.test("///")  ==> true// ROOT_DIR_RE.test("sd//dd") ==>false// ROOT_DIR_RE.test("sd//dd/") ==>true// ROOT_DIR_RE.test("http://127.0.0.1:8080/s/") ==> true// ROOT_DIR_RE.test("http://127.0.0.1:8080/s") ==> truevar ROOT_DIR_RE = /^.*?\/\/.*?\//;function addBase(id, refUri) {  var ret;  var first = id.charCodeAt(0);  // Absolute  if (ABSOLUTE_RE.test(id)) {    ret = id;  }  // Relative  else if (first === 46 /* "." */) {    ret = (refUri ? dirname(refUri) : data.cwd) + id;  }  // Root  else if (first === 47 /* "/" */) {    var m = data.cwd.match(ROOT_DIR_RE);    ret = m ? m[0] + id.substring(1) : id;  }  // Top-level  else {    ret = data.base + id;  }  // Add default protocol when uri begins with "//"  if (ret.indexOf("//") === 0) {    ret = location.protocol + ret;  }  return realpath(ret);}function id2Uri(id, refUri) {  if (!id) return "";  id = parseAlias(id);  id = parsePaths(id);  id = parseAlias(id);  id = parseVars(id);  id = parseAlias(id);  id = normalize(id);  id = parseAlias(id);  var uri = addBase(id, refUri);  uri = parseAlias(uri);  uri = parseMap(uri);  return uri;}// For Developersseajs.resolve = id2Uri;


可以看到id2Uri这个方法在不停的处理alias、paths、vars、map,有兴趣的可以去专研。util-path.js核心就是一堆正则表达式,上面已经加了很多注释。


1 0
原创粉丝点击