Grunt & requirejs optimizer for a multi app project
gruntjs, javascript, optimization, requirejs, task
Solution
Solved, by passing multiple sets of options to the requirejs task, thanks to this article for the final pointers I needed:
module.exports = function(grunt) {
var files = grunt.file.expand('static/js/apps/*.js');
var requirejsOptions = {};
files.forEach(function(file) {
var filename = file.split('/').pop();
requirejsOptions[filename] = {
options: {
baseUrl: 'static/js/',
include: './apps/'+filename,
out: 'static/js/build/'+filename
}
};
});
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
requirejs: requirejsOptions,
});
};
Then the `['requirejs']` task can be run as normal and will output the appropriate compiled .js file as per each of the `options: {}` blocks that were specified in `requirejsOptions`, eg:
`grunt.registerTask('default', ['requirejs']);`
Problem
I'm having issues getting Grunt to perform requirejs optimization on a project with the following structure: ``` static/js |── apps |── app.js |── dash.js |── news.js ... (many more 'app' files) |── build |── collections |── libs |── models |── util |── views ``` Each of `static/js/apps/*.js` should be compiled to `static/js/build/*.js` containing the relevant dependencies (eg. `views/view1`, `libs/query` etc). This is currently being performed by a basic bash script: ``` JS_ROOT="static/js" for f in ${JS_ROOT}/apps/* do FILE=$(basename -s .js ${f}) pushd . cd ${JS_ROOT} && r.js -o baseUrl=. name=libs/require-min.js include=apps/${FILE} out=build/${FILE}.js popd done ``` I'm attempting to move to a Grunt-based optimization, with the following in `Grunt.js`: ``` requirejs: { compile: { options: { appDir: 'static/js/', baseUrl: './apps/', dir: 'static/js/build/', modules: [ { name: 'app', } ] } } } ``` Running generates the following error: ``` >> Tracing dependencies for: app >> Error: ENOENT, no such file or directory >> 'static/js/build/apps/libs/jquery.js' >> In module tree: >> app ``` I can clearly see what the problem is, but am failing to figure out how to indicate that the dependencies in each `static/js/apps/*.js` file are in `static/js/` not `static/js/build` In addition to this, I'm assuming that the `modules` block containing `name: 'app'` should be outputting the compiled file `static/js/build/app.js` from the contents of `static/js/apps/app.js`. Without creating an additional `module` block for each file in `static/js/apps`, how can I compile each of the files into their relevant `static/js/build/*.js` file? Update 1 So the following in my Gruntfile compiles `static/js/apps/app.js` successfully into `static/js/build/app.js`: ``` requirejs: { compile: { options: { baseUrl: 'static/js/', include: './apps/app.js', out: 'static/js/build/app.js', } } } ``` The next step being to compile `static/js/apps/*.js` into `static/js/build/*.js` without having to define each individually... Update 2 Modifying the above to: ``` requirejs: { compile: { options: { baseUrl: '../', include: './apps/<%= appFile %>', out: 'static/js/build/<%= appFile %>', } } } ``` And creating the task: ``` grunt.registerTask('buildrjs', function() { var dir='static/js/apps/'; grunt.file.setBase(dir); var files = grunt.file.expand(['*.js']); files.forEach(function(filename) { grunt.log.write('Compiling '+filename+'\n'); grunt.config.set('appFile', filename); grunt.task.run('requirejs:compile'); }); }); ``` Almost gets me to the solution. The tasks runs through each file in `static/js/apps/` and passes the filename into `grunt.config.set('appFile', filename);`. The output of the task outputs `Compiling app.js Compiling news.js...` etc, however afterwards the actual `requirejs:compile` tasks runs over & over on the last file in the `static/js/apps/` directory, rather than each individual file. An async issue?