Skip to content

Commit

Permalink
replaceRequireScript fix for conditional html in head and for django …
Browse files Browse the repository at this point in the history
…template tags

If html have some conditional html or template tags in start of the
file, they get messed up because of template parsing.
Presently we don’t parse the html, we use regex to find script tag and
then replace it.
  • Loading branch information
nitinhayaran committed Feb 28, 2014
1 parent e869e59 commit 78a3ec5
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 30 deletions.
56 changes: 29 additions & 27 deletions lib/replace.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ exports.init = function(grunt) {

// External libs.
var Q = require('q');
var jsdom = require('jsdom');
var fs = require('fs');
var rBody = /<body>/;
var cheerio = require('cheerio');

return function(config) {
var deferred = Q.defer();
Expand All @@ -29,36 +27,40 @@ exports.init = function(grunt) {
var filesEvaluated = 0;

// iterate over found html files
files.forEach(function(file) {
var fileContents = fs.readFileSync(file, 'utf-8');
var hasBody = rBody.test(fileContents);
files.forEach(function (file) {
// load file contents
var contents = String(grunt.file.read(file, 'utf-8'));
// reference to script regex https://github.com/jquery/jquery/blob/1.7.2/src/ajax.js#L14
var script_re = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
matches = contents.match(script_re);

jsdom.env(fileContents, {
FetchExternalResources: false,
ProcessExternalResources: false
}, function(err, window) {
var scripts = window.document.querySelectorAll('script[data-main]');

[].slice.call(scripts).forEach(function(script) {
var insertScript = (file.modulePath || script.getAttribute('data-main'));
script.src = insertScript + '.js';
script.removeAttribute('data-main');
});

var html = hasBody ? window.document.innerHTML : window.document.body.innerHTML;
grunt.log.writeln('Updating requirejs script tag for file', file);
grunt.file.write(file, html);

// only resolve after all files have been evaluated
filesEvaluated++;
if (filesEvaluated >= files.length) {
deferred.resolve(config);
[].slice.call(matches).forEach(function(match, i){
var $ = cheerio.load(match),
elm = $('script');
if (elm.attr('data-main')){
var insertScript = (file.modulePath || elm.attr('data-main'));
elm.attr('src', insertScript + '.js');
elm.removeAttr('data-main');
// replace i'th occurrence in content
var j = 0;
contents = contents.replace(script_re, function(match){
j++;
return (j-1 === i) ? $.html() : match;
});
}
});

grunt.log.writeln('Updating requirejs script tag for file', file);
grunt.file.write(file, contents);
// only resolve after all files have been evaluated
filesEvaluated++;
if (filesEvaluated >= files.length) {
deferred.resolve(config);
}

});
});

return deferred.promise;
};
};

5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,10 @@
},
"dependencies": {
"requirejs": "2.1.x",
"cheerio": "0.10.x",
"cheerio": "0.13.x",
"almond": "0.2.x",
"gzip-js": "0.3.x",
"q": "0.8.x",
"jsdom": "0.8.x"
"q": "0.8.x"
},
"devDependencies": {
"grunt": "~0.4.0",
Expand Down
16 changes: 16 additions & 0 deletions test/fixtures/replaceConditionalComments.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!doctype html>
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<title>Testing</title>
<!-- build:js scripts/vendor/modernizr.js -->
<script src="bower_components/modernizr/modernizr.js"></script>
<!-- endbuild -->
</head>
<body>
<script src="js/require.js" data-main="js/main"></script>
</body>
</html>
17 changes: 17 additions & 0 deletions test/fixtures/replaceInDjangoTemplates.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{% load static %}
<!doctype html>
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<title>Testing</title>
<!-- build:js scripts/vendor/modernizr.js -->
<script src="bower_components/modernizr/modernizr.js"></script>
<!-- endbuild -->
</head>
<body>
<script src="js/require.js" data-main="js/main"></script>
</body>
</html>
42 changes: 42 additions & 0 deletions test/require_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,48 @@ exports['require'] = {
result = grunt.file.read('node_modules/almond/almond.js');
test.ok(result.length > 0, 'original almond.js should still be there');
test.done();
},

'requirejs script tag should be replaced without messing with conditional html': function(test) {
'use strict';
test.expect(2);
var config = {
replaceRequireScript: [{
files: ['tmp/replaceConditionalComments.html'],
module: 'main'
}],
modules: [{name: 'main'}],
almond: true
};

grunt.file.copy('test/fixtures/replaceConditionalComments.html', 'tmp/replaceConditionalComments.html');
replaceAlmondInHtmlFiles(config).then(function() {
var replacedFileContents = grunt.file.read(config.replaceRequireScript[0].files[0]);
test.ok(replacedFileContents.search('<script src="js/main.js"></script>') > -1, 'should replace script tag ´src´ contents');
test.ok(replacedFileContents.search('<!--\\[if lt IE 7\\]>') > -1, 'should not mess with conditional html');
test.done();
});
},

'requirejs script tag should be replaced without altering django template tags': function(test) {
'use strict';
test.expect(2);
var config = {
replaceRequireScript: [{
files: ['tmp/replaceInDjangoTemplates.html'],
module: 'main'
}],
modules: [{name: 'main'}],
almond: true
};

grunt.file.copy('test/fixtures/replaceInDjangoTemplates.html', 'tmp/replaceInDjangoTemplates.html');
replaceAlmondInHtmlFiles(config).then(function() {
var replacedFileContents = grunt.file.read(config.replaceRequireScript[0].files[0]);
test.ok(replacedFileContents.search('<script src="js/main.js"></script>') > -1, 'should replace script tag ´src´ contents');
test.ok(replacedFileContents.search('{% load static %}') > -1, 'should not mess with conditional html');
test.done();
});
}

};

0 comments on commit 78a3ec5

Please sign in to comment.