express-yui
Version:
Express extension for YUI Applications
265 lines (195 loc) • 7.95 kB
JavaScript
/*
* Copyright (c) 2013, Yahoo! Inc. All rights reserved.
* Copyrights licensed under the New BSD License.
* See the accompanying LICENSE file for terms.
*/
/*jslint node:true, nomen: true */
/**
The `express-yui.origin` extension that provides a set of features
to mutate the express app into an origin server for yui
modules and static assets.
@module yui
@submodule origin
**/
'use strict';
var libpath = require('path'),
utils = require('./utils'),
DEFAULT_COMBO_CONFIG = {
maxURLLength: 1024,
comboBase: "/combo~",
comboSep: "~"
};
/**
The `express-yui.origin` extension that provides some basic configuration
that will facilitate the configuration of YUI Core modules and other
groups to be served from the express app in a form of origin server.
This is not recommended for production and instead you should use the
`cdn` module, but it is a very useful feature for development of offline
applications.
// Creates a new express app.
var app = express();
// getting YUI Core modules from the app origin.
app.yui.setCoreFromAppOrigin();
// registering a group `app` based on a folder generated by `shifter` module
app.yui.registerGroup('app', '/path/to/foo/yui-build');
// getting group `app` from the app origin.
app.yui.setGroupFromAppOrigin('app');
// add support for `combine` for core and `app` groups.
app.yui.combineGroups();
app.use(yui.static());
@class origin
@static
@uses utils, *path
@extensionfor yui
*/
module.exports = {
/**
Set YUI Core Modules from the same origin as to where the application
is hosted.
Here is an example on how to use it:
app.yui.setCoreFromAppOrigin({});
@method setCoreFromAppOrigin
@public
@param {Object} loaderConfig
@chainable
**/
setCoreFromAppOrigin: function (loaderConfig) {
var prefix = this._app.set('yui static prefix') || "/",
config = this.config();
loaderConfig = loaderConfig || {};
// fixed base and root for this group
loaderConfig.base = prefix + "yui/";
loaderConfig.root = "/yui/";
loaderConfig.local = true;
loaderConfig = utils.extend(config, DEFAULT_COMBO_CONFIG, loaderConfig);
return this;
},
/**
Set a registered group from the app origin server as to
where the application is hosted.
Here is an example of how to use it.
app.yui.setGroupFromAppOrigin('app', { }, { });
@method setGroupFromAppOrigin
@public
@param {String} groupName the name of the group used by loader.
@param {Object} loaderConfig The custom loader configuration
for the group.
@param {number} loaderConfig.maxURLLength default to `1024`
@param {string} loaderConfig.comboBase default to `"/combo~"`
@param {string} loaderConfig.comboSep default to `"~"`
@chainable
**/
setGroupFromAppOrigin: function (groupName, loaderConfig) {
var prefix = this._app.set('yui static prefix') || "/",
config = this.config(),
folderPath = groupName && this._groupFolderMap && this._groupFolderMap[groupName];
if (!folderPath || !config.groups || !config.groups[groupName]) {
throw new Error("Unknown group name [" + groupName + '], ' +
"you should register the group by calling `registerGroup()` method.");
}
loaderConfig = loaderConfig || {};
loaderConfig.base = prefix + groupName + "/";
loaderConfig.root = "/" + groupName + "/";
loaderConfig.local = true;
loaderConfig = utils.extend(config.groups[groupName], DEFAULT_COMBO_CONFIG,
loaderConfig);
return this;
},
/**
Register a group and its modules by analyzing the meta file and defining the
group configuration for the loader. Groups can be served from origin app or
from CDN by calling `setGroupFromAppOrigin` or `setGroupFromCDN`.
Here is an example on how to use it, assuming that the YUI metadata are
located in the `build` directory under the app root.
app.yui.registerGroup('app', __dirname + '/build');
@method registerGroup
@public
@param {String} groupName the name of the group used by loader.
@param {String} groupRoot filesystem path for the group. This will be used to
analyze all modules in the group.
@param {String} metaFile optional filesystem path for the yui module that holds
the metas for the group. Default value: `<groupRoot>/<groupName>/<groupName>.js`
@chainable
**/
registerGroup: function (groupName, groupRoot, metaFile) {
var group,
groupConfig,
config;
metaFile = metaFile || libpath.join(groupRoot, groupName, groupName + '.js');
// collect the group information from the meta file
group = this.getGroupConfig(metaFile);
if (!group) {
throw new Error("Invalid meta file [" + metaFile + "], " +
"it contains no group.");
}
if (groupName !== group.groupName) {
throw new Error("Mismatch between the groupName [" + groupName +
"] and the group registered in [" + metaFile + "].");
}
config = this.config();
config.groups = config.groups || {};
config.groups[groupName] = groupConfig =
config.groups[groupName] || {};
// inherit combine if needed
if (!groupConfig.hasOwnProperty('combine')) {
groupConfig.combine = config.combine;
}
// inherit filter if needed
if (!groupConfig.hasOwnProperty('filter')) {
groupConfig.filter = config.filter;
}
// storing the root path to the group in case we
// need it later to server the group from origin server
this._groupFolderMap = this._groupFolderMap || {};
this._groupFolderMap[groupName] = groupRoot;
// add the meta module into the core structure
// to make sure it gets attached to Y upfront
this.addModuleToSeed(group.moduleName, groupName);
return this;
},
/**
Combine group and core modules if they loader configuration matches the values
of `loaderConfig.comboBase` and `loaderConfig.comboSep`.
The default configuration for the combo is:
{
maxURLLength: 1024,
comboBase: "/combo~",
comboSep: "~"
}
Here is an example of how to use it:
app.yui.combineGroups();
Note: this method should be called after defining
the settings for all groups and core modules.
@method combineGroups
@public
@param {Object} loaderConfig The base loader configuration
for the groups to be combined.
@param {Number} loaderConfig.maxURLLength default to `1024`
@param {String} loaderConfig.comboBase default to `"/combo~"`
@param {String} loaderConfig.comboSep default to `"~"`
@chainable
**/
combineGroups: function (loaderConfig) {
var config = this.config(),
groups = config.groups || {},
group;
// getting options ready, mixing it with default values
loaderConfig = utils.extend({}, DEFAULT_COMBO_CONFIG, (loaderConfig || {}));
function fnTestGroup(g) {
return g.comboBase === loaderConfig.comboBase &&
g.comboSep === loaderConfig.comboSep &&
g.combine !== false && g.root;
}
// forcing combine for yui
if (fnTestGroup(config)) {
config.combine = true;
}
// forcing combine for group that can work with combo
for (group in groups) {
if (groups.hasOwnProperty(group) && fnTestGroup(groups[group])) {
groups[group].combine = true;
}
}
return this;
}
};