I would like to have all javascript, css and images that are sent to the browser to be concatenated, minified and have a md5 cache busting filename. I've been able to achieve this with packages like connect-assets and others.
However I have not been able to add the md5'ed image filename into the css before it is processed.
I am using Less css templates.
Any pointers to packages that could help me would be great.
eg
image.png is converted to image-455454545.png
css references background-image: url(image.png) -> should change to image-455454545.png
As far as I know, Less doesn't have the ability to utilize user-defined functions. Stylus, however, does. So if you're willing to hop onto an alternate CSS preprocessor, then there is great fun to be had! (Stylus is really very simliar to Less, and it shouldn't take much to switch to it. Plus connect-assets already supports Stylus, so it should plug into your environment easily.)
server.js
var fs = require('fs');
var stylus = require('stylus');
stylus(fs.readFileSync("styles.styl", 'utf8')) //load stylus file
.define("versionedFile", versionedFile) //add our custom function to the stylus env
.render(function(err, css){ //render!
if (err) {
throw err;
}
fs.writeFileSync("styles.css", css); //write the compiled css to a .css file
});
//our custom function
function versionedFile(filename) {
... lookup versioned file of filename ...
return "versionedFilename.png"
}
styles.styl
.image-block {
background-image: url(versionedFile('unversionedFilename.png')); //this is how we use our custom function
}
Which will compile into:
styles.css
.image-block {
background-image: url("versionedFilename.png"); //hooray!
}
Related
I have tried using npm-concat but it concats all files from folder. but my requirement is something like this-
I have a single file called "header.html","footer.html" and i have folder called view in which i have raw text of html.
tpl
---- header.html
---- footer.html
view
---- view1.html
---- view2.html
Now i want to prepend header.html to all files under view and I want to append footer.html to all files under view folder. How we can achieve this ?
I think you would do better to consider using a template engine such as handlebars to accomplish this task, rather than concatenating files. But I'll try to answer your question since you asked.
I don't know of any plugin that can do this in an optimal way. However, I have written a plugin called gulp-transform that will let you do this fairly easily.
const gulp = require('gulp');
const transform = require('gulp-transform');
const readFileSync = require('fs').readFileSync;
const HEADER = readFileSync('tpl/header.html');
const FOOTER = readFileSync('tpl/footer.html');
gulp.task('html', () => {
return gulp.src('view/*.html')
.pipe(transform(contents => Buffer.concat([HEADER, contents, FOOTER])))
.pipe(gulp.dest('dist'));
});
This is a bit ugly, and in fact I would only recommend using this plugin for a quick fix when there is no better option. A better solution would be to define a custom plugin that does exactly this. If you think it would be helpful, I can show you how you might do that. This is a bit more involved though. I really think your best option is to use a template engine.
Framework: node.js / express.js / Jade
Question: in production env, when a jade file is rendered by express, jade cache's it so future renders are faster.
When I start node.js app, how can I pre-compile (or) pre-render (like warmup) all the jade files so its already in cache when requests start to come in...
I can use a folder recursion, I just need to know how to pre-compile (or) pre-render.
Is this possible?
Jade has template pre-compiling and caching built in.
http://jade-lang.com/api/
Simply specify cache: true option to jade.compileFile, and iterate through all of your template files.
var options = {cache: true};
// iterate/recurse over your jade template files and compile them
jade.compileFile('./templates/foo.jade', options);
// Jade will load the compiled templates from cache (the file path is the key)
jade.renderFile('./templates/foo.jade');
If you're not using any parameters, you can compile jade templates directly to HTML with grunt or gulp and make it watch for file modifications
Try it from the command-line:
jade view/map-beacons.jade -D
If you do need to use parameters I would use something like in Andrew Lavers answer.
compileFile returns a function which you can use to pass in parameters i.e. fn({ myJsVar: 'someValue' })
There is also a client option in the command-line but I didn't find any use for it :
jade view/map-beacons.jade -cD
i do this solution, this code outside http.createServer function
let cache_index=jade.renderFile('index.jade');
and when return view
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');
res.end(cache_index);
when use this solution server return index to 1ms
but without solution server return index between 150ms to 400ms
result:
Picture 1 with cache
Picture 2 without cache
I'm developing a web application and I'm using about 20 bower_components (bootstrap, jquery, some jquery plugin like cookie and serializejson, mousewheel, mustache, underscore etc).
All these plugins are quite small (except for bootstrap and jquery), but are loaded with a dedicated "" tag.
This makes my page asks for 20 micro javascript files and this makes the page load slowly.
I'd like to bundle all these scripts together and load the bundle...
I've tried with gulp-bower-src but it just help me to uglify them and move them in a "lib" folder... Can't find a way to compress them all together.
This is my gulp task atm
var filter = gulpFilter("**/*.js", "!**/*.min.js");
gulp.task("default", function () {
bowerSrc()
.pipe(filter)
.pipe(uglify())
.pipe(filter.restore())
.pipe(gulp.dest(__dirname + "/public/lib"));
});
How can I do?
You can use gulp-concat to bundle all these micro files into one asset.
var concat = require('gulp-concat');
var filter = gulpFilter("**/*.js", "!**/*.min.js");
gulp.task("default", function () {
bowerSrc()
.pipe(filter)
.pipe(uglify())
.pipe(concat('bundle.js'))
.pipe(filter.restore())
.pipe(gulp.dest(__dirname + "/public/lib"));
});
This will concat all filtered and uglified files as bundle.js into directory public/lib. Keep in mind that when concatenating these files the order of files matters. I guess that gulp-bower-src does not order scripts according to a dependency graph (I found nothing in the documentation) so it might require you to select the bower files by hand in the right order.
A manual ordering/selecting of the bower components could be done by substituting the bowerSrc() by a line somehow like this
gulp.src(['./bower_components/jquery/jquery.js', './bower_components/jquery-ui/jquery-ui.js', './bower_components/jquery-swift-color-picker/color.js']);
This may seem a little clumsy and it is but order matters.
Background / Need
I am working with a group on a web application using Node.JS and Express. We need to be able to generate reports which can be printed as hard copies and also hard copy forms. Preferably we'd like to dynamically generate PDFs on the server for both reports and hand written forms. We're currently using EJS templates on the server.
Options
I was thinking that it would be convenient to be able to use templates to be able to build forms/reports and generate a PDF from the resulting HTML, however my options to do this appear limited as far as I can find. I have looked at two different possible solutions:
PhantomJS -- (npm node-phantom module)
PDFKit
EDIT: I found another Node.JS module which is able to generate PDFs from HTML called node-wkhtml which relies on wkhtmltopdf. I am now comparing using node-phantom and node-wkhtml. I have been able to generate PDFs on a Node server with both of these and they both appear to be capable of doing what I need.
I have seen some examples of using PhantomJS to render PDF documents from websites, but all of the examples I have seen use a URL and do not feed it a string of HTML. I am not sure if I could make this work with templates in order to dynamically generate PDF reports.
When a request for a report comes in I was hoping to generate HTML from an EJS template, and use that to generate a PDF. Is there anyway for me to use Phantom to dynamically create a page completely on the server without making a request?
My other option is to use PDFkit which allows dynamic generation of PDFs, but it is a canvas-like API and doesn't really support any notion of templates as far as I can tell.
The Question
Does anyone know if I can use PhantomJS with Node to dynamically generate PDFs from HTML generated from a template? Or does anyone know any other solutions I can use to generate and serve printable reports/forms from my Node/Express back-end.
EJS seems to run fine in PhantomJS (after installing the path module). To load a page in PhantomJS given a string of HTML, do page.content = '<html><head>...';.
npm install ejs and npm install path, then:
var ejs = require('ejs'),
page = require('webpage').create();
var html = ejs.render('<h1><%= title %></h1>', {
title: 'wow'
});
page.content = html;
page.render('test.pdf');
phantom.exit();
(Run this script with phantomjs, not node.)
I am going to post an answer for anyone trying to do something similar with node-phantom. Because node-phantom controls the local installation of PhantomJS, it must use asynchronous methods for everything even when the corresponding PhantomJS operation is synchronous. When setting the content for a page to be rendered in PhantomJS you can simply do:
page.content = '<h1>Some Markup</h1>';
page.render('page.pdf');
However, using the node-phantom module within node you must use the page.set method. This is the code I used below.
'use strict';
var phantom = require('node-phantom');
var html = '<!DOCTYPE html><html><head><title>My Webpage</title></head>' +
'<body><h1>My Webpage</h1><p>This is my webpage. I hope you like it' +
'!</body></html>';
phantom.create(function (error, ph) {
ph.createPage(function (error, page) {
page.set('content', html, function (error) {
if (error) {
console.log('Error setting content: %s', error);
} else {
page.render('page.pdf', function (error) {
if (error) console.log('Error rendering PDF: %s', error);
});
}
ph.exit();
});
});
});
A really easy solution to this problem is the node-webshot module - you can put raw html directly in as an argument and it prints the pdf directly.
I am learning node and express from the simplest and when rendering views using res.render('view',{data:data}) is it only a template engine like jade that fits in view. can I not use a normal html?
You can, but this is a problem I ran into when I was learning Node. If you do not want to use a templating engine, you can still have Node just spit out the contents of your HTML file in a static way. For example (VERY BASIC EXAMLE):
var base = '/path/to/your/public_html',
fs = require('fs'),
http = require('http'),
sys = requrie('sys');
http.createServer(function (req,res) {
path = base + req.url;
console.log(path);
path.exists(path, function(exists) {
if(!exists) {
res.writeHead(404);
res.write('Bad request: 404\n');
res.end();
} else {
res.setHeader('Content-Type','text/html');
res.statusCode = 200;
var file = fs.createReadStream(path);
file.on("open",function() {
file.pipe(res);
});
file.on("error",function(err) {
console.log(err);
});
}
});
}).listen(80);
console.log('server on tcp/80');
The great thing about Node is that it forces you to separate templates from logic (to a certain level, you can squeeze a lot of logic into template anyway).
I didn't like Jade and used EJS until it turned out that client-side EJS is different from server-side and you cannot really re-use templates in the browser (as you would definitely want at some point, when you start rendering pages in the browser). You can re-use simple EJS templates but you cannot re-use templates with partials (as most of your templates will be).
After a lot of searching and trial-and-error I ended up using doT templates that are very fast (the fastest there is, actually), light-weight (only 140 lines of JavaScript), can be easily integrated in Express (by following the pattern of consolidate - you can't use consolidate directly with doT yet), can be used in the browser (the function to load partials will have to be different, but it is easy again).
doT seems to have features that I haven't seen in other templating engines, has a very elegant syntax that is the closest to handlebars (my favourite) but still allows normal JavaScript inside (that's why I chose EJS in the first place).