require 书写约定 #259

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

Projects

None yet
@lifesinger
Member

require 书写约定

使用 Sea.js 书写模块代码时,需要遵循一些简单规则。

只是书写和调试时的规范!!!构建后的代码完全不需要遵循下面的约定!!!!!!

1. 正确拼写

模块 factory 构造方法的第一个参数 必须 命名为 require

// 错误!
define(function(req) {
  // ...
});

// 正确!
define(function(require) {
  // ...
});

2. 不要修改

不要重命名 require 函数,或在任何作用域中给 require 重新赋值。

// 错误 - 重命名 "require"!
var req = require, mod = req("./mod");

// 错误 - 重定义 "require"!
require = function() {};

// 错误 - 重定义 "require" 为函数参数!
function F(require) {}

// 错误 - 在内嵌作用域内重定义了 "require"!
function F() {
  var require = function() {};
}

3. 使用直接量

require 的参数值 必须 是字符串直接量。

// 错误!
require(myModule);

// 错误!
require("my-" + "module");

// 错误!
require("MY-MODULE".toLowerCase());

// 正确!
require("my-module");

在书写模块代码时,必须遵循这些规则。其实只要把 require 看做是语法关键字 就好啦。

关于动态依赖

有时会希望可以使用 require 来进行条件加载:

if (todayIsWeekend)
  require("play");
else
  require("work");

但请牢记,从静态分析的角度来看,这个模块同时依赖 play 和 work 两个模块,加载器会把这两个模块文件都下载下来。 这种情况下,推荐使用 require.async 来进行条件加载。

Why?

这些约定初看起来会有些小不爽,其实也的确可以通过每次都编译的方式来去掉这些限制。但编译的方式,会给开发调试带来麻烦,代码的实现复杂度也会增加。Sea.js 的核心设计原则是保持简单,遵循 New Jersey Approach

简单性:设计必须简单,这既是对实现的要求,也是对接口的要求。实现的简单要比接口的简单更加重要。简单是设计中需要第一重视的因素。

因为简单,所以可靠!

参考文档

@lifesinger
Member

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

@lifesinger lifesinger closed this Jul 6, 2012
@nnzbz
nnzbz commented Jul 3, 2013

很不理解,在框架中用到一个动态加载依赖的设计是很正常的,不会是不良设计的根源,不可能要求以后每添加一个模块就要在这里加个else,而其实只要简单传个变量过来就可以做到的,代码也是相当的优雅

@lifesinger
Member

@nnzbz 那只有等浏览器以后来支持了。

@nnzbz
nnzbz commented Jul 4, 2013

我水平面比较低,能讲解一下为什么只能是字符串直接量吗?我好学习一下

@afc163
Member
afc163 commented Jul 4, 2013

@nnzbz 看文中的参考文档。

@zzuhan
zzuhan commented Sep 4, 2013

@nnzbz 因为在要执行某个模块时,会预加载这个模块中的依赖,里面变量都未执行,所以。。。

@luhang02

为什么我写的require("$")返回结果是空的因为jquery.js没有exports,而arale的模块require同一个js是正常的

@sprying
sprying commented Feb 17, 2014

看了《程序员》上关于玉伯 的 模块化开发思想,当时也想到了将函数字符串化,再正则提取。Seajs正是如此,但有许多限制。

@emilley
emilley commented Apr 14, 2014

为什么require来进行条件加载,两个文件就都加载进来了?而require.async只加载进来需要的文件?

@afc163
Member
afc163 commented Apr 14, 2014

@emilley 这篇文档不就是解释你的问题的?

@zlstone
zlstone commented Apr 18, 2014

e42b29288c800c5ce42071c28f717de4
fa26926299b75ee5e34517867d59bbe6

@lifesinger 模块构造函数的第一个参数必须用require么?我在2个项目里使用seajs,2.1.0版本,我发现前一个版本将第一个参数写成任何样子都可以,但是第二个项目却不行,第一个参数必须要require才能识别,2.2.1和2.1.0都做了测试,能帮忙解决一下这个疑惑么?

@afc163
Member
afc163 commented Apr 18, 2014

你看下并理解楼上这篇文档就行了。

包括 #426

@zlstone
zlstone commented Apr 18, 2014

@afc163 我看过文档了,我看第一个约定就是工厂第一个参数必须为require,我这边不用require也可以应该是什么原因导致的呢?cmd压缩也说要保留require关键字,但是grunt打包没有保留require也一切正常。

@zlstone
zlstone commented Apr 18, 2014

@afc163 还是没找到答案,提点一两下被

@afc163
Member
afc163 commented Apr 18, 2014

压缩操作。经过上面的提取操作后,构建工具就可以调用任何 JS 压缩工具来进行压缩了,require 参数也可以被压缩成任意字符。


由于各种原因,暂时无法使用 Sea.js 配套的构建工具来压缩时 ... 压缩时,不要压缩 require 参数 ... 或者自己写工具来保证 id 和 dependencies 的预先提取。

