Minify Scripts/CSS in production mode with node.js
Asked Answered
A

5

12

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?

Antiphonary answered 12/2, 2013 at 20:35 Comment(0)
T
21

You 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.

Tessellation answered 12/2, 2013 at 20:47 Comment(0)
H
5

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.

Haley answered 12/2, 2013 at 20:47 Comment(3)
@Pascal, quick question - are you suggesting that the minified js file should be present in that folder? If that is the case you will have to build it on your system every time there is a change and then use git etc to push it to production which does not seem like a very good idea.Pernicious
no, the minified file should not typically be stored in git. Either the server itself, or something like grunt can be used on the production server to generate the minified version.Haley
To start in production mode use following NODE_ENV=production node app.jsWakeless
A
1

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.

Antiphonary answered 17/6, 2013 at 6:29 Comment(0)
S
1

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

Site answered 1/3, 2014 at 16:8 Comment(0)
J
0

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.

Jackscrew answered 18/6, 2015 at 15:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.