Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

executable file 181 lines (175 sloc) 8.433 kb
#!/usr/bin/env node
var _ = require('underscore'),
AssetGraph = require('assetgraph'),
oneBootstrapper = require('../lib/util/oneBootstrapper'),
query = AssetGraph.query,
urlTools = require('assetgraph/lib/util/urlTools'),
commandLineOptions = require('optimist')
.usage('$0 --root <inputRootDirectory> --outroot <dir> [options] <htmlFile(s)>')
.options('root', {
describe: 'Path to your web root',
type: 'string',
demand: true
})
.options('outroot', {
describe: 'Path to the output folder. Will be generated if non-existing',
type: 'string',
demand: true
})
.options('cdnroot', {
describe: 'URI root where the static assets will be deployed',
type: 'string',
demand: false
})
.options('cdnoutroot', {
describe: 'Path to the CDN output folder. Will be generated if non-existing',
type: 'string',
demand: false
})
.options('label', {
describe: 'Registers labels as custom protocols for path resolving. You can create multiple of these: <labelName>=<dir>',
type: 'string',
demand: false
})
.options('locale', {
describe: 'Comma seperated list of locales to build seperate versions for',
type: 'string',
demand: false
})
.options('optimizepngs', {
describe: 'Tries optimal pallette reduction, removes ancillary chunks and tries for better compression',
type: 'boolean',
default: false
})
.options('inlinesize', {
describe: 'Inline CSS backgrounds below this threshold as data-uris',
default: 8192
})
.options('deferscripts', {
describe: 'Sets the "defer" attribute on all script tags',
type: 'boolean',
default: false
})
.options('asyncscripts', {
describe: 'Sets the "async" attribute on all script tags',
type: 'boolean',
default: false
})
.options('nocompress', {
describe: 'Prettifies HTML, CSS and Javascript for easier debugging',
type: 'boolean',
default: false
})
.options('mangletoplevel', {
describe: 'Wraps your javascript code in a function literal that pulls global variables into local variables for better minification. WARNING: This may break your JS',
type: 'boolean',
default: false
})
.options('manifest', {
describe: 'Generates an appcache manifest file with all static assets included',
type: 'boolean',
default: false
})
.options('less', {
describe: 'Translates .less files to CSS',
type: 'boolean',
default: false
})
.check(function (argv) {
return typeof argv.inlinesize === 'number';
})
.wrap(72)
.argv,
outroot = urlTools.fsDirToFileUrl(commandLineOptions.outroot),
cdnroot = commandLineOptions.cdnroot && urlTools.ensureTrailingSlash(commandLineOptions.cdnroot),
cdnoutroot = commandLineOptions.cdnoutroot && urlTools.fsDirToFileUrl(commandLineOptions.cdnoutroot),
localeIds = commandLineOptions.locale && _.flatten(_.flatten([commandLineOptions.locale]).map(function (localeId) {return localeId.split(",");}));
require('../lib/registerTransforms');
new AssetGraph({root: commandLineOptions.root})
.on('afterTransform', function (transform, elapsedTime) {
console.log((elapsedTime / 1000).toFixed(3) + " secs: " + transform.name);
})
.on('error', function (err) {
console.error(err.stack);
process.exit(1);
})
.registerRequireJsConfig()
.registerLabelsAsCustomProtocols(commandLineOptions.label)
.loadAssets(commandLineOptions._.map(urlTools.fsFilePathToFileUrl))
.populate({
followRelations: query.or({to: {type: 'I18n'}},
{type: query.not(['JavaScriptOneInclude', 'JavaScriptExtJsRequire', 'JavaScriptCommonJsRequire', 'HtmlAnchor']), to: {url: query.not(/^https?:/)}})
})
.stripDevelopmentModeFromOneBootstrapper({type: 'Html', isInitial: true})
.if(cdnroot)
.queue(function addCdnRootToOneBootstrapper(assetGraph) {
oneBootstrapper.findOneBootstrappersInGraph(assetGraph).forEach(function (javaScript) {
javaScript.parseTree[1].splice(1, 0, ['stat', ['assign', true, ['dot', ['name', 'one'], 'cdnRoot'], ['string', cdnroot]]]);
});
})
.endif()
.addContentVersionMetaElement({type: 'Html'}, '{0}/production', true)
.if(commandLineOptions.less)
// Replace Less assets with their Css counterparts:
.compileLessToCss({type: 'Less'})
// Kill in-browser less compiler and remove its incoming relations:
.removeAssets({url: /\/less(?:-\d+\.\d+\.\d+)?(?:\.min)?\.js$/}, true)
// Find and populate CssImage relations from the compiled Less assets:
.populate({from: {type: 'Css'}})
.endif()
.removeRelations({type: 'JavaScriptOneInclude', to: {type: ['Css', 'JavaScript']}}, {detach: true, unresolved: true})
.convertCssImportsToHtmlStyles()
.removeAssets({isEmpty: true, type: ['Css', 'JavaScript']}, true)
.externalizeRelations({from: {type: query.not('Htc')}, type: ['HtmlStyle', 'HtmlScript'], node: function (node) {return !node.hasAttribute('nobundle');}})
.mergeIdenticalAssets(query.or({isImage: true}, {type: ['JavaScript', 'Css']}))
.spriteBackgroundImages()
.postProcessCssImages()
.if(commandLineOptions.optimizepngs)
.optimizePngs()
.endif()
.bundleRequireJs({type: 'Html'})
.bundleRelations({type: 'HtmlStyle', to: {type: 'Css'}, node: function (node) {return !node.hasAttribute('nobundle');}})
.bundleRelations({type: 'HtmlScript', to: {type: 'JavaScript'}, node: function (node) {return !node.hasAttribute('nobundle');}})
.removeNobundleAttribute({type: ['HtmlScript', 'HtmlStyle']})
.inlineCssImagesWithLegacyFallback({type: 'Html', isInline: false}, commandLineOptions.inlinesize)
.if(commandLineOptions.mangletoplevel)
.pullGlobalsIntoVariables({type: 'JavaScript'})
.endif()
.if(!commandLineOptions.nocompress)
.compressJavaScript({type: 'JavaScript'}, 'uglifyJs', {toplevel: commandLineOptions.mangletoplevel})
.endif()
.if(localeIds)
.cloneForEachLocale({type: 'Html', isInitial: true}, localeIds)
.runJavaScriptConditionalBlocks({isInitial: true}, 'localize', true)
.endif()
.removeAssets({type: 'I18n'}, true)
.minifyAssets()
.inlineRelations({
type: ['HtmlStyle', 'HtmlScript'],
from: {isInline: false}, // Excludes relations occurring in conditional comments
to: function (asset) {return asset.isAsset && asset.rawSrc.length < 4096;}
})
.if(commandLineOptions.manifest)
.addCacheManifest({isInitial: true})
.endif()
.if(commandLineOptions.nocompress)
.prettyPrintAssets({type: ['Html', 'JavaScript', 'Css']})
.endif()
.setAsyncOrDeferOnHtmlScripts({to: {isInline: false, url: /^file:/}}, commandLineOptions.asyncscripts, commandLineOptions.deferscripts)
.omitGetStaticUrlFunctionCall()
.inlineRelations({type: 'JavaScriptOneGetText'})
.moveAssetsInOrder({isInitial: query.not(true), type: query.not('CacheManifest')}, function (asset, assetGraph) {
var targetUrl = "/static/";
// Conservatively assume that all one.getStaticUrl relations pointing at non-images are intended to be fetched via XHR
// and thus cannot be put on a CDN because of same origin restrictions:
if (cdnroot && (asset.isImage || assetGraph.findRelations({to: asset, type: 'StaticUrlMapEntry'}).length === 0)) {
targetUrl = cdnroot;
}
return targetUrl + asset.md5Hex.substr(0, 10) + asset.extension + asset.url.replace(/^[^#\?]*/, ''); // Preserve query string and fragment identifier
})
.writeAssetsToDisc({url: /^file:/}, outroot)
.if(cdnroot)
.writeAssetsToDisc({url: query.createPrefixMatcher(cdnroot)}, cdnoutroot || outroot, cdnroot)
.endif()
.writeStatsToStderr()
.run();
Jump to Line
Something went wrong with that request. Please try again.