Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to concatenate JavaScript files with dependencies and to output them as a module?

I know this question came up in similar variations often, but no solution seems to fully fit my needs. I have the following problem:

In development I use multiple JS files (a single file every "object"). These JS files have several dependencies within each other - some rely on others and I need to load them first. Currently I use RequireJS to load each JS file in the right order, so I define a module for each file. Fine and dandy. But now I want to concatenate all my JS files into one big JS file which should be a module itself. I use the RequireJS optimizer r.js to do that. My problem: Every JS file is concatenated to a big JS file, but the module definition for each object is included to. I don't have one big module in one big file, but many modules in one big file.

After that I tried grunt for concatenating which works fine, but ignores dependencies of files. It just concatenates every file in alphabetical order or I have to hardcode the order in my gruntfile.

How can I solve this?

Just as an illustration to my problem: I have following files (pseudo code):

FileA
- define FileA module
- depends on FileB
- FileA Logic

FileB
- define FileB module
- FileB Logic

And I want this output:

LibFile
- define LibFile module
- FileB Logic, FileA Logic

But I get this with r.js (module definition from FileA and FileB is copied):

LibFile
- define FileB module
- FileB Logic
- define FileA module
- depends on FileB
- FileA Logic

And I get this with grunt (wrong order):

LibFile
- FileA Logic
- FileB Logic

Maybe that questions is a little bit stupid, but I just can't solve this with the tools everybody seems to use... I tried the grunt-requirejs plugin, too. But it throws several erros which I couldn't resolve.

Thank you, Pipo

like image 493
Pipo Avatar asked Jun 07 '12 12:06

Pipo


People also ask

How do I share data between JavaScript files?

In JavaScript, variables can be accessed from another file using the <script> tags or the import or export statement. The script tag is mainly used when we want to access variable of a JavaScript file in an HTML file. This works well for client-side scripting as well as for server-side scripting.

How do I include a JavaScript file in Webpack?

You can bundle your JavaScript using the CLI command by providing an entry file and output path. Webpack will automatically resolve all dependencies from import and require and bundle them into a single output together with your app's script.


1 Answers

I am going to move it into an answer. Just so the code is a bit clearer.

I am doing these by memory (since I can't test it right now) so some little things may be not entirely accurate.

It depends of course on how you package your modules, but one way is to register all your smaller modules in a bigger module:

File A.js

define([], function() {
    // do something
    return A;
});

File B.js

define(['path/to/A'], function(A){
    // do something with A and more
    return B;
});

Then, you package them together:

File mylib.js

define(['path/to/A', 'path/to/B'], function(A, B){
    return {
        A : A,
        B : B
    }
}

you then can point your build profile to mylib.js and it will be combined into one big file. It won't be one all-encapsulating module, but it will have an entry module that references everything else. You then can use it like so:

require.config({
    paths : {
        'path/to/mylib' : 'real/path/to/mylib/on/server'
    }
});
require(['path/to/mylib'], function(Lib) {
    // do something using Lib.A or Lib.B
}

the one thing to pay attention to is the ID of your big module file. By default RequireJS build gives ID that matches physical path (from appDir IIRC) and you have to match that when you load your dependency. Simply put, if your resulting mylib.js file has a main module that received the name 'path/to/mylib', you will have to match it and load it by the same ID (using require.config.paths) or play with maps and such (some of which requires RequireJS 2.0).

The following is the reason I asked you why would you want to do the "big module" thing

Other thing of note is that all your inner smaller modules also receive IDs matching their physical path and you can use these IDs when you use the big package module (so that you can access them not only through Lib.A) if mylib.js has been loaded:

require(['path/to/A'], function(A) {
    // do something using A
}
like image 100
ZenMaster Avatar answered Oct 25 '22 10:10

ZenMaster