我正在构建我的第一个(非意大利面)大型JavaScript应用程序。虽然为JavaScript引入RequireJS和其他依赖关系管理框架可以更容易地分割文件,但我不清楚如何将大型代码库推向生产。我想要的是使用诸如Ready.js和UglifyJS之类的东西来聚合和缩小/ uglify我的JavaScripts以进行生产的方法。或者其他一些方法,如果有意义的话。
生产中使用大型JavaScript应用的开发人员如何处理开发和生产中的结构?
例如,我可以在开发中使用RequireJS,然后使用Ready / Uglify进行聚合/缩小。但是,我的代码在整个过程中都会毫无意义require()'s
。我确信有更好的方法。
我也对在这些文件中包含jQuery感到困惑。我应该在他们自己的$(document).ready(function(){...})
内包装每个单独的jQuery文件(例如使用jQuery的Backbone视图)吗?这似乎非常不干。
答案 0 :(得分:2)
您可以使用RequireJS optimizer。即使在压缩的应用程序中,这些要求也毫无意义,因为您始终必须获得对模块的引用。优化器文档还说,它不会包含已加载变量的模块,如
var mods = someCondition ? ['a', 'b'], ['c', 'd'];
require(mods);
我认为RequireJS应该等到DOM准备就绪和所有模块都已加载,所以你不需要包装每个文件。
那就是说,我最喜欢的包经理仍然是StealJS。它可以在生产构建中启动不必要的调用,并且模块总是封装在一个闭包中,该闭包将传递jQuery对象并等待直到DOM准备好并且所有脚本都已加载。不幸的是,它还没有与CommonJS模块规范兼容。
答案 1 :(得分:1)
我发现YUI Builder对我很有用。如果你没有使用YUI 3,我不确定它是多么有用,但你很有可能根据你的需要调整它。
另一方面,你看过RequireJS Optimizer吗?
关于document.ready
处理;我认为最好不要让模块中的代码在初始化或调用之前做任何事情。所以我在页面底部的$(document).ready()
标签中会有一个<script>
,它会“粘合”该页面上所需的模块。
答案 2 :(得分:0)
为了有效地开发和轻松维护JavaScript应用程序,而不是大量的临时脚本或低于非透明的自动化,您可以使用native Qooxdoo application。如果不写太多,就不可能覆盖Qooxdoo,但是对于本机应用程序(不要将术语与C或Java混淆,Qooxdoo是纯JavaScript),它被描述为:
对于使用基于HTML / CSS的自定义GUI而不是qooxdoo的小部件图层的应用程序。
因此,此类应用程序不使用任何Qooxdoo UI层,而只使用代码结构工具和构建工具。 Qooxdoo中的代码按类组织,每个文件一个,如Java。我可能看起来像这样:
/**
* @use(website.library.MosaicFlow)
*/
qx.Class.define('website.controller.Gallery', {
extend : website.controller.Abstract,
members : {
_baseUrl : 'https://picasaweb.google.com/data/feed/api',
_render : function(photos)
{
q('.preloader').remove();
q.template.get('gallery-template', {'photos': photos}).appendTo('#gallery-container');
var gallery = window.jQuery('#gallery-container .gallery').mosaicflow({
'minItemWidth' : 256,
'itemSelector' : '.photo',
'autoCalculation' : false
});
gallery.trigger('resize');
},
_convert : function(item, index)
{
try
{
return {
'url' : item.content.src,
'summary' : item.summary.$t,
'thumb' : item.media$group.media$thumbnail[0]
};
}
catch(ex)
{
this.debug('failed to convert', index, item);
return null;
}
},
_onLoadSuccess : function(event)
{
var request = event.getTarget();
var response = request.getResponse();
if(!qx.lang.Type.isObject(response) || !('feed' in response))
{
request.debug('Malformed response received');
}
else
{
this._render(response.feed.entry.map(this._convert, this).filter(function(item)
{
return !!item;
}));
}
},
_onLoadFail : function()
{
this.debug('Picasa search failed');
},
main : function()
{
var query = /^\/gallery\/(\w+)$/.exec(window.location.pathname);
var request = new qx.io.request.Jsonp(qx.lang.String.format('%1/all', [this._baseUrl]));
request.setRequestData({
'q' : query[1],
'thumbsize' : 300,
'max-results' : 20,
'alt' : 'json'
});
request.setTimeout(16000);
request.setCache(false);
request.addListener('fail', this._onLoadFail, this);
request.addListener('success', this._onLoadSuccess, this);
request.send();
}
}
});
Qooxdoo对象模型充分利用了这两个方面。具有Java等成熟平台的特性,同时具有现代和动态,提供类,继承,接口,混合,事件,属性,数据绑定等。因为每个类都有一个已定义的名称并位于命名空间树中,所以Qooxdoo生成器可以利用它。它解析您的类并构建其语法树。然后它解决了依赖关系。即当你引用另一个类时,比如website.controller.Abstract
。这导致依赖图,用于按正确顺序加载脚本。请注意,对于开发人员来说,这一切都是自动且透明的,文件按原样加载。在CommonJS的情况下没有任何让步,没有像AMD这样的包装代码的丑陋样板。
正如您在上面的示例中所看到的,可以处理外部非qooxdoo库。您只需要为库编写一个虚拟包装器,以便在构建过程中包含它。
您开发构建应用程序(仅在代码中引入新依赖项时才需要构建),并使用所谓的源目标。您的应用程序文件按依赖顺序逐个加载。框架文件可以逐个加载,或者哪个是更好的选项,它们构建在几个大块中。在生产环境中,您的应用程序代码使用构建目标构建。您可以选择生成单个输出文件,或者具有部分生成,其中代码在大文件中分块(您可以控制它们的大小)。部分构建可能看起来像这样(优化/ gzip):
├── [127/64kB] website.f6ffa57fc541.js
├── [100/33kB] website.f86294b58d1a.js
└── [361/110kB] website.js
请注意,部件是在需要它们的页面上按需加载的。
http://example.com/
└── website.js
http://example.com/article
└── website.js
http://example.com/form
└── website.js
└── website.f86294b58d1a.js
http://example.com/gallery
└── website.js
└── website.f6ffa57fc541.js
http://example.com/geo
└── website.js
由于Qooxdoo尚未针对成熟的网站构建,但仅提供本机应用程序类型的平台,您需要编写应用程序的条目和一些基础知识,如引导,URL路由等。我试过使用qooxdoo-website-skeleton解决此问题,以上哪些示例属于。您可以自由使用它,也可以自己编写。
最后请注意,它可能不像普通的JavaScript库那样容易,但复杂性与最终的好处成正比。