模块标识 #258

Closed
lifesinger opened this Issue Jul 6, 2012 · 12 comments

Projects

None yet

10 participants

@lifesinger
Member

模块标识

模块标识是一个字符串,用来标识模块。在 requirerequire.async 等加载函数中,第一个参数都是模块标识。

Sea.js 中的模块标识是 CommonJS 模块标识 的超集:

  1. 一个模块标识由斜线(/)分隔的多项组成。
  2. 每一项必须是小驼峰字符串、 ...
  3. 模块标识可以不包含文件后缀名,比如 .js
  4. 模块标识可以是 相对顶级 标识。如果第一项是 ...,则该模块标识是相对标识。
  5. 顶级标识根据模块系统的基础路径来解析。
  6. 相对标识相对 require 所在模块的路径来解析。

注意,符合上述规范的标识肯定是 Sea.js 的模块标识,但 Sea.js 能识别的模块标识不需要完全符合以上规范。 比如,除了大小写字母组成的小驼峰字符串,Sea.js 的模块标识字符串还可以包含下划线(_)和连字符(-), 甚至可以是 http://https://file:/// 等协议开头的绝对路径。

相对标识

相对标识以 . 开头,只出现在模块环境中(definefactory 方法里面)。相对标识永远相对当前模块的 URI 来解析:

// 在 http://example.com/js/a.js 的 factory 中:
require.resolve('./b');
  // => http://example.com/js/b.js

// 在 http://example.com/js/a.js 的 factory 中:
require.resolve('../c');
  // => http://example.com/c.js

顶级标识

顶级标识不以点(.)或斜线(/)开始, 会相对模块系统的基础路径(即 Sea.js 的 base 路径)来解析:

// 假设 base 路径是:http://example.com/assets/

// 在模块代码里:
require.resolve('gallery/jquery/1.9.1/jquery');
  // => http://example.com/assets/gallery/jquery/1.9.1/jquery.js

模块系统的基础路径即 base 的默认值,与 sea.js 的访问路径相关:

如果 sea.js 的访问路径是:
  http://example.com/assets/sea.js

则 base 路径为:
  http://example.com/assets/

sea.js 的访问路径中含有版本号时,base 不会包含 seajs/x.y.z 字串。 当 sea.js 有多个版本时,这样会很方便。

如果 sea.js 的路径是:
  http://example.com/assets/seajs/1.0.0/sea.js

则 base 路径是:
  http://example.com/assets/

当然,也可以手工配置 base 路径:

seajs.config({
  base: 'http://code.jquery.com/'
});

// 在模块代码里:
require.resolve('jquery');
  // => http://code.jquery.com/jquery.js

普通路径

除了相对和顶级标识之外的标识都是普通路径。普通路径的解析规则,和 HTML 代码中的 <script src="..."></script> 一样,会相对当前页面解析。

// 假设当前页面是 http://example.com/path/to/page/index.html

// 绝对路径是普通路径:
require.resolve('http://cdn.com/js/a');
  // => http://cdn.com/js/a.js

// 根路径是普通路径:
require.resolve('/js/b');
  // => http://example.com/js/b.js

// use 中的相对路径始终是普通路径:
seajs.use('./c');
  // => 加载的是 http://example.com/path/to/page/c.js

seajs.use('../d');
  // => 加载的是 http://example.com/path/to/d.js

提示

  1. 顶级标识始终相对 base 基础路径解析。
  2. 绝对路径和根路径始终相对当前页面解析。
  3. requirerequire.async 中的相对路径相对当前模块路径来解析。
  4. seajs.use 中的相对路径始终相对当前页面来解析。

文件后缀的自动添加规则

Sea.js 在解析模块标识时, 除非在路径中有问号(?)或最后一个字符是井号(#),否则都会自动添加 JS 扩展名(.js)。如果不想自动添加扩展名,可以在路径末尾加上井号(#)。

// ".js" 后缀可以省略:
require.resolve('http://example.com/js/a');
require.resolve('http://example.com/js/a.js');
  // => http://example.com/js/a.js

// ".css" 后缀不可省略:
require.resolve('http://example.com/css/a.css');
  // => http://example.com/css/a.css

// 当路径中有问号("?")时,不会自动添加后缀:
require.resolve('http://example.com/js/a.json?callback=define');
  // => http://example.com/js/a.json?callback=define

// 当路径以井号("#")结尾时,不会自动添加后缀,且在解析时,会自动去掉井号:
require.resolve('http://example.com/js/a.json#');
  // => http://example.com/js/a.json

设计原则

模块标识的规则就上面这些,设计的核心出发点是:

  1. 关注度分离。比如书写模块 a.js 时,如果需要引用 b.js,则只需要知道 b.js 相对 a.js 的相对路径即可,无需关注其他。
  2. 尽量与浏览器的解析规则一致。比如根路径(/xx/zz)、绝对路径、以及传给 use 方法的非顶级标识,都是相对所在页面的 URL 进行解析。

一旦理解了以上两点,一切都会很自然、很简单。不必刻意去记这些规则,多写写,自然就会。

@lifesinger
Member

有任何问题,欢迎留言交流。
注意:已解决的问题,会在整理后删除掉。

@lifesinger lifesinger closed this Jul 6, 2012
@peichao01

关于手动指定ID和依赖,或者后期自动化构建为transport结构,都需要更为清晰的了解ID的解析模式,这里的介绍还没有面面俱到。这篇文章算是一个补充吧:seajs中模块ID注意事项,模块定义、模块加载、模块依赖的ID路径解析规则

@lifesinger
Member

@peichao01 非常感谢补充,很详尽的说明。

@saraOrg
saraOrg commented May 21, 2014

nice!

@afc163 afc163 referenced this issue in spmjs/spm Jun 4, 2014
Closed

spm@1.x 旧版文档备份 #808

@ghost
ghost commented Oct 10, 2014

在“自动添加规则”这一部分,
require.resolve('http://example.com/css/a.css');
的结果不应该是:
http://example.com/css/a.css.js吗?

@bytesnail

路径解析中的paths参数

  1. paths在这里的仅仅能够识别顶级标示, 相对于base路径的普通路径均不能被正确识别, 也就是paths仅支持base路径下的路径扩展;
  2. 是否能够使paths支持相对于base路径的普通路径解析(或者仅支持相对标示), 这样可以支持base路径外的路径扩展, 有利于统一模板路径配置, 不必再设置独立的相对路径, 所有路径都可以根据base路径进行配置;
@afc163 afc163 referenced this issue Mar 3, 2015
Closed

新手请教 #1446

@Sessionking

seajs.use 中的相对路径始终相对当前页面来解析。 应该是相对于sea.js的地址吧,

@liujie1990

学习了,非常感谢

@Timi-code

在引入css文件的时候,貌似必须添加后缀的吧。在script里面引入css的时候就回找不到,在define里面引入css 的时候会自动添加上.js的后缀引入导致找不到。

@baiduoduo

同问,在“自动添加规则”这一部分,
require.resolve('http://example.com/css/a.css');
的结果不应该是:
http://example.com/css/a.css.js吗?

@sxmsxmsxm

感谢分享

@chinleo
chinleo commented Mar 17, 2017

总结下:
./开头:本级路径
../开头:上级
/开头:域名之后的根路径
名称开头:相对于base的路径

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment