I'm using Grunt for the first time. Someone else has already setup/configured the Gruntfile.js configuration file. Although it works, what I find incredibly annoying is that all my js files are reduced into a single app.min.js file with a map file.
So even though this works, when I get an error or a bug, it is impossible to know which source file caused the JS bug.
Is there a way to configure Grunt not to compress everything into a single file, but to leave everything as separate includes? I love the ability to only need to include a single JS in my html.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
jsFilesApis: [
'client/vendors/apis/jquery-1.11.0.min.js',
'client/vendors/apis/bootstrap.min.js',
'client/vendors/apis/angular.1.2.16.min.js',
.....
],
jsFilesApp: [
'client/app/**/*.js'
],
'angular-injector': {
test: {
expand: true, // required
token: 'ng', // optional
src: '<%= jsFilesApp %>',
dest: 'build/'
}
},
uglify: {
dist: {
files: {
"build/app.min.js": '<%= jsFilesApp %>',
"build/apis.min.js": '<%= jsFilesApis %>'
},
options: {
mangle: false,
compress: false,
sourceMap: true
}
},
},
});
An my HTML is:
<html ng-app='app'>
<head>
<script type="text/javascript" src="./build/apis.min.js"></script>
<script type="text/javascript" src="./build/app.min.js"></script>
</head>
...
How do I configure Grunt such that I can have all my JS files separately included to be able to view/debug them appropriately in the browser?
Well for starters, there's no way to only include a single script tag with all of your javascript, while keeping them separate in your source. I do not know of a grunt plugin or otherwise that will concat your javascripts into a single script but allow you to see them separately in the browser (a la sprockets).
However, what I have is a non-minified script (in development) that I can look at. It does not show you immediately what library, or file it is from, but you can at least see the code.
What I have is (using grunt-contrib-concat)
concat: {
'build/<%= pkg.name %>.js': ['build/vendor.js', 'build/app.js', 'build/templates.js']
},
which for you would be something like
concat: {
"build/app.js": '<%= jsFilesApp %>',
"build/apis.js": '<%= jsFilesApis %>'
},
And then include both of those in your html. You'll also want to specify not to uglify on a development build. For me, this look like
grunt.registerTask('build:dev', ['clean:dev', 'browserify:app', 'browserify:test', 'emberTemplates', 'jshint:dev', 'less:transpile', 'concat', 'copy:dev']);
So for you it would be
grunt.registerTask('build:dev', ['angular-injector', 'concat']);
grunt.registerTask('build:prod', ['angular-injector', 'concat', 'uglify']);
@JakeDluhy gave me a good suggestion and some pointers in the right direction. I ended up using grunt-injector combined with bower/wiredep to get what I needed. Final trick was to use yeoman to generate a scaffold AngularJS file and steal ideas from the generated Gruntfile.js.
Now in my index.html I have the following:
<!-- build:js scripts/vendor.js -->
<!-- bower:js -->
<script src="bower_components/jquery/dist/jquery.js"></script>
<script src="bower_components/underscore/underscore.js"></script>
<!-- endbower -->
<!-- endbuild -->
<!-- build:js(client/) scripts/apis.js -->
<!-- api injector:js -->
<script src="vendors/apis/http-auth-interceptor.js"></script>
<script src="vendors/apis/ng-tags-input.js"></script>
<!-- endinjector -->
<!-- endbuild -->
<!-- build:js(client/) scripts/app.js -->
<!-- app injector:js -->
<script src="app/app.js"></script>
<script src="app/breadcrumb/breadcrumbController.js"></script>
<!-- endinjector -->
<!-- endbuild -->
And my Gruntfile.js:
// Automatically inject Bower components into the app
wiredep: {
options: {
cwd: '<%= yeoman.app %>'
},
app: {
src: ['<%= yeoman.app %>/index.html'],
ignorePath: /\.\.\//
},
// Automatically inject app JS files into the app
injector:{
app:{
options:{
starttag: '<!-- app injector:{{ext}} -->',
ignorePath: 'client/',
addRootSlash: false
},
files:{
'<%= yeoman.app %>/index.html' : ['<%= yeoman.app %>/app/**/*.js']
}
},
api:{
options: {
starttag: '<!-- api injector:{{ext}} -->',
ignorePath: 'client/',
addRootSlash: false
},
files:{
'<%= yeoman.app %>/index.html' : ['<%= yeoman.app %>/vendors/**/*.js']
}
}
Hopefully this can help someone in the future.