I have a web app that runs in node. All the (client) Javascript/CSS files are not minified at the moment to make it easier to debug.
When I am going into production, I would like to minify these scripts. It would be nice to have something like:
node app.js -production
How do I serve the minified version of my scripts without changing the script tags in my html files? There should be something like: if I am in production, use these 2 minified(combined) scripts, else use all my unminified scripts..
Is this possible? Maybe I am thinking too complicated?
I have a web app that runs in node. All the (client) Javascript/CSS files are not minified at the moment to make it easier to debug.
When I am going into production, I would like to minify these scripts. It would be nice to have something like:
node app.js -production
How do I serve the minified version of my scripts without changing the script tags in my html files? There should be something like: if I am in production, use these 2 minified(combined) scripts, else use all my unminified scripts..
Is this possible? Maybe I am thinking too complicated?
Share Improve this question edited Feb 12, 2013 at 20:45 Mechlar 4,97414 gold badges60 silver badges83 bronze badges asked Feb 12, 2013 at 20:35 ChristianChristian 7,42912 gold badges57 silver badges90 bronze badges5 Answers
Reset to default 21You might be interested in Piler. It's a Node.js module that delivers all the JavaScript (and CSS) files you specify as usual when in debug mode, but concatenated and minified when in production mode.
As a special feature, you can force CSS updates via Socket.io in real-time to appear in your browser (called "CSS Live Updated" in Piler), which is quite awesome :-).
The trick is that inside your template you only have placeholders for the script
and link
elements, and Piler renders these elements at runtime - as single elements in debug mode, and as a dynamically generated single element in production mode.
This way you can forget about creating concatenated and minified versions of your assets manually or using a build tool, it's just there at runtime, but you always have the separated, full versions when developing and debugging.
you could use 2 separate locations for your static files
Here's some express code:
if (process.env.MODE === "production") {
app.use(express['static'](__dirname + '/min'));
} else {
app.use(express['static'](__dirname + '/normal'));
}
and start node with
MODE=production node app.js
Furthermore, if you don't want to duplicate all your files, you could take advantage of the fact that express static router stops at the first file, and do something like this instead:
if (process.env.MODE === "production") {
app.use(express['static'](__dirname + '/min')); // if minized version exists, serves it
}
app.use(express['static'](__dirname + '/normal')); // fallback to regular files
Using the same name for minimized or not is going to cause problem with browser caching, though.
I want to share my final solution with you guys.
I use JSHTML for Express (enter link description here)
In my main node file I use a special route:
app.get('/**:type(html)', function (req, res, next) {
var renderingUrl = req.url.substring(1, req.url.lastIndexOf("."));
//TODO: Find a better solution
try{
var assetUrl = req.url.substring(req.url.lastIndexOf("/") + 1, req.url.lastIndexOf("."));
var assets = config.getResourceBundle(assetUrl);
assets.production = config.getEnviroment() === "production";
res.locals(assets);
res.render(renderingUrl);
}catch(e){
res.redirect("/");
}
});
As you can see, I get my assets from config.getResourceBundle. This is a simply function:
exports.getResourceBundle = function(identifier){
switch(enviroment){
case "development":
return devConfig.getResourceBundle(identifier);
case "production":
return prodConfig.getResourceBundle(identifier);
default:
return devConfig.getResourceBundle(identifier);
}
}
And finally an example for an asset file collection is here:
exports.getResourceBundle = function (identifier) {
return resourceBundle[identifier];
};
resourceBundle = {
index:{
cssFiles:[
"resources/dev/css/login.css",
"resources/dev/css/logonDlg.css",
"resources/dev/css/footer.css"
],
jsFiles:[
"resources/dev/js/lib/jquery/jquery.183.js",
"resources/dev/js/utilities.js",
"resources/dev/js/lib/crypto.3.1.2.js"
]
},
register:{
cssFiles:[
"resources/dev/css/login.css",
"resources/dev/css/modalDialog.css",
"resources/dev/css/footer.css"
],
jsFiles:[
"resources/dev/js/lib/jquery/jquery.183.js",
"resources/dev/js/utilities.js",
"resources/dev/js/lib/crypto.3.1.2.js",
"resources/dev/js/lib/jquery.simplemodal.js",
"resources/dev/js/xfiles.register.js"
]
}
(...)
I have 2 folders. dev / prod. grunt will copy the minified files into prod/.. and deletes the files from dev/... And if the NODE_ENV variable is set to production, I will ship the minified versions of my scripts/css. I think this is the most elegant solution at the moment.
There are build tool plugins for you, may help you gracefully solve this problem:
For Gulp: https://www.npmjs.org/package/gulp-useref/
For Grunt: https://github.com/pajtai/grunt-useref
Another Node.js module which could be relevant is connect-cachify.
It doesn't seem to do the actual minification for you, but it does let you serve the minified version in production, or all the original scripts in development, without changing the templates (thanks to cachify_js
and cachify_css
).
Seems it's not as feature-rich as Piler, but probably a bit simpler, and should meet all the requirements mentioned in the question.