I have the following simple structure for my website:
src
js
core.js
main.js
lib
jquery-1.8.2.js
require-2.1.1.js
require-text.js
templates
1.html
2.html
index.html
build
I want all js+lib files to be compiled into one build/js/main.js file and other files just to be copied to build folder. How to write grunt.js config for this task? It seems I should use grunt-contrib-require..
The second question is how to compile 1.html and 2.html (I use require text! plugin) into one line for each and include theese lines to build/js/main.js? This case there should be only two files into build folder - index.html and main.js.
Take a look at grunt-contrib-requirejs and see if it is helpful to you.
The Grunt Website offers a very good tutorial to get you started, this is what you will need:
grunt-contrib-concat - To put files together in one
grunt-contrib-copy - To copy files to your "build" folder
grunt-usemin - To use the compiled js file in your html
I am not sure how to put those html files together though, feels weird to do that but maybe you can find a plugin for it.
Your Gruntfile.js should reside at the root of the directory i.e ls should show src/ build/ Gruntfile.js
Contents of `Gruntfile.js specific for your requirements:
module.exports = function (grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
concat: {
js: {
src: [
'src/js/*', 'src/lib/*'
],
dest: 'build/js/combined.js'
}
},
uglify: {
js: {
files: {
'build/js/main.js': ['build/js/combined.js']
}
}
},
});
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.registerTask('default', ['concat:js', 'uglify:js']);
};
I don't think require-js to be used here. Require-js is helpful when you need to load your js scripts in a specific order. If that being the case add the below code in your Gruntfile.js just below pkg: grunt.file.readJSON('package.json'), line
requirejs: {
compile: {
options: {
baseUrl: "path/to/base",
mainConfigFile: "path/to/config.js",
name: "path/to/almond", // assumes a production build using almond
out: "path/to/optimized.js"
}
}
}
You might consider adding grunt-require to the list that luschn put together. It uses r.js, has lots of options, and is pretty darn nice.
Related
My folder structure is as follows
static/
js/
default/
main.js
lib/
someplugin.js
vendor/
jquery.js
tinyMce.js
Inside main.js I have the following code
#import '../lib/vendor/jquery.js';
#import '../lib/vendor/tinyMce.js';
#import '../lib/someplugin.js';
// ... more code ...
Every time I run grunt I'm getting the follwing error:
Warning: Unable to read "/PATH_TO_MY_APP/static/js/lib/vendor" file (Error code: EISDIR).
If I remove the tinyMce.js import line, grunt runs fine. So the problem must be with tinyMce, right? Wrong, if I cut all the content of tinyMce.js and paste it inside jquery.js (after jquery.js own content), grunt will run ok.
Here is my Gruntfile.js:
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
import: {
options: {},
default: {
expand: true,
cwd: 'static/js/default/',
src: '**/*.js',
dest: 'static/js/stage/default/',
ext: '.js',
}
}
});
grunt.loadNpmTasks('grunt-import');
grunt.registerTask('default', ['import']);
};
I've read the docs of the plugins I use, but I found no option that may help. :(
instead import all your files in the main.js
why you don't let grunt do this?
you can use concat and uglify for this:
see: Grunt concat all package.json dependencies
have you tried just use that cwd:
'static/**/*.js',
also can you share your gruntfile.js? so I can have a better look.
I hope that helped you.
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
I'm configuring my Gruntfile and I'm stuck on something I feel should be possible but I'm not able to find the right configuration for it. I'm trying to copy my bower components to my dist on build with the grunt-contrib-requirejs module. The part I'm stuck on is keeping the folder structure in tact when copying to dist.
My app's basic structure, and dist/ should build the same way
Gruntfile.js
app/
- assets/
- bower_components/
- js/
- img/
- etc/
- index.html
Currently, I define each file in the copy module and it copy's them all over
copy: {
dist: {
files: [{
expand: true,
dot: true,
cwd: 'app',
dest: 'dist',
src: [
'*.{ico,png}',
'.htaccess',
'partials/**/*',
// Bower Components
'assets/bower_components/requirejs/require.js',
'assets/bower_components/fastclick/lib/fastclick.js',
'assets/bower_components/jquery/dist/jquery.min.js',
'assets/bower_components/modernizr/modernizr.js'
]
}]
}
},
But I want to eliminate this and use the paths I've already defined in main.js to copy these files over. Less hardcoded stuff, more automation.
My require task
requirejs: {
dist: {
options: {
mainConfigFile: app + '/assets/js/main.js',
dir: dist + '/assets/js',
optimize: 'uglify',
paths: {
modernizr: 'empty:',
jquery: 'empty:',
fastclick: 'empty:'
}
}
}
},
This current configuration combined with copy moves them all over properly. If I could eliminate the paths property all together and use directory properties only that would be great. If I have to copy my paths from my main.js into here thats ok... if it's the only way to do it.
Let me know if you need any more info!
The JS files in your bower directory should be included in the optimized output of requirejs, as long as they are configured and referenced in your require js app. If they're not referenced as dependencies, I don't think they get included.
The ico, png, htaccess and other files may need to be copied over manually.
Depending on your partials, the text plugin and hbs plugin could compile those into the optimized file I think.
I think defining empty: in paths are for using network resources (e.g. when using CDNs instead of using local bower libraries), so the paths config is probably unnecessary
I'd like to combine all the underscore templates in a directory to a single js file ( possibly precompile it ? ) for use with the backbonejs part of my sails.js app.
I think I can use the plain fs module with nodejs to read the files and combine them, I'm looking at grunt to do this as well but still not sure.
Can someone help me with this ?
You can use grunt to do this. The plugin grunt-contrib-jst is what you're looking for; it has installation and usage documents here.
A simple Gruntfile.js like this should do it. (This example assumes all your source code is under a src/ subdirectory, all templates are in *.html files under src/, and you're creating an output file in the build/ subdirectory. Adjust as needed to fit your actual situation.) Run by typing grunt on the command line.
Just include the single file build/view-templates.js in your index file to load all of your Underscore view templates.
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-jst');
grunt.initConfig({
// compile view templates into single file
jst: {
compile: {
files: {
"build/view-templates.js": ["src/**/*.html"]
}
}
}
});
grunt.registerTask('default', 'jst' );
};
Is there an easy way to reference all js files in an HTML file rather than referencing it one by one?
Instead of this -
<script type="text/javascript" src="js/controllers/mainCtrl.js"></script>
<script type="text/javascript" src="js/controllers/browseCtrl.js"></script>
...
I'm looking for something like this -
<script type="text/javascript" src="js/controllers/*.js"></script>
Or is there a tool out there that copies the contents of these files into one file and reference that one file instead? This will be minimize the HTTP calls.
Is there an easy way to reference all js files in an HTML file rather than referencing it one by one?
For some value of "easy". There is nothing built in to browsers that will do it though.
Or is there a tool out there that copies the contents of these files into one file and reference that one file instead?
There are many. cat is the simplest one.
Call it from your usual build tool.
You can use something like require.js to combine them at runtime during development, and call r.js via Node from your build tool for packaging for your staging and live environments.
You can give Require.js a go. Require.js is the only JavaScript-file that is loaded through the script-tag. When you go out of development you can use Require.js's r.js to minify and concat everything into one file.
I use this tool all the time to minify my JS files:
Online Javascript Compression Tool
You can upload multiple files and it will concatenate them into one for you. It also produces smaller filesizes than YUI compressor, and Google's JS compiler most of the time too.
I am not sure why this hasn't been mentioned yet, but I do suppose this thread is a bit dated. Since I stumbled on this during my search to solve this very problem, I thought I would put a quick write-up about GruntJS here for other newbie JS guys to find.
Essentially, a properly configured Gruntfile.js will be able to perform a variety of tasks around JS including, but not limited to: concatenating files, minifying files, code linting, and much much more.
You can install grunt on Ubuntu with:
$ sudo apt-get install nodejs
$ sudo npm -g install grunt-cli
$ cd /path/to/my/project
--- Assumming you have a package.json file already in place ---
$ npm install grunt --save-dev
--- Install grunt plugins you wish to use ---
$ npm install grunt-contrib-concat --save-dev
$ npm install grunt-contrib-uglify --save-dev
$ npm install grunt-contrib-jshint --save-dev
$ npm install grunt-contrib-watch --save-dev
On the GruntJS site, there is a pretty good write-up for how to use GruntJS, but here is an example Gruntfile.js that will:
Lint all the JS files (app.js in the current directory and all .js files in the ngmodules directory).
Concatenate and save the files to dist/package-name.js.
Minify the concatenated file and save it to dist/package-name.min.js.
Gruntfile.js:
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
concat: {
options: {
separator: ';'
},
dist: {
src: ['app.js', 'ngmodules/**/*.js'],
dest: 'dist/<%= pkg.name %>.js'
}
},
uglify: {
options: {
banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
},
dist: {
files: {
'dist/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>']
}
}
},
jshint: {
files: ['Gruntfile.js', 'app.js', 'ngmodules/**/*.js'],
options: {
// options here to override JSHint defaults
globals: {
jQuery: true,
console: true,
module: true,
document: true
}
}
},
watch: {
files: ['<%= jshint.files %>'],
tasks: ['jshint']
}
});
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.registerTask('default', ['jshint', 'concat', 'uglify']);
};
There is also Gulp (http://gulpjs.com/), which can be used with various plugins. Here's an example that concatenates *.js files in one single file (main.js), then renames the resulting file and finally minifies it:
var gulp = require('gulp'),
rename = require('gulp-rename'),
uglify = require('gulp-uglify'),
concat = require('gulp-concat');
gulp.task('scripts', function(){
return gulp.src('./src/js/*.js')
.pipe(concat('main.js'))
.pipe(rename({suffix: '.min'}))
.pipe(uglify())
.pipe(gulp.dest('./src/js/*.js'));
You can try and combine your javascript files or plugins into one:
<script type="text/javascript" src="js/controllers/plugins.js"></script>
You'll have to do it manually though.
Another option would be to write a server-side script to combine and minify all your javascript files.