1

We have an AngularJS front end application where the backend is ASP.NET MVC used as an API. We have removed all controllers and views and depend primarily on AngularJS based HTML as views. What we need to do now is bundle our js and css, but we have no access to Razor syntax.

Since we don't have access to Razor, we need a way to bundle our JS and CSS files. How do we bundle those files without Razor?

4
  • That's a fair question. Not sure why anyone would downvote it. Although a bit of advice, I started off this way and quickly realized that mix & matching doesn't really work. Stick with Angular + WebAPI. Commented Oct 22, 2014 at 14:11
  • We are using those conventions, but is there a way to bundle without razor sytax, maybe a nuget package you can recommend, or just give up on the idea. Commented Oct 22, 2014 at 14:15
  • Answer: Just use Razor. Commented Oct 22, 2014 at 14:26
  • @SLaks I would argue that the answer is to remove Razor, entirely, but I agree with the sentiment - it should be all or none. Commented Oct 22, 2014 at 14:32

3 Answers 3

3

You're looking for ResolveBundleUrl, although keep in mind this needs to be generated by the server so you'll need to get Angular to make a request to get this URL so you won't be able to include Angular inside the bundle.

However, it's also possible to hardcode your bundle. Assuming you register like: new ScriptBundle("~/js/mybundle"):

<script src="/js/mybundle"></script>

Although you won't get the versioning included with the Razor implementation.

Finally, the whole ASP.NET MVC model doesn't offer a huge amount of benefits if already using Angular. You should move your Angular into a plain HTML project and use something like GruntJS to automate your bundling & minification. Then you can use WebAPI as the server-backend.

Sign up to request clarification or add additional context in comments.

2 Comments

This is true, you can access the bundle URL directly. The only thing you will be missing out on is the "Cache buster" query string that is generated by the razor helper. You may also have trouble when in Debug mode because the bundle won't be generated. See: tech.pro/tutorial/1411/bundling-and-minification-in-asp-net-mvc
see stackoverflow.com/a/34508048/1545567 to workaround the cache buster limitation from plain html
2

The major benefit to referencing Bundles in a view using Razor is the automatic creation of URLs to the bundle with a cache buster query string appended to it (so that when content of any of the files in the bundle change, the URL changes, and you don't need to worry about the client still referencing an older cached version of your bundle). A second benefit is that when debug=true (in web.config), it renders URLs directly to the items in the bundle.

You could, of course, just hardcode the path to the bundle in your plain HTML, but then you lose both of these features. I'm also not sure if it'll render the combined bundle if you go to the bundle URL when debug=true (meaning, it might not work when you are in debug mode on your dev machine).

What I'm getting at is that if you aren't using a Razor view for at least the initial page in your SPA (the page that bootstraps your Angular client), you're not going to find Bundles very useful.

If you forego Razor entirely, you may wish to use alternate ways of bundling assets (and updating references to the bundle in HTML). There are a number of ways, but the most popular involve using Grunt or Gulp build tasks, which run on Node.js. For example (using Grunt), see grunt-contrib-concat, grunt-contrib-uglify, grunt-rev, and grunt-usemin.

Here is a link using Grunt and a variety of the aforementioned tasks to accomplish all of the things Bundles do without using Bundles or Razor.

Brief summary of the article follows (your mileage may vary):

  1. Install Node.js
  2. Install Grunt CLI
  3. Create package.json (npm init can create this for you).
  4. Add requisite Grunt add-ons:

    "grunt": "~0.4.1",
    "grunt-contrib-concat": "~0.3.0",
    "grunt-contrib-uglify": "~0.2.7",
    "grunt-contrib-cssmin": "~0.7.0",
    "grunt-usemin": "~2.0.2",
    "grunt-contrib-copy": "~0.5.0",
    "grunt-rev": "~0.1.0",
    "grunt-contrib-clean": "~0.5.0"
    
  5. Create Gruntfile.js

    module.exports = function (grunt) {
    
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
    
        clean: ["dist", '.tmp'],
    
        copy: {
            main: {
                expand: true,
                cwd: 'app/',
                src: ['**', '!js/**', '!lib/**', '!**/*.css'],
                dest: 'dist/'
            },
            shims: {
                expand: true,
                cwd: 'app/lib/webshim/shims',
                src: ['**'],
                dest: 'dist/js/shims'
            }
        },
    
        rev: {
            files: {
                src: ['dist/**/*.{js,css}', '!dist/js/shims/**']
            }
        },
    
        useminPrepare: {
            html: 'app/index.html'
        },
    
        usemin: {
            html: ['dist/index.html']
        },
    
        uglify: {
            options: {
                report: 'min',
                mangle: false
            }
        }
    });
    
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-cssmin');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-rev');
    grunt.loadNpmTasks('grunt-usemin');
    
    // Tell Grunt what to do when we type "grunt" into the terminal
    grunt.registerTask('default', [
        'copy', 'useminPrepare', 'concat', 'uglify', 'cssmin', 'rev', 'usemin'
    ]);
    };
    
  6. Edit your index.html (or whatever your main app bootstrap page is) so your CSS and JS assets are properly decorated for usemin and rev:

     <!-- build:css css/app-name.min.css -->
     <link rel="stylesheet" href="lib/bootstrap/bootstrap.min.css"/>
     <link rel="stylesheet" href="lib/font-awesome/font-awesome.min.css"/>
     <link rel="stylesheet" href="lib/toaster/toaster.css"/>
     <link rel="stylesheet" href="css/app.css"/>
     <link rel="stylesheet" href="css/custom.css"/>
     <link rel="stylesheet" href="css/responsive.css"/>
     <!-- endbuild -->
     ...
     <!-- build:js js/app-name.min.js -->
     <script src="lib/jquery/jquery-1.10.2.min.js"></script>
     <script src="lib/bootstrap/bootstrap.min.js"></script>
     <script src="lib/angular/angular.min.js"></script>
     <script src="lib/angular/angular-animate.min.js"></script>
     <script src="lib/angular/angular-cookies.min.js"></script>
     <script src="lib/angular/angular-resource.min.js"></script>
     <script src="lib/angular/angular-route.min.js"></script>
     <script src="lib/fastclick.min.js"></script>
     <script src="lib/toaster/toaster.js"></script>
     <script src="lib/webshim/modernizr.min.js"></script>
     <script src="lib/webshim/polyfiller.min.js"></script>
     <script src="js/app.js"></script>
     <script src="js/services.js"></script>
     <script src="js/controllers.js"></script>
     <script src="js/filters.js"></script>
     <script src="js/directives.js"></script>
     <!-- endbuild -->
    

Now you have a Grunt build task that will look at your page for any asset blocks and concatenate/uglify the individual files referenced therein, and then replace the links in that block with one link to a single cache-busted file. This gets you what you had with Bundles.

During development, you don't need to do anything except add or remove assets from these blocks. For production, you just need to run your grunt build task before you package up or deploy your application.

1 Comment

If you're starting from scratch with JS task runners, you're better off with gulp or broccoli. Both have the same extent of plugin support at this point (including minification and revving), but are far better in terms of performance and programming paradigms.
0

Well the Razor syntax is used to run serverside code. That is in MVC mostly code located in the Controller classes.

Ask yourselves why you need MVC if you don't use the Controller / Model / View relationships.

1 Comment

We are using mvc in angular js, so the controllers and and view is all handled by angular js, we are using web apis to handle the get our models. We are trying to speed up the site, so we want to try bundling, without using razor sytax.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.