Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'develop-perf' of git://github.com/yahoo/mojito into dev…

…elop-perf
  • Loading branch information...
commit c744d78818615e9456d9564047f055c7fdfc6ac6 2 parents 1eb1180 + 4164f22
@bthaeler authored
View
9 lib/app/addons/ac/deploy.server.js
@@ -112,8 +112,9 @@ YUI.add('mojito-deploy-addon', function(Y, NAME) {
yuiConfig.base = appConfigClient.yui.base;
yuiConfig.combine = !!appConfigClient.yui.combine;
} else {
- yuiConfig.base = 'combo?';
yuiConfig.combine = true;
+ yuiConfig.comboBase = "/combo?";
+ yuiConfig.root = "";
}
clientConfig.store = store.serializeClientStore(contextClient);
@@ -169,11 +170,7 @@ YUI.add('mojito-deploy-addon', function(Y, NAME) {
initialModuleList = "'" + Y.Object.keys(initialModuleList).join("','") + "'";
initializer = '<script type="text/javascript">\n' +
- ' YUI_config = ' + yuiConfigStr + ';\n' +
- ' YUI.Env.core.push("loader-base"); // workaround (ticket 2532571)\n' +
- ' YUI_config.bootstrap = true;\n' +
- ' YUI_config.comboBase = "/combo?";\n' +
- ' YUI_config.combine = true;\n' +
+ ' YUI.applyConfig(' + yuiConfigStr + ');\n' +
' YUI().use(' + initialModuleList + ', function(Y) {\n' +
' window.YMojito = { client: new Y.mojito.Client(' +
clientConfigStr + ') };\n' +
View
95 lib/app/middleware/mojito-combo-handler.js
@@ -19,7 +19,7 @@
*/
-/*jslint anon:true, sloppy:true, nomen:true, stupid:true*/
+/*jslint anon:true, sloppy:true, nomen:true, stupid:true, node: true*/
/*
DECLAIMER: this is VERY experimental, and the purpose of this
@@ -37,14 +37,31 @@ dependencies computations efficiently.
var libfs = require('fs'),
mime = require('mime'),
libpath = require('path'),
- existsSync = libfs.existsSync || libpath.existsSync,
parseUrl = require('url').parse,
logger,
NAME = 'ComboHandler',
MODULE_META_ENTRIES = ['requires', 'use', 'optional', 'skinnable', 'after', 'condition'],
+ // TODO: revisit this list with @davglass
MODULE_META_PRIVATE_ENTRIES = ['after', 'expanded', 'supersedes', 'ext', '_parsed', '_inspected',
- 'skinCache', 'langCache'];
+ 'skinCache', 'langCache'],
+
+ DEFAULT_HEADERS = {
+ '.js': {
+ 'Content-Type': 'application/javascript; charset=utf-8'
+ },
+ '.css': {
+ 'Content-Type': 'text/css; charset=utf-8'
+ }
+ },
+
+ // This dummy templace will be use to produce the loader content.
+ // TODO: we should use YUI.applyConfig() instead of the internal
+ // YUI.Env API, but that's pending due a bug in YUI:
+ // http://yuilibrary.com/projects/yui3/ticket/2532854
+ LOADER_MODULE_TEMPLATE = 'YUI.add("loader",function(Y){' +
+ 'YUI.Env[Y.version].modules=YUI.Env[Y.version].modules||{metadata};' +
+ '}, "", {requires:["loader-base"]});';
/*
* File buffer cache.
@@ -274,7 +291,7 @@ function staticProvider(store, globalLogger, Y) {
files = [],
filename = '',
module = '',
- yui = '',
+ ext = '',
result = [],
counter = 0,
i = 0,
@@ -282,13 +299,17 @@ function staticProvider(store, globalLogger, Y) {
head = (req.method === 'HEAD');
// only combo requests are allow here
- if (url.pathname !== '/combo') {
+ if (url.pathname !== '/combo' || !url.query) {
return next();
}
logger.log('serving static path: ' + url.pathname, 'debug', 'static-handler');
- files = url.query.split('&');
+ // YIV might be messing around with the querystring params
+ // trying to formalize them by adding = and transforming /
+ // so we need to revert back to / and remove the =
+ // TODO: this might not work in Windows
+ files = url.query.replace(/[=]/g, '').replace(/%2F/g, '/').split('&');
function readHandler(index, filename) {
return function (err, data) {
@@ -303,15 +324,16 @@ function staticProvider(store, globalLogger, Y) {
result[index].content = data;
}
if (counter === files.length) {
+
for (i = 0; i < counter; i += 1) {
content += result[i].content;
}
- headers = {
- 'Content-Type': 'application/javascript; charset=utf-8',
+ headers = Y.merge({
'Content-Length': content.length,
'Last-Modified': new Date().toUTCString(),
'Cache-Control': 'public max-age=' + (maxAge / 1000)
- };
+ }, (DEFAULT_HEADERS[ext] || {}));
+
res.writeHead(200, headers);
res.end(head ? undefined : content);
@@ -319,45 +341,64 @@ function staticProvider(store, globalLogger, Y) {
};
}
+ if (files.length === 0) {
+ // probably an empty /combo? request
+ res.writeHead(400);
+ res.end(undefined);
+ return;
+ }
+
+ // combo response's content-type should be
+ // resolved from the first file in the list
+ ext = libpath.extname(files[0]);
+
+ if (!ext || !DEFAULT_HEADERS.hasOwnProperty(ext)) {
+ // probably an invalid request
+ res.writeHead(400);
+ res.end(undefined);
+ return;
+ }
+
// validating all files before doing anything else
// so errors can be found early on.
for (i = 0; i < files.length; i += 1) {
- yui = libpath.join(__dirname,
- '../../../node_modules/yui', files[i]);
- module = libpath.basename(files[i]).split('.')[0];
- module = module.replace(/\-(min|debug)$/, '');
+ // something like foo/bar-min.js should become just "bar"
+ module = libpath.basename(files[i], ext).
+ replace(/\-(min|debug)$/, '');
if (module === 'loader-app-base') {
result[i] = {
fullpath: module,
- content: "YUI.applyConfig({modules:" + appMetaData + "});"
+ content: LOADER_MODULE_TEMPLATE.replace('{metadata}', appMetaData)
};
} else if (module === 'loader-app-full') {
result[i] = {
fullpath: module,
- content: "YUI.applyConfig({modules:" + appResolvedMetaData + "});"
+ content: LOADER_MODULE_TEMPLATE.replace('{metadata}', appResolvedMetaData)
};
} else if (urls[module]) {
result[i] = {
fullpath: urls[module],
content: ''
};
- } else if ((module.indexOf('..') === -1) && existsSync(yui)) {
+ } else if (loader.moduleInfo[module] && loader.moduleInfo[module].path) {
result[i] = {
- fullpath: yui,
+ fullpath: libpath.join(__dirname,
+ '../../../node_modules/yui', loader.moduleInfo[module].path),
content: ''
};
} else {
logger.log('Invalid module name: ' + module, 'warn', NAME);
res.writeHead(400);
res.end(undefined);
+ break;
}
}
// async queue implementation
- if (result.length === files.length) {
+ if (files.length > 0 && (result.length === files.length)) {
for (i = 0; i < result.length; i += 1) {
filename = result[i].fullpath;
if (result[i].content) {
@@ -365,9 +406,25 @@ function staticProvider(store, globalLogger, Y) {
// just use it directly.
readHandler(i, filename)(null, result[i].content);
} else {
- libfs.readFile(filename, readHandler(i, filename));
+ try {
+ libfs.readFile(filename, readHandler(i, filename));
+ } catch (err) {
+ logger.log('Error reading: ' + filename, 'error', NAME);
+ // this should never happen, if the module is in loader
+ // meta, it should be in disk as well.
+ res.writeHead(400);
+ res.end(undefined);
+ break;
+ }
}
}
+ } else {
+ logger.log('Error producing combo: ' + files, 'error', NAME);
+ // this should never happen, because an invalid
+ // module error should happen before reaching this.
+ res.writeHead(400);
+ res.end(undefined);
+ return;
}
};
View
2  package.json
@@ -27,7 +27,7 @@
"semver": "1.0.14",
"wrench": "~1.3.9",
"ycb": "~1.0.0",
- "yui": "~3.5.1",
+ "yui": "~3.7.2",
"yuidocjs": "~0.3.14",
"yuitest": "~0.7.4"
},
Please sign in to comment.
Something went wrong with that request. Please try again.