Multiple paths in requirejs r.js optimize - javascript

Is there a way to keep one paths.js file to keep track of all paths for
//i know you can do this where configobject.paths = require('paths');
requirejs.config(configobject)
//and r.js build config
({
paths:require('paths'),
})

I also wanted to centralize my AMD module paths. This is an implementation in curl, but the same approach works for RequireJS:
Basically, but the config in a file:
https://github.com/SimpleAsCouldBe/appCore/blob/master/shared/appCore/setCurlPaths.js
And use the config in any page you want:
https://github.com/SimpleAsCouldBe/appCore/blob/master/exampleApp1/index.html
You can optimize this with grunt concat or something during the build. You can also tell grunt's requirejs optimizer about this shared config file:
# https://github.com/jrburke/r.js/blob/master/build/example.build.js
requirejs:
oneForAll:
options:
mainConfigFile: "shared/appCore/requireConfig.js"

Related

How to read and parse gruntfile programatically so I can modify it and save again?

I am creating a complex Yeoman Generator and I need to read an existing gruntfile and modify it.
Any javascript way of parsing a gruntfile is enought.
Any help will be appreciated.
imo i dont think you can achieve that by parsing js files and generating a new gruntfile.
instead of doing that you can try creating template files ex. .jade (or another template engine) so , you can produce the final gruntfile, you can look into grunt configuration object grunt.config and eventually read information, interpolate data into your template(s) and produce the final gruntfile.js.
Here's a modular approach to grunt that you can use without having to modify gruntfile.js every time you add new tasks, plugin or custom.
Add load-grunt-tasks npm module as a dev dependency: npm install load-grunt-tasks --save-dev. This plugin allows you to load all your grunt dependencies using one line of code.
Specify a folder in your project to hold all your modular configuration files. This example uses the path grunt/configs/. Each json file's name should match the it's property name in the grunt config. For example, the config for grunt-copy-config should be grunt/configs/copy.json
Copy the gruntfile.js I've posted as a public gist (stack overflow wasn't formatting the code properly). This gruntfile will automatically load your plugins and compile a config object using the project's package.json file and every .json file found in grunt/configs/. The gruntfile also loads any custom tasks I've saved into grunt/tasks/
As an alternate option - you can host your modular config objects in JavaScript files instead of json files (that's what I do). This provides me with the capability to dynamically compile my config objects if I need to. If that's something that interests you, I can share that code as well.
Thank you guys for the tips, great ideas, with your guidance I came up using a json file for each configuration:
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
browserify: grunt.file.readJSON('browserify.json'),
uglify: grunt.file.readJSON('uglify.json'),
sass: grunt.file.readJSON('sass.json'),
cssmin: grunt.file.readJSON('cssmin.json'),
});
grunt.loadNpmTasks('grunt-browserify');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-sass');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.registerTask('default', ['browserify', 'sass']);
grunt.registerTask('production', ['browserify', 'sass', 'uglify', 'cssmin']);
};
Now I can easily modify the configuration

Requirejs and Grunt: mainConfigFile vs grunt task options

I find there to be a lot of confusion/lack a specific way of handling building with require in grunt. I'm just confused what configuration should go directly in Grunt task options:
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
requirejs: {
compile: {
options: {
baseUrl: './js',
mainConfigFile: 'config.js',
optimize: 'none',
include: ['./main'],
out: 'optimized.js'
}
}
}
});
And then in config file:
({
appDir: './',
baseUrl: './js',
dir: './dist',
optimize: 'none',
optimizeCss: 'standard',
removeCombined: true,
paths: {
jquery: './js/jQuery/jquery',
}
})
Obviosuly there seems to be some redundancy but that is mostly what I've found. Can someone explain why or if I'm mistaken? Can I place all config in one or the other? I'm only planning on working off of the optimized single file with almond.
Also do I only state the initial single point of entry to build the dependency chain from ie my main.js file and any require calls in there or can I state a wildcard list of files that calls modules:
include: ['./variousFiles/*.js']
Any and all clarifications of how to best utilize require with Grunt will be appreciated. Thank you!
When you use RequireJS' r.js optimizer there are two configurations to speak of:
The runtime configuration which is what is described in the RequireJS documentation. This is where you tell RequireJS where to find modules at runtime.
The build configuration, which is what is described with r.js' documentation. This tells r.js how to build bundles from your modules.
The mainConfigFile option is for the build configuration, it tells r.js where to find the runtime configuration you plan to use when you run the bundles it will create. This is to prevent having to duplicate shim and paths options from the runtime configuration to the build configuration.
In your description, it looks like you are making mainConfigFile point to a build configuration. This is useless.

Requirejs optimiser - Include nested dependencies for certain files and folders

I'm using the RequireJS optimiser to minify and concatenate my code. At the moment r.js doesn't minify a lot of my scripts because of the nested dependencies.
I want to include nested dependencies for:
All dependencies inside: 'js/services'
All nested dependencies for a list of specific JavaScript files
Note: I do realise that there is the option findNestedDependencies: true but this looks for absolutely every dependency across all JavaScript files in the app where as I only want to do this for certain JavaScript files and folders as I have a set of files which are always used on every page/view.
My current build file looks like:
({
baseUrl: '../static/js',
mainConfigFile: '../static/js/main.js',
name: 'main',
out: '../static/js/scripts.min.js',
paths: {
requireLib: 'vendor/require/require.min'
},
include: 'requireLib'
})
I have been following this tutorial to get the optimiser running:
http://www.youtube.com/watch?v=m6VNhqKDM4E
You can use include to specify all dependencies you want to force into the output file:
// ...
include: ['requireLib', 'js/services/dep1', 'js/services/dep2'],
// ...
I don't think there's a way to include entire folder (something like "js/services/*"), though.
Since in my project I had many dynamic dependencies I wanted to include in the output I ended up creating an "js/services/_all.js" module which lists files in its directory, for example:
define([
'./dep1',
'./dep2'
],
function () {
// this module imports all modules from current folder so
// there's no need to list every single file in the build config
});
and then configuring r.js with:
// ...
include: ['requireLib', 'js/services/_all'],
// ...

