Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assemble every module into a single .js file

I want to minimize the number of HTTP requests from the client to load scripts in the browser. This is going to be a pretty general question but I still hope I can get some answers because module management in javascript has been a pain so far.

Current situation

Right now, in development, each module is requested individually from the main html template, like this:

<script src="/libraries/jquery.js"></script>
<script src="/controllers/controllername.js"></script>
...

The server runs on Node.js and sends the scripts as they are requested.

Obviously this is the least optimal way of doing so, since all the models, collections, etc. are also separated into their own files which translates into numerous different requests.

As far as research goes

The libraries I have come across (RequireJS using AMD and CommonJS) can request modules from within the main .js file sent to the client, but require a lot of additional work to make each module compliant with each library:

;(function(factory){

    if (typeof define === 'function' && define.amd) define([], factory);
    else factory();

}(function(){

    // Module code

    exports = moduleName;
}));

My goal

I'd like to create a single file on the server that 'concatenates' all the modules together. If I can do so without having to add more code to the already existing modules that would be perfect. Then I can simply serve that single file to the client when it is requested.

Is this possible?

Additionally, if I do manage to build a single file, should I include the open source libraries in it (jQuery, Angular.js, etc.) or request them from an external cdn on the client side?

like image 359
notyourtype Avatar asked Jul 10 '15 15:07

notyourtype


2 Answers

What you are asking to do, from what I can tell, is concat your js files into one file and then in your main.html you would have this

<script src="/pathLocation/allMyJSFiles.js"></script>

If my assumption is correct, then the answer would be to use one of the two following items

GULP link or GRUNT link

I use GULP.

You can either use gulp on a case by case basis, which means calling gulp from the command line to execute gulp code, or use a watch to do it automatically on save.

Besides getting gulp to work and including the gulp files you need to do what you need, I will only provide a little of what I use to get your answer.

In my gulp file I would have something like this

var gulp = require('gulp');
var concat = require('gulp-concat');
...maybe more.

Then I have the file paths I need to be reduced into one file.

var onlyProductionJS = [
  'public/application.js',
  'public/directives/**/*.js',
  'public/controllers/**/*.js',
  'public/factories/**/*.js',
  'public/filters/**/*.js',
  'public/services/**/*.js',
  'public/routes.js'
];

and I use this info in a gulp task like the one below

gulp.task('makeOneFileToRuleThemAll', function(){
  return gulp.src(onlyProductionJS)
    .pipe(concat('weHaveTheRing.js'))
    .pipe(gulp.dest('public/'));
});

I then run the task in my command line by calling

gulp makeOneFileToRuleThemAll

This call runs the associated gulp task which uses 'gulp-concat' to get all the files together into one new file called 'weHaveTheRing.js' and creates that file in the destination 'public/'

Then just include that new file into your main.html

<script src="/pathLocation/weHaveTheRing.js"></script>

As for including all your files into one file, including your vendor files, just make sure that your vendor code runs first. It's probably best to keep those separate unless you have a sure fire way of getting your vendor code to load first without any issues.

UPDATE

Here is my gulp watch task.

gulp.task('startTheWatchingEye', function () {
  gulp.watch(productionScripts, ['makeOneFileToRuleThemAll']);
});

Then I start up my server like this (yours may differ)

npm start
// in a different terminal window I then type
gulp startTheWatchfuleye

NOTE: you can use ANY movie or show reference you wish! :)

Now just code it up, every time you make a change in the specified files GULP will run your task(s).

If you want to say run Karma for your test runner...

add the following to your gulp file

var karma = require('karma').server;

gulp.task('karma', function(done){
  karma.start({
    configFile: __dirname + '/karma.conf.js'
  }, done);
});

Then add this task karma to your watch I stated above like this...

gulp.task('startTheWatchingEye', function(){
  gulp.watch(productionScripts, ['makeOneFileToRuleThemAll', 'karma']);
});

ALSO

Your specific settings may require a few more gulp modules. Usually, you install Gulp globally, as well as each module. Then use them in your various projects. Just make sure that your project's package.json has the gulp modules you need in dev or whatever.

There are different articles on whether to use Gulp or Grunt. Gulp was made after Grunt with a few additions that Grunt was lacking. I don't know if Grunt lacks them anymore. I like Gulp a lot though and find it very useful with a lot of documentation.

Good luck!

like image 102
SoEzPz Avatar answered Oct 14 '22 01:10

SoEzPz


I'd like to create a single file on the server that 'concatenates' all the modules together. If I can do so without having to add more code to the already existing modules that would be perfect.

Sure you can. You can use Grunt or Gulp to do that, more specifically grunt-contrib-concat or gulp-concat

Here's an example of a Gruntfile.js configuration to concat every file under a js directory:

grunt.initConfig({
  concat: {
    dist: {
      files: {
        'dist/built.js': ['js/**/**.js'],
      },
    },
  },
});

Also, you can minify everything after concatenating, using grunt-contrib-minify.

Both libraries support source maps so, in the case a bug gets to production, you can easily debug.

You can also minify your HTML files using grunt-contrib-htmlmin.


There's also an extremely useful library called grunt-usemin. Usemin let's you use HTML comments to "control" which files get minified (so you don't have to manually add them).

The drawback is that you have to explicitely include them in your HTML via script tags, so no async loading via javascript (with RequireJS for instance).


Additionally, if I do manage to build a single file, should I include the open source libraries in it (jQuery, Angular.js, etc.) or request them from an external cdn on the client side?

That's debatable. Both have pros and cons. Concatenating vendors assures that, if for some reason, the CDN isn't available, your page works as intended. However the file served is bigger so you consume more bandwidth.

In my personal experience, I tend to include vendor libraries that are absolutely essential for the page to run such as AngularJS for instance.

like image 33
Tivie Avatar answered Oct 14 '22 00:10

Tivie