@zlstone
zlstone commented Apr 18, 2014

@afc163 这个我知道,问题是你看我的截图,我没提取id和依赖,没有压缩,依然可以直接使用第一个参数,这是为什么....但是在另一个项目,确实修改require无法正确加载,提取id和依赖后解析正常,我想知道截图这种情况是怎么导致的

@afc163
Member
afc163 commented Apr 18, 2014

把 require 改为 e 后,如果也没有提前提取依赖数组的话,seajs 无法提前获取本模块的依赖,就不会去载入 jQuery 和 underscore,这样你的逻辑很可能就跑不通了。

但是如果你在别的代码里恰好提前定义了 jQuery 和 underscore 的话。那么这个改了名的 require 作为一个正常的函数,依然可以去拿到已定义的 jQuery 和 underscore,这个功能是没有变化的。

改名后,缺少的只是提前读取依赖的特性。

当然,上面的恰好是一个不推荐的应用场景,也不符合模块化的定义,建议安装 seajs 推荐的方式来进行书写和打包。

@zlstone
zlstone commented Apr 18, 2014

@afc163 截图这个模块就是整个项目的入口,之前没有定义过jquery之类的东西.....我log打印出来第一个参数,不管是不是require结果都一样,应该不提前获取模块依赖,也可以请求加载吧,问题是现在的项目,修改require就解析错误,exec解析失败,why,好奇怪.....

@afc163
Member
afc163 commented Apr 18, 2014

不提前获取模块依赖,就不会请求加载。

之前要是没定义过 jQuery 之类的,那么第一个 require (e) 的地方肯定就报错了。

空说无凭,上线上能访问的静态 demo 吧。

@army8735
Member

好大一堆426啊

@zlstone
zlstone commented Apr 21, 2014

@afc163 截图的问题又没办法复现了...奇怪的问题,可能是当时个人代码问题,感谢回复!之后如果再碰到,我会及时留存demo。

@rebornvip

如何在infor.js中调用到 moduleMain.js 中的APP+"/social/js/a"
index.html
seajs.use(["../Public/Static/social/js/moduleMain"])

moduleMain.js
define(APP+"/social/js/smallModule",["./a"], function (require, exports, module) {})

define(APP+"/social/js/a",[], function (require, exports, module) {
module.exports={
a:"String"
}
})

infor.js
define([], function (require, exports, module) {})

@saraOrg
saraOrg commented May 21, 2014

我看官网的hello,world中都不规范,例如:
image
都不符合模块 factory 构造方法的第一个参数 必须 命名为 require 。

@popomore
Member

这是构建后的,非书写规范

@saraOrg
saraOrg commented May 21, 2014

构建后到底是什么意思,请明示!

@saraOrg
saraOrg commented May 21, 2014

Tks

@saraOrg
saraOrg commented May 21, 2014

还要麻烦问一下我这段带am为什么要在后面使用seajs.use之后才会执行预加载prelaod
[code]
seajs.config({
base: '/',
alias: {'jq': 'jquery10.js'},
preload: ['jq']
});
[/code]

@army8735
Member

逻辑如此。preload的执行是写在use之前的,不调用use啥也不干。

@saraOrg
saraOrg commented May 21, 2014

额,感觉怪怪的,既然是预加载,那说明在不调用什么的时候就应该事先加载进来,这个官网文档没有说明吧

@afc163
Member
afc163 commented May 21, 2014

因为 seajs 的加载都是异步的,想象一下,你肯定得保证预加载的模块可以用之后才开始你的业务逻辑。

<script src="sea.js"></script>
<script>
seajs.config({
  preload: ['json.js']
});
</script>
<script>
// here can't find JSON
// 因为 preload 是异步的啊!!!!!!!!!!!!!!!!!!!
</script>
<script>
seajs.use([], function() {
  // here you can find JSON
});
</script>

所以只能在 use 的回调前保证。逻辑是很自然的。

如果要同步加载,那就 script 标签来引用吧。这是原生的,当然也很自然。

<script src="sea.js"></script>
<script src="json.js"></script>
<script>
console.log(JSON);
</script>
@saraOrg
saraOrg commented May 21, 2014

我甚是不理解啊,要保证预加载模块可以使用,use回调前也没有去判断,我就是配置的时候随便写一个模块【肯定不存在】,use之后还是会加载,还是加载失败的。。。先下班去,回家之后继续讨论哈!!!

@xieranmaya

想问一下seajs.require这个函数跟传入define里的require有什么区别吗?

@army8735
Member
army8735 commented Jun 4, 2014

seajs.require是开发者使用,根据uri获取一个模块,uri是定死的。
define的require更多是当前模块中请求依赖的模块,而且有解析相对路径。

@zhishaofei3

@nnzbz 可能是正则匹配吧

@iamweilee

请问seajs如何处理循环依赖的?
比如如下代码:
spinning.js:
define(function(require, exports, module) {

var $ = require('jquery');
var aaa = require('./test1');//这里是为了测试循环依赖而加入的代码

function Spinning(container) {
this.container = $(container);
this.icons = this.container.children();
this.spinnings = [];
}

module.exports = Spinning;
……
});

