Reputation: 33318
I'm developing a legacy ASP.NET MVC 5 project which still uses ASP.NET Bundling and Minification. I'm interested in switching to Gulp or Grunt, because I need to save source maps for my js files.
It seems easy to generate a minified script bundle with Gulp or Grunt, but what I do not understand yet is the recommended setup for loading single js files when debugging and minified bundles in production. I guess it would be quite easy to generate a razor view for including the scripts as part of my Grunt / Gulp compilation process, but it feels like re-inventing the wheel.
For instance, in ASP.NET MVC i can write something like this:
@Scripts.Render("~/bundles/MyJSBundle")
and it will automatically load separate js files in development and a single script bundle in production. What is the easiest way achieve this with Gulp or Grunt?
Upvotes: 0
Views: 328
Reputation: 25002
Typically when using Grunt you generate two builds - one for "dev" (development) and another for "dist" (distribution/production). Whereby for the scenario you've described;
bundle.min.js
) derived from multiple source .js
files..js
files, for the purpose of debugging during the development lifecycle.Grunt plugins, such as grunt-processhtml, provide a way to update any links to .js
assets in the .html
file. For example, let's say your source .html
contains these two links;
<script src="js/a.js"/>
<script src="js/b.js"/>
They can be substituted during the "dist" and/or "dev" build step to the following single <script>
element:
<script src="dir/bundle.min.js"/>
The following somewhat contrived example demonstrates how you may approach your requirement using Grunt.
Let's say our initial project directory is structured as follows:
project
├── Gruntfile.js
├── node_modules
│ └── ...
├── package.json
└── src
├── index.html
└── js
├── a.js
└── b.js
Note, in the src
directory we have a single index.html
file, and two .js
files in the js
directory.
In the contents of index.html
shown below it contains two <script>
elements, each one referencing a .js
file.
project/src/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>demo</title>
</head>
<body>
<!--build:js js/bundle.min.js-->
<script src="js/a.js"></script>
<script src="js/b.js"></script>
<!--/build-->
</body>
</html>
Note, the custom HTML comments encasing both <script>
elements. These custom HTML comments are utilized by grunt-processhtml
. The part that reads; js/bundle.min.js
in the comment essentially defines the new pathname to be used.
Let's consider the following Gruntfile.js
configuration:
Gruntfile.js
module.exports = function (grunt) {
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-processhtml');
grunt.initConfig({
// 1. Concatenate .js files.
concat: {
dist: {
src: [
'src/js/a.js',
'src/js/b.js'
],
dest: './dist/js/bundle.min.js'
},
dev: {
options: {
sourceMap: true
},
src: [
'src/js/a.js',
'src/js/b.js'
],
dest: './dev/js/bundle.min.js'
}
},
// 2. Minify .js files.
uglify: {
dist: {
files: {
'./dist/js/bundle.min.js': './dist/js/bundle.min.js' // dest : src
}
},
dev: {
options: {
mangle: false,
sourceMap: true,
sourceMapIn: './dev/js/bundle.min.js.map'
},
files: {
'./dev/js/bundle.min.js': './dev/js/bundle.min.js' // dest : src
}
}
},
// 2. Process .html file.
processhtml: {
dist: {
files: {
'./dist/index.html': './src/index.html' // dest : src
}
},
dev: {
files: {
'./dev/index.html': './src/index.html' // dest : src
}
}
}
});
grunt.registerTask('default', ['dist', 'dev']);
grunt.registerTask('dist', [
'concat:dist',
'uglify:dist',
'processhtml:dist'
]);
grunt.registerTask('dev', [
'concat:dev',
'uglify:dev',
'processhtml:dev'
]);
};
Explanation of Gruntfile.js:
In addition to the previously mentioned grunt-processhtml
plugin the following two are also utilized in this example:
grunt-contrib-concat - for concatenating the two .js
files.
grunt-contrib-uglify - for minifying the .js
file.
Note: There are other plugins available for these types of task. I have chosen these additional two plugins for the purpose of this demonstration.
Each of the three Tasks (concat
, uglify
, and processhtml
) contain two separate Targets named dist
and dev
. The main differences in each Target are:
dest
(destination) paths for the resultant generated .js
file(s).concat:dev
and uglify:dev
Targets its options
object defines the configuration for the resultant Source Map file.At the end of Gruntfile.js
three different grunt.registerTask()
have been defined. Each one defines a taskList that essentially defines which Task and Target to run in the order specified.
For example consider the following registered task named dist
:
grunt.registerTask('dist', [
'concat:dist',
'uglify:dist',
'processhtml:dist'
]);
When running grunt dist
via the command line Grunt essentially invokes this Task, which subsequently performs the following in this order:
dist
Target defined in the concat
Task.dist
Target defined in the uglify
Task.dist
Target defined in the processhtml
Task.Running Gruntfile.js (above) and its output
Running the following command via the command line:
grunt dev
outputs the following additional assets to the project directory:
project
├── ...
├── dev
│ ├── index.html
│ └── js
│ ├── bundle.min.js
│ └── bundle.min.js.map
└── ...
As you can see it has:
Created a new dev
folder in the root of the project directory.
The two <script>
elements originally defined in project/src/index.html
have been substituted in the newly generated project/dev/index.html
with a single <script>
tag as follows:
<script src="js/bundle.min.js"></script>
Both files; project/src/js/a.js
and project/src/js/b.js
, have been concatenated and minified in the resultant project/dev/js/bundle.min.js
.
The following source map file has been generated; project/dev/js/bundle.min.js.map
. This file essentially maps back to the original project/src/js/a.js
and project/src/js/b.js
files.
Running the following command via the command line:
grunt dist
outputs the following additional assets to the project directory:
project
├── ...
├── dist
│ ├── index.html
│ └── js
│ └── bundle.min.js
└── ...
As you can see this time it has;
Created a dist
folder in the root of the project directory.
Again, the two <script>
elements originally defined in project/src/index.html
have been substituted in the newly generated project/dist/index.html
with a single <script>
tag (as per the aforementioned dev
Task).
Again, both files; project/src/js/a.js
and project/src/js/b.js
, have been concatenated and minified in the resultant project/dist/js/bundle.min.js
.
However, the main notable difference is that NO source map file has been created.
Running the following command via the command line:
grunt
will produce both the outputs defined in the previous steps 1 and 2.
Upvotes: 3