Running tasks configured across multiple grunt.js files

I have a node app that includes multiple unpublished modules. My app's package.json includes a few git dependencies:
"module-a": "git+ssh://git#github.com:me/module-a.git",
"module-b": "git+ssh://git#github.com:me/module-b.git"
and each of those have their own grunt config. Eg in node_modules/module-a/grunt.js:
module.exports = function(grunt) {
grunt.initConfig({
lint: {
files: ['server/**/*.js', 'test/**/*.js']
},
jshint: {
options: require('./lint-ci')
}
});
grunt.registerTask('default', 'lint');
};
(they also run tests, etc, but I'm keeping it simple here)
Is there a built-in way to do this with grunt? Note that I want to keep the dependent grunt.js files for convenience when I've only changed something within that dependency.
The only solutions I have found are
build up my main grunt.js programmatically (eg, iterating over my dependencies in package.json to build the lint and test config)
call grunt multiple times using --config node_modules/module-a/grunt.js
Neither seems ideal. Is there a better way?
Just a thought but have you looked at grunt-hub?
https://github.com/shama/grunt-hub

Working project structure that uses grunt.js to combine JavaScript files using RequireJS?

I have some projects that use RequireJS to load individual JavaScript modules in the browser, but I haven't optimized them yet. In both development and production, the app makes a separate request for each JavaScript file, and now I would like to fix that using Grunt.
I have tried to put together a simple project structure to no avail, so I'm wondering if someone can provide a working example for me. My goals are the following:
In development mode, everything works in the browser by issuing a separate request for each required module. No grunt tasks or concatenation are required in development mode.
When I'm ready, I can run a grunt task to optimize (combine) all of the JavaScript files using r.js and test that out locally. Once I'm convinced the optimized application runs correctly, I can deploy it.
Here's a sample structure for the sake of this conversation:
grunt-requirejs-example/
grunt.js
main.js (application entry point)
index.html (references main.js)
lib/ (stuff that main.js depends on)
a.js
b.js
requirejs/
require.js
text.js
build/ (optimized app goes here)
node_modules/ (necessary grunt tasks live here)
Specifically, I'm looking for a working project structure that I can start from. My main questions are:
If this project structure is flawed, what do you recommend?
What exactly needs to be in my grunt.js file, especially to get the r.js optimizer working?
If all of this isn't worth the work and there's a way to use the grunt watch task to automatically build everything in development mode every time I save a file, then I'm all ears. I want to avoid anything that slows down the loop from making a change to seeing it in the browser.
I use the grunt-contrib-requirejs task to build project based on require.js. Install it inside your project directory with:
npm install grunt-contrib-requirejs --save-dev
BTW: --save-dev will add the package to your development dependencies in your package.json. If you're not using a package.json in your project, ignore it.
Load the task in your grunt file with:
grunt.loadNpmTasks('grunt-contrib-requirejs');
And add the configuration to your grunt.initConfig
requirejs: {
production: {
options: {
baseUrl: "path/to/base",
mainConfigFile: "path/to/config.js",
out: "path/to/optimized.js"
}
}
}
Now you're able to build your require.js stuff into a single file that will be minimized with uglifyjs by running grunt requirejs
You can bundle a set of different tasks into some sort of main task, by adding this to your grunt file
grunt.registerTask('default', ['lint', 'requirejs']);
With this, you can simply type grunt and grunt will automatically run the default task with the two 'subtasks': lint and requirejs.
If you need a special production task: define it like the above
grunt.registerTask('production', ['lint', 'requirejs', 'less', 'copy']);
and run it with
grunt production
If you need different behaviors for 'production' and 'development' inside i.e. the requirejs task, you can use so called targets. In the configuration example above it's already defined as production. You can add another target if you need (BTW, you can define a global config for all targets by adding a options object on the same level)
requirejs: {
// global config
options: {
baseUrl: "path/to/base",
mainConfigFile: "path/to/config.js"
},
production: {
// overwrites the default config above
options: {
out: "path/to/production.js"
}
},
development: {
// overwrites the default config above
options: {
out: "path/to/development.js",
optimize: none // no minification
}
}
}
Now you can run them both at the same time with grunt requirejs or individually with grunt requirejs:production, or you define them in the different tasks with:
grunt.registerTask('production', ['lint', 'requirejs:production']);
grunt.registerTask('development', ['lint', 'requirejs:development']);
Now to answer your questions:
I would definitely use a subfolder in your project. In my case I use a 'src' folder for development that is build into a 'htdocs' folder for production. The project layout I prefere is:
project/
src/
js/
libs/
jquery.js
...
appname/
a.js
b.js
...
main.js // require.js starter
index.html
...
build/
... //some tmp folder for the build process
htdocs/
... // production build
node_modules/
...
.gitignore
grunt.js
package.json
see above
You can do so, but I wouldn't recommend to add requirejs to the watch task, it's a resource hungry task and it will slow down your machine noticeable.
Last but not least: Be very cautious when playing around with r.js. Especially when you want to optimize the whole project with r.js by adding a modules directive to your config. R.js will delete the output directory without asking. If it happens that it is accidentally configured to be your system root, r.js will erase your HDD. Be warned, I erased my whole htdocs folder permanently some time ago while setting up my grunt task... Always add keepBuildDir:true to your options when playing around with the r.js config.

Categories