在复杂的客户端项目中,Javascript文件的数量会变得非常大。但是,出于性能原因,最好连接这些文件,并压缩生成的文件以通过网络发送。我在连接这些时遇到了问题,因为在某些情况下需要它们之后会包含依赖项。
例如,有2个文件:
/modules/Module.js <requires Core.js>
/modules/core/Core.js
以递归方式遍历目录,并在Module.js
之前包含Core.js
,这会导致错误。这只是一个简单的示例,其中依赖项可以跨目录,并且可能存在其他复杂情况。但是没有循环依赖。
我遵循的Javascript结构类似于Java包,其中每个文件定义一个Object(我使用的是MooTools,但这是无关紧要的)。每个javascript文件的结构和依赖关系始终是一致的:
Module.js
var Module = new Class({
Implements: Core,
...
});
Core.js
var Core = new Class({
...
});
在Javascript文件数量巨大且存在文件间依赖关系的项目中,您通常遵循哪些实践来处理依赖项?
答案 0 :(得分:2)
使用目录很聪明,但是,我认为当您有多个依赖项时可能会遇到问题。我发现我必须创建自己的解决方案来处理这个问题。所以,我创建了一个值得一试的依赖管理工具。 (Pyramid Dependency Manager documentation)
它做了一些其他javascript依赖管理器不做的重要事情,主要是
一些示例代码,用于说明它在开发过程中的工作原理。
文件: dependencyLoader.js
//Set up file dependencies
Pyramid.newDependency({
name: 'standard',
files: [
'standardResources/jquery.1.6.1.min.js'
]
});
Pyramid.newDependency({
name:'lookAndFeel',
files: [
'styles.css',
'customStyles.css'
]
});
Pyramid.newDependency({
name:'main',
files: [
'createNamespace.js',
'views/buttonView.view', //contains just html code for a jquery.tmpl template
'models/person.js',
'init.js'
],
dependencies: ['standard','lookAndFeel']
});
Html文件
<head>
<script src="standardResources/pyramid-1.0.1.js"></script>
<script src="dependencyLoader.js"></script>
<script type="text/javascript">
Pyramid.load('main');
</script>
</head>
答案 1 :(得分:1)
这可能很粗糙,但我所做的是将单独的脚本片段保存在单独的文件中。我的项目是这样的,我愿意为每个页面提供所有可用的Javascript(因为,毕竟,它将被缓存,并且我没有注意到解析步骤中的性能问题)。因此,在构建时,我的Ant脚本通过一个小的自定义Ant任务运行Freemarker。这些任务以源代码树为基础,将所有单独的Javascript源文件收集到一组Maps中。有几种不同类型的源(jQuery扩展,一些页面加载操作,所以常规实用程序等等),因此任务将这些不同类型组合在一起(从脚本源目录结构中获取有关内容的提示。
一旦它构建了地图,它就会将它们提供给Freemarker。有一个全局模板,通过Freemarker,所有脚本片段都打包到那个文件中。然后通过YUI压缩机和宾果游戏!每个页面只抓取一个脚本,一旦它被缓存,我的整个站点就不再有脚本了。
依赖性,你问?好吧,Ant任务在构建这些映射时按名称命令我的源文件,因此在需要确保定义使用顺序时,我只需在数据代码前加上文件。 (在某些时候我会把它搞砸,以便源文件可以在注释块或其他内容的源代码中保留它们的排序信息,或者甚至可能是显式声明的依赖项。我不是太有动力,因为它虽然有点丑陋它真的不会打扰任何人那么多。)
答案 2 :(得分:1)
我编写了一个非常粗略的依赖查找程序,基于此我正在进行连接。事实证明,使用MooTools并不是那么无关紧要。解决方案很有效,因为它不需要单独维护依赖信息,因为它在javascript文件中可用,这意味着我可以超级懒惰。
由于类和文件命名是一致的,因此类Something
将始终具有文件名Something.js
。要找到外部依赖项,我正在寻找三件事:
new
关键字在每个javascript文件中搜索上述三种模式会给出其依赖类。找到依赖类后,搜索驻留在任何文件夹中的所有Javascript文件并与此类名匹配,以确定该类的定义位置。找到依赖项后,我构建一个dependency graph并使用topological sort算法生成应包含文件的顺序。
答案 3 :(得分:0)
我说只需按顺序将这些文件复制并粘贴到一个文件中即可。每个文件都有一个开始和结束注释,以区分每个特定代码。
每次更新其中一个文件时,您都需要更新此文件。因此,此文件只需包含 finish 库,这些库在近期内不会发生变化。
答案 4 :(得分:0)
您的目录结构已反转......
核心依赖项应位于根目录中,模块位于子目录中。
scripts/core.js
scripts/modules/module1.js
,你的问题就解决了。
任何进一步的依赖性问题都将表明有缺陷的“阶级”/依赖性设计。
答案 5 :(得分:0)
与Mendy类似,但我在服务器端创建组合文件。创建的文件也将缩小,并且具有唯一的名称,以在更新后省略缓存问题。
当然,这种做法只适用于整个应用程序或框架。
答案 6 :(得分:0)
我认为,如果可能的话,最好的选择就是重新设计没有大量具有文件间依赖关系的javascript文件。 Javascript只是不打算去那里。
答案 7 :(得分:0)
这可能太明显但你看过mootools Core Depender:http://mootools.net/docs/more/Core/Depender
答案 8 :(得分:0)
打破解析时或加载时依赖性的一种方法是使用自定义对象(Self-Defining Functions的变体)。
假设你有这样的事情:
var obj = new Obj();
此行在someFile.js中,而Obj在Obj.js中定义。为了成功解析,必须在someFile.js之前加载或连接Obj.js。
但是如果你这样定义obj:
var obj = {
init: function() {
obj = new Obj();
}
};
然后在解析或加载时,只要Obj在运行时可见,加载这两个文件的顺序并不重要。你必须调用obj.init()才能使你的对象进入你想要的状态,但这是打破依赖性的一个小代价。
为了更清楚地了解这是如何工作的,您可以剪切并粘贴到浏览器控制台中的一些代码:
var Obj = function() {
this.func1 = function ( ) {
console.log("func1 in constructor function");
};
this.init = function () {
console.log("init in constructor function");
}
};
var obj = {
init: function() {
console.log("init in original object");
obj = new Obj();
obj.init();
}
};
obj.init();
obj.func1();
您还可以尝试像RequireJS这样的模块加载器。