Reduce HTTP requests bundling bower_components together? - node.js

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.

Related

How to compile ReactJS for use on server with command line arguments?

I've decided to try out ReactJS. Along with that, I've decided to use Gulp for compiling .jsx to .js, also for the first time.
I can compile it no problem for the client use with browserify. Here's my gulp task:
browserify("./scripts/main.jsx")
.transform(
babelify.configure({
presets: ["react"]
}))
.bundle()
.pipe(source('bundle.js'))
.pipe(gulp.dest('./scripts/'));
But since I use PHP to generate data, I need to get those data to node. If I use browserify, it will prevent me from using process.argv in node. I can save data to file and read that file in node, so I wouldn't need to pass the whole state to node, but I still need to pass the identifying arguments, so the node knows which file to load.
What should I use instead of browserify?
If you need to compile a React module to es5 for use on the server, use Babel itself.
A module that may help with reading and writing files is this one: https://nodejs.org/api/fs.html
Have you considered posting and getting from a database?
Here's how I solved it:
I have learnt that you can create standalone bundles with browserify, so I've compiled all the server code I need (components + rendering) as a standalone bundle. Then I have created small node script which is responsible only for reading arguments, loading data and sending it to the rendering code.
I'm not sure if this is a proper way how it should be done but it works.
Here's code for the "setup" script:
var fs = require('fs');
var Server = require('./server.js');
if (process.argv[2]) {
region = process.argv[2].toLowerCase().replace(/[^a-z0-9]/, '');
if (region != '') {
var data = JSON.parse(fs.readFileSync(__dirname + '/../tmp/' + region + '.json', 'utf8'));
console.log(Server.render(data.deal, data.region));
}
}
This way I only need to deploy two files and I still can easily compile jsx to js.

Webpack Aliases in Node JS Server code

I'm building an isomorphic React/React-Router/Redux/Webpack application and I'm attempting to implement server side rendering.
My directory looks like:
/client
/actions
/components
/containers
/server
/server.js
In my webpack config, I have aliases set up for all the folders inside client:
var path_base = path.resolve(__dirname, '..');
const resolve = path.resolve;
const base = function() {
var args = [path_base];
args.push.apply(args, arguments);
return resolve.apply(resolve,args);
};
const resolve_alias = base.bind(null, 'src/client');
const aliases = [
'actions',
'components',
'constants',
'containers',
'middleware',
'reducers',
'routes',
'store',
'styles',
'utils',
'validation'
];
so that inside the code that gets bundled by webpack, I can do:
import { Widget } from 'components';
and that import gets resolved by webpack.
Now in my server code, in order to do the rendering, I have to import some of my client files, like routes/index.js. The problem I'm running into when I import my routes file, it's using a webpack alias to another file, say components or containers so naturally, the node js require system can't resolve it.
How do I fix something like that? I looked at this question and it talks about essentially setting up the same aliases that exist in webpack with mock-require. But then the issue becomes that my routes file imports all my components which then all import things like stylesheets, images, etc. Should I then be using something like webpack-isomorphic-tools?
The guides I've been looking at (this for example) are all great at showing how server side rendering is accomplished but none of them really talk about how to resolve all the requires and whatnot.
After battling with this issue for 2 days I settled on babel-plugin-webpack-alias.
What you need to do to resolve paths with that is:
$ npm install --save-dev babel-plugin-webpack-alias
Add the plugin to your .babelrc
Add the aliases to your webpack.config (make sure you use path.join())
Refer to this post if you have problems loading styles
The other option I tried was universal-webpack but I found it to be a bit verbose. If you want to see roughly how the whole server-side loading works, you can check out this video.
If you really want them, run your server side code through babel and use this plugin: https://www.npmjs.com/package/babel-plugin-module-alias which will let you do the same thing as webpack.
Edit: This one works a lot better: https://github.com/jagrem/babel-resolve-relative-module it allows multiple paths
Try to use NODE_PATH. Node will always look for a module in this path during require calls. It allows to short cut your relative paths as you want.
// turn this
import {Widget} from '../../components';
// into this
import {Widget} from 'components';
See Node.js docs for more information.
P.S. this thing is very sensitive, so use it carefully. Now your code tightly depends from the environment and may break somewhere.
If you use webpack-isomorphic-tools then it'll take your webpack config into account for your server side which will make all your aliases work.
https://www.npmjs.com/package/webpack-isomorphic-tools

node.js/Jade - How to pre-compile jade files and cache it?

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

Does jadeify download templates 1 by 1 on demand?

I am thinking of using Jade templates on client side (with BackboneJS). Seems like I can use jadeify. But was wondering, how does it work? Does it download each template 1 by 1 or compile all templates on serverside then serve a "compiled" templates file to the client? Looking at the source, it looks surprisingly short:
https://github.com/substack/node-jadeify/blob/master/jadeify.js
var views = require('jadeify/views'); ...
module.exports = function (file, vars, opts) {
...
return $(jade.render(views[file], opts));
};
Line 1: can I even require a folder like that? Can I say views is now an array of scripts under that directory? That appear to be the case from Line 5, where views[file] is used.
But it calls jade.render. Won't it be more efficient to call jade.compile and cache it first? Or is it already cached somewhere?

Node.js, Express and css, js, image assets

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!
}

Resources