How can I tell grunt-usemin to ignore Django's static template tags?

angularjs, django, django-templates, grunt-usemin, gruntjs

Solution

Alright, I think I have a workaround. This is assuming you want the built file to also point to the static url for the built assets.

This will require you to define a STATIC_URL on your view context (instead of using `src="{% static 'foo/bar.js' %}"` you'll use `src="{{STATIC_URL}}foo/bar.js"`). I couldn't get `{% static %}` to work without hacking the grunt-usemin source.

So using your example, this:

<!-- build:js {{STATIC_URL}}scripts/scripts.js -->
<script src="{{STATIC_URL}}scripts/app.js"></script>
<script src="{{STATIC_URL}}scripts/controllers/main.js"></script>
<script src="{{STATIC_URL}}scripts/controllers/stats.js"></script>
<script src="{{STATIC_URL}}scripts/directives/highchart.js"></script>
<!-- endbuild -->

Compiles down to:

<script src="{{STATIC_URL}}scripts/scripts.js"></script>

In order to achieve this, I had to add the following grunt configurations (in Gruntfile.js):

// custom createConfig script for replacing Django {{STATIC_URL}} references
// when building config for concat and cssmin
var path = require('path');
function createDjangoStaticConcatConfig(context, block) {
  var cfg = {files: []};
  var staticPattern = /\{\{\s*STATIC_URL\s*\}\}/;

  block.dest = block.dest.replace(staticPattern, '');
  var outfile = path.join(context.outDir, block.dest);

  // Depending whether or not we're the last of the step we're not going to output the same thing
  var files = {
    dest: outfile,
    src: []
  };
  context.inFiles.forEach(function(f) {
    files.src.push(path.join(context.inDir, f.replace(staticPattern, '')));
  });
  cfg.files.push(files);
  context.outFiles = [block.dest];
  return cfg;
}


grunt.initConfig({
    /*...*/

    // add a preprocessor to modify the concat config to parse out {{STATIC_URL}} using the above method
    useminPrepare: {
      html: 'app/index.html',
      options: {
        dest: 'dist',
        flow: {
          steps: {
            js: [
              {
                name: 'concat',
                createConfig: createDjangoStaticConcatConfig
              },
              'uglifyjs'
            ],
            // also apply it to css files
            css: [
              {
                name: 'cssmin',
                createConfig: createDjangoStaticConcatConfig
              }
            ]
          },
          // this property is necessary
          post: {}
        }
      }
    },

    // add a pattern to parse out the actual filename and remove the {{STATIC_URL}} bit
    usemin: {
      html: ['dist/{,*/}*.html'],
      css: ['dist/styles/{,*/}*.css'],
      options: {
        assetsDirs: ['dist'],
        patterns: {
          html: [[/\{\{\s*STATIC_URL\s*\}\}([^'"]*)["']/mg, 'django static']]
        }
      }
    },


    // if you are using bower, also include the jsPattern to automatically 
    // insert {{STATIC_URL}} when inserting js files
    'bower-install': {
      app: {
        html: 'app/index.html',
        jsPattern: '<script type="text/javascript" src="{{STATIC_URL}}{{filePath}}"></script>'
      }
    }
});

Problem

I'm building a Django app that serves a single page Angular app. Django serve's Angular's index.html which has the following usemin script block: ``` <!-- build:js scripts/scripts.js --> <script src="{% static "scripts/app.js" %}"></script> <script src="{% static "scripts/controllers/main.js" %}"></script> <script src="{% static "scripts/controllers/stats.js" %}"></script> <script src="{% static "scripts/directives/highchart.js" %}"></script> <!-- endbuild --> ``` Usemin tries to find "{% static "scripts/app.js" %}" on the filesystem and of course fails because what it should really be trying to find is "scripts/app.js". Has anyone seen a workaround for this?

Original source