test1.js:
define(function(require, exports, module) {

var aaa = require('./spinning');//测试循环依赖

function test() {
return aaa;
}

module.exports = test;

});

这是官方的Hello Seajs的示例。我稍微做了修改。然后就有问题了。调试的时候发现main、spinning和test1的_remain=1、status = 3。所以不知道seajs是如何处理这种问题的?

@liudan92221

我估计里面肯定是用了toStrng()把方法里面的require提出来进行模块id解析的,等会去看看源码。

@zhishaofei3

比如说我有一个placeholder模块 用来在IE8以下浏览器模拟placeholder
我在入口文件里 我需要根据浏览器来决定是否require("placeholder")
用if和else不行 用动态加载貌似也不行 因为下面马上会用placeholder里面的方法了啊

@zhishaofei3

@iamweilee 那我这种情景 还有办法优化吗 chrome下也要加载这个js了?但是我压根没用它

@iamweilee

那你就用异步require吧,然后在回调里写业务逻辑,具体你看看seajs的demo

@szlijia
szlijia commented Aug 26, 2014

使用require 火狐浏览器出现卡死的情况,这是我使用的方法不对吗?
define(function(require) {
"use strict";
window.$ = window.jQuery = $ = require('jquery');
require('layer/layer.min');

出现卡死

@saraOrg
saraOrg commented Sep 12, 2014

哇 这么多人回复了!

@jsCONFIG
jsCONFIG commented Oct 8, 2014

这个直接字符串是不是为了用于打包时候的匹配检测啊?

@Grantlv
Grantlv commented Dec 4, 2014

大神,我想问一个seajs的require 和nodejs的require 的问题。虽然前者是前端,后者是服务器,但是有没有考虑到node-webkit? 如果我在node-webkit 桌面应用项目中用nodejs和seajs 他们的require是不是会冲突?

@wangxian
wangxian commented Dec 4, 2014

@grantSeajs

Sea.js 的 require 是一个形参,node-webkit的 require 是全局的,不影响。
对于 requirejs, node-webkit 的 wiki 上提供了官方的解决方案
见:https://github.com/rogerwang/node-webkit/wiki/faq-name-conflict

@meiyouqing

define("base/easing/1.3.0/easing", ["jquery"], function(require) {
var jQuery = require("jquery");
...
})
请问为什么浏览器提示“jQuery”是null了?路径都没有错,jquery也顺利加载了
还要我只要用var $ = require('jquery');,就会提示“$()"为object is not a function

@helloqinqin

用require加载一个文件,然后new的时候报错

我的代码是这样的
require('charts/component/colorFac');
var color = new gradientColor('#013548','#554851',10);

colorFac文件为是这样的
(function(win){
function gradientColor(startColor,endColor,step){
.....
}
gradientColor.prototype.colorRgb = function(sColor){
......
};
.....
})(window);

然后总是报错,gradientColor is not defined。我不清楚这是什么原因,看着colorFac.js文件已经加载了~

我想知道这是为啥呢?难道colorFac非得按照seajs的写法写?还是new的时候,colorFac.js文件没加载?

@zlstone
zlstone commented Mar 12, 2015

@helloqinqin 一般不会有这种情况发生,gradientColor is not defined说明全局肯定没有这个类存在,你得先确定库文件内部对外的接口是如何处理的,可能是进行过模块化的兼容,试试gradientColor=require('charts/component/colorFac');获取文件对外的api。还不行的话,确认一下gradientColor类名是否正确

@helloqinqin

@zlstone
首先谢谢了~
1.确定及肯定名字没错~
2.gradientColor=require('charts/component/colorFac'); 断点,gradientColor为空
3.从sources可以看到colorFac.js是加载了的

不过没有对colorFac.js用defined模块化。我想着,这个也不能强制要那么写的

@zlstone
zlstone commented Mar 12, 2015

@helloqinqin 不需要强制写,至少我用的2.1.0不需要,还是文件本身的问题,如果确定加载成功,全局没有,看看文件代码吧...

@helloqinqin

@zlstone
1.我按照define进行模块化了,并且把colorFac.js中的gradientColor方法前面的g大写了,然后就能行了~

2.我又把colorFac.js按照原来的,并且把gradientColor方法前面的g大写了,还是不行

我的seajs是2.3.0 具体什么原因还得多做实验,才能得出啊

@zhs23
zhs23 commented Mar 16, 2015

这种是不是以后加反射来处理了

@DennisEllen

用$=require('jquery')时,为什么alert($)返回的是null

@tbx19930222

希望有大牛帮我解答一下,为什么在safari浏览器下http://www.51go.me/加载的这么慢,是seajs的原因吗,有几个js我是require进来的

@xxiiaass

第一个参数'require',在压缩时候会改名,导致无法正常执行,有什么好的办法吗

@virtuecai

@xxiiaass 同问

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