Skip to content
This repository has been archived by the owner on Jan 4, 2019. It is now read-only.

Commit

Permalink
Inplace inline *all* imports
Browse files Browse the repository at this point in the history
Instead of searching for "good" spots to insert HTML, we just replace links inline.
This is a major change, but it greatly simplifies the code, and makes understandable output.
  • Loading branch information
dfreedm committed Feb 25, 2014
1 parent 3048fdd commit 2f85cdf
Showing 1 changed file with 34 additions and 72 deletions.
106 changes: 34 additions & 72 deletions lib/vulcan.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,24 @@ var cleancss = require('clean-css');
var fs = require('fs');
var path = require('path');
var uglify = require('uglify-js');
var url = require('url');

var constants = require('./constants.js');
var optparser = require('./optparser.js');
var pathresolver = require('./pathresolver');

var import_buffer = [];
var read = {};
var options = {};


// validate options with boolean return
function setOptions(optHash, callback) {
optparser.processOptions(optHash, callback);
optparser.processOptions(optHash, function(err, o) {
if (err) {
return callback(err);
}
options = o;
callback();
});
}

function exclude(regexes, href) {
Expand All @@ -49,22 +54,14 @@ function setTextContent(node, text) {
node[0].children[0].data = text;
}

function readDocument(docname) {
if (options.verbose) {
console.log('Reading:', docname);
}
var content = fs.readFileSync(docname, 'utf8');
return cheerio.load(content);
}

// inline relative linked stylesheets into <style> tags
function inlineSheets($, inputPath, outputPath) {
$('link[rel="stylesheet"]').each(function() {
var href = this.attr('href');
if (href && !excludeStyle(href)) {
var filepath = path.resolve(inputPath, href);
// fix up paths in the stylesheet to be relative to the location of the style
var content = rewriteURL(path.dirname(filepath), inputPath, fs.readFileSync(filepath, 'utf8'));
var content = pathresolver.rewriteURL(path.dirname(filepath), inputPath, fs.readFileSync(filepath, 'utf8'));
var styleDoc = cheerio.load('<style>' + content + '</style>');
// clone attributes
styleDoc('style').attr(this.attr());
Expand All @@ -77,7 +74,7 @@ function inlineSheets($, inputPath, outputPath) {
}

function inlineScripts($, dir) {
$(JS_SRC).each(function() {
$(constants.JS_SRC).each(function() {
var src = this.attr('src');
if (src && !excludeScript(src)) {
var filepath = path.resolve(dir, src);
Expand All @@ -87,15 +84,19 @@ function inlineScripts($, dir) {
});
}

function readDocument(filename) {
return cheerio.load(fs.readFileSync(filename, 'utf8'));
}

function concat(filename) {
if (!read[filename]) {
read[filename] = true;
var $ = readDocument(filename);
var dir = path.dirname(filename);
processImports($, dir);
inlineSheets($, dir, options.outputDir);
resolvePaths($, dir, options.outputDir);
import_buffer.push($.html());
pathresolver.resolvePaths($, dir, options.outputDir);
return $.html();
} else {
if (options.verbose) {
console.log('Dependency deduplicated');
Expand All @@ -104,53 +105,23 @@ function concat(filename) {
}

function processImports($, prefix) {
$(IMPORTS).each(function() {
$(constants.IMPORTS).each(function() {
var href = this.attr('href');
if (excludeImport(href)) {
// rewrite href to be deduplicated later
this.attr('href', rewriteRelPath(prefix, options.outputDir, href));
imports_before_polymer.push(this);
this.attr('href', pathresolver.rewriteRelPath(prefix, options.outputDir, href));
} else {
concat(path.resolve(prefix, href));
this.replaceWith(concat(path.resolve(prefix, href)));
}
}).remove();
});
}

function findScriptLocation($) {
var pos = $(POLYFILLS).last().parent();
if (!pos.length) {
pos = $('body').last();
}
if (!pos.length) {
pos = $.root();
}
return pos;
}

function insertImport($, importText) {
// before polymer script in <head>
var pos = $('head ' + POLYFILLS).last();
var operation = 'after';
if (!pos.length) {
// at the bottom of head
pos = $('head').last();
operation = 'append';
}
if (!pos.length) {
// at the top of top document
pos = $.root();
operation = 'prepend';
}
pos[operation](importText);
}

function insertInlinedImports($, importText) {
var pos = $('body').last();
var operation = 'prepend';
if (!pos.length) {
pos = $.root();
}
pos[operation](importText);
return pos;
}

// arguments are (index, node), where index is unnecessary
Expand All @@ -167,21 +138,20 @@ function removeCommentsAndWhitespace($) {
$.root().contents().filter(isCommentOrEmptyTextNode).remove();
$('head').contents().filter(isCommentOrEmptyTextNode).remove();
$('body').contents().filter(isCommentOrEmptyTextNode).remove();
$(JS).each(function() {
$(constants.JS).each(function() {
if (!this.attr('src')) {
var content = this.html();
var ast = uglify.parse(content);
this.replaceWith('<script>' + ast.print_to_string() + '</script>');
}
});
$(CSS).each(function() {
$(constants.CSS).each(function() {
setTextContent(this, new cleancss().minify(this.text()));
});
}

function handleMainDocument() {
// reset shared buffers
import_buffer = [];
imports_before_polymer = [];
read = {};
var $ = readDocument(options.input);
Expand All @@ -190,8 +160,7 @@ function handleMainDocument() {
if (options.inline) {
inlineSheets($, dir, options.outputDir);
}
resolvePaths($, dir, options.outputDir);
var output = import_buffer.join(EOL);
pathresolver.resolvePaths($, dir, options.outputDir);

// strip scripts into a separate file
if (options.csp) {
Expand All @@ -218,12 +187,7 @@ function handleMainDocument() {
};

// CSPify main page
$(JS).each(fn).remove();

// CSPify imports
var tempoutput = cheerio.load(output);
tempoutput(JS).each(fn).remove();
output = tempoutput.html();
$(constants.JS).each(fn).remove();

// join scripts with ';' to prevent breakages due to EOF semicolon insertion
var script_name = path.basename(options.output, '.html') + '.js';
Expand All @@ -232,9 +196,7 @@ function handleMainDocument() {
findScriptLocation($).append(EOL + scripts_after_polymer.join(EOL) + EOL);
}

imports_before_polymer = deduplicateImports(imports_before_polymer);
insertImport($, imports_before_polymer.join(EOL) + EOL);
insertInlinedImports($, output);
deduplicateImports($);
if (!options.csp && options.inline) {
inlineScripts($, options.outputDir);
}
Expand All @@ -245,20 +207,20 @@ function handleMainDocument() {
fs.writeFileSync(options.output, outhtml, 'utf8');
}

function deduplicateImports(importArray) {
function deduplicateImports($) {
var imports = {};
return importArray.filter(function(im) {
var href = im.attr('href');
$(constants.IMPORTS).each(function() {
var href = this.attr('href');
// TODO(dfreedm): allow a user defined base url?
var abs = url.resolve('http://', href);
if (!imports[abs]) {
imports[abs] = true;
return true;
} else if(options.verbose) {
console.log('Import Dependency deduplicated');
} else {
if(options.verbose) {
console.log('Import Dependency deduplicated');
}
this.remove();
}
}).map(function(im) {
return cheerio.html(im);
});
}

Expand Down

0 comments on commit 2f85cdf

Please sign in to comment.