Grunt.js output and write contents of folder to file? - node.js

Goal:
Dynamically include /static/js/**/*.js and /static/css/**/*.css files too <head>
Method:
I am using client side templating partials, so in this example, I would like to write filepaths of everything in:
/static/js/**/*.js too /templates/head.js.dust
/static/css/**/*.css too /templates/head.css.dust
File paths are not enough of course. I need a way to preprocess the the output so that every "file" is wrapped by appropriate tags like:
<!-- /templates/head.js.dust -->
<script src="/static/js/assests/jquery.js"></script>
<script src="/static/js/assests/jquery_ui.js"></script>
<script src="/static/js/app.js"></script>
...
<!-- /templates/head.css.dust -->
<link src="/static/css/assests/jquery_ui.css"/>
<link src="/static/css/app.css"/>
...
Question:
Is there a grunt module out there that already does something like this?
Bonus Points: How do I even get started building something like this if it does not?

You can do so in a fairly easy way:
grunt.registerMultiTask("assetAppend", "Append JS/CSS assets to a file", function() {
var paths = grunt.file.expand( this.data.paths ),
out = this.data.output,
contents = "";
paths.forEach(function( path ) {
if ( /\.js$/i.test( path ) ) {
contents += '<script src="' + path + '"></script>';
} else if ( /\.css$/i.test( path )) {
contents += '<link rel="stylesheet" type="text/css" href=' + path + ' />';
}
});
grunt.file.write( out, contents );
});
grunt.initConfig({
assetAppend: {
js: {
paths: ["static/js/**/*.js"],
output: "head.js.dust"
},
css: {
paths: ["static/css/**/*.css"],
output: "head.css.dust"
}
}
});
This example is now part of my plugin grunt-contrib-assetpush

Related

How to include corresponding css and javascript of the page in assemble layout

I am using assemble to generate from html files with a common layout files. I want to include the corresponding css and javascript file with different pages. So that, for index.html, only index.css and index.js are included, and for about-us.html, only about-us.css and about-us.js are included.
Here's my respository on github https://github.com/xchitox/assemble-gulp-test
If you are already using gulp then use gulp-inject to inject the html files with their respective dependencies based on injection tags.
function injectStartingTag(filepath, starttag) {
var inject = require('gulp-inject');
// Injects the source using relative paths
return inject(gulp.src(filepath, {
read: false
}), {
relative: true,
starttag: '<!-- ' + starttag + ' -->'
});
}
In your index.html:
<!--inject:index:css-->
<!--endinject-->
<!--inject:index:js-->
<!--endinject-->
In your about-us.html:
<!--inject:about-us:css-->
<!--endinject-->
<!--inject:about-us:js-->
<!--endinject-->
Call the function above in any gulp task. You can filter with gulp-if and call the function with the specific starttag. i.e.:
gulp.task('Inject', function(){
var _if = require('gulp-if');
var all_your_files = "**/*.*"; // obvously only add html, js, and css files
return gulp
.src(all_your_files)
.pipe(_if('index.html', injectStartingTag('index.css', 'inject:index:css')))
.pipe(_if('about-us.html', injectStartingTag('about-us.css', 'inject:about-us:css')))
...
...
// you get the idea
});
You can use a helper to generate the link to the assets based on the filename of the current view:
app.helper('filename', function() {
// this.view is the current view being rendered
return this.view.stem; // just get the basename without extension
});
Now you can use this to add the assets path in your layout:
<link rel="stylesheet" href="/assets/css/{{filename}}.css">
<script src="/assets/js/{{filename}}.js"></script>

Gulp Usemin not doing anything

I have multiple apps in one project, so I have this task:
gulp.task('usemin', function() {
return gulp.src('/app1/index.html')
.pipe(usemin({
js: [ uglify(), rev() ]
}))
.pipe(gulp.dest('app1/build/'));
});
And this is the index.html:
<!-- build:js app.js -->
<script src="bower_components/jquery/dist/jquery.min.js"></script>
<script src="bower_components/angular/angular.min.js"></script>
<script src="bower_components/d3/d3.min.js"></script>
.
.
.
<!-- endbuild -->
The task runs without issues but generates no file!
You're using an absolute path here:
return gulp.src('/app1/index.html')
You probably want to use a project relative path:
return gulp.src('app1/index.html')
Have you tried appending to relative path on gulp.src?
return gulp.src('./app1/index.html')
Read the Doc for more details.

RequireJS module that extends another module

I'm using a project that has 2 different files wrapped in AMD which one extends the other, project is jsondiffpatch.
The project has 2 files (build/bundle.js and build/formatters.js) each export jsondiffpatch. When I include them in my file like:
define(['jsondiffpatch',
'jsondiffpatch-formatters'], function (jsondiffpatch) {
});
the formatters extensions are not present. If I change the main config make jsondiffpath depend on the formatters like:
shim: {
'jsondiffpatch': {
deps: ['jsondiffpatch-formatters']
}
}
I still don't get the formatters. This is a pretty common practice, but haven't seen to overcome it; i know its something simple, what am i missing?
This should work:
shim: {
'jsondiffpatch-formatters': {
deps: ['jsondiffpatch'],
exports: 'jsondiffpatch.formatters'
},
'jsondiffpatch': {
exports: 'jsondiffpatch'
}
}
When you load jsondiffpatch with an AMD loader like RequireJS the formatters are a different module. In other words, it works slightly differently from when you load jsondiffpatch without an AMD-loader. Here's a complete example:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/xhtml; charset=utf-8"/>
<link rel="stylesheet" href="bower_components/jsondiffpatch/src/formatters/html.css" type="text/css" />
<link rel="stylesheet" href="bower_components/jsondiffpatch/src/formatters/annotated.css" type="text/css" />
</head>
<script type="text/javascript" src="bower_components/requirejs/require.js"></script>
</head>
<body>
<div id="visual"></div>
<hr/>
<div id="annotated"></div>
<script>
require.config({
baseUrl: ".",
paths: {
jsondiffpatch: "bower_components/jsondiffpatch/build/bundle",
"jsondiffpatch.formatters": "bower_components/jsondiffpatch/build/formatters"
},
enforceDefine: true
});
require(["jsondiffpatch", "jsondiffpatch.formatters"],
function (jsdp, formatters) {
//
// Code here adapted from jsondiffpatch's examples:
// https://github.com/benjamine/jsondiffpatch
//
var left = { a: 3, b: 4 };
var right = { a: 5, c: 9 };
var delta = jsdp.diff(left, right);
document.getElementById('visual').innerHTML =
formatters.html.format(delta, left);
document.getElementById('annotated').innerHTML =
formatters.annotated.format(delta, left);
});
</script>
</body>
</html>
The only thing you need other than this HTML above is to install RequireJS and jsondiffpatch with Bower.

Phantom JS for Node, use print stylesheet?

I'm using Node JS to generate PDFs.
Is there a way to get Phantom JS to screenshot pages using the print stylesheet instead of the screen one?
At the moment I have the print stylesheet all set up and good to go, but Phantom JS is being recognised as a screen device instead of print.
Here's a snipped of code so you can see what I'm doing.
Thanks in advance!
var date = Date.now();
var images = [];
capture(results.length, 0);
function capture(pagesLength, pageId) {
if (pagesLength <= 0) {
stopCapture();
}
else {
snapshot(pagesLength, pageId);
}
}
function snapshot(pagesLength, pageId) {
phantom.create(function (ph) {
ph.createPage(function (page) {
page.open("http://127.0.0.1:3000/#/pages/" + results[pageId]["_id"], function (status) {
var fileName = results[pageId]["_id"] + ".jpeg";
images.push(fileName);
page.render("public/temp/" + date + "/" + fileName, {format: 'jpeg', quality: '100'}, function () {
pagesLength--;
pageId++;
ph.exit();
if (pagesLength <= 0) {
mergeImages();
} else {
snapshot(pagesLength, pageId);
}
});
});
});
});
}
You cannot change it, because it is hard coded in QtWebkit. There are two approaches that you can try.
First:
If your print stylesheet is separate from the screen styles:
<link rel="stylesheet" href="style.css" type="text/css" media="screen" />
<link rel="stylesheet" href="printstyle.css" type="text/css" media="print" />
then you can remove the screen style and change the media type of the print stylesheet inside evaluate:
Array.prototype.forEach.call(document.querySelectorAll("link:not([media='print']), style"), function(el){
el.parentNode.removeChild(el);
});
Array.prototype.forEach.call(document.querySelectorAll("link[media='print']"), function(el){
el.media = "screen";
});
(^ untested)
This should yield:
<link rel="stylesheet" href="printstyle.css" type="text/css" media="screen" />
and you will probably have to wait a little until phantom applies the styles.
Second:
Compile your own phantomjs version with the changed media type.
You can currently find it under line 125 of src / qt / src / 3rdparty / webkit / Source / WebCore / page / FrameView.cpp:
FrameView::FrameView(Frame* frame)
...
, m_mediaType("screen")
...
(^ also untested)
Change screen to print, compile it and have fun.

requireJS “Uncaught TypeError: undefined is not a function”

I have been using requirejs on couple projects, and today is the first time I got this problem and not sure how to fix it. I am using requirejs and tyepscript, I can't really tell what's wrong here. Can someone take a look?
Here is my main.ts:
///<reference path="../lib/require/requirejs.d.ts"/>
///<reference path="TestClass.ts"/>
require.config(
{
baseUrl: 'js',
paths: {
puremvc: 'lib/puremvc/puremvc_standard_1.0_min'
}
}
);
require(
[
'puremvc',
'sim/TestClass'
],
function (TestClass ) {
var test = new TestClass();
test.logMsg("WHO AM I");
}
);
and this is my TestClass.ts
class TestClass{
constructor(){
console.log ("TestClass constructor")
}
public logMsg(msg:string){
console.log ("TestClass.log(): " + msg);
}
}
export = TestClass;
and my sim.html looks like this one
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Simulation Tester</title>
<script src="js/lib/puremvc/puremvc_standard_1.0_min.js"></script>
<script data-main="js/sim/main.js" src="js/lib/require/require.js" ></script>
</head>
<body >
</body>
</html>
And this is my folder structure:
- root
- sim.html
- js
- lib
- require (containt requirejs)
- sim
- main.ts
- TestClass.ts
Any idea?
Are you loading puremvc through the script tag, or through require.js? I don't think you want to do both.
Over here:
require(
[
'puremvc',
'sim/TestClass'
],
function (TestClass ) {
var test = new TestClass();
test.logMsg("WHO AM I");
}
);
The callback function gets the modules in the same order you listed them. So the 'TestClass' parameter is being supplied the value from the 'puremvc' module. You probably want function(puremvc, TestClass) instead here.

Resources