Open monitorjbl opened 10 years ago
In other words: we want to manipulate the final imported assets uris, and not the ones generated before filerev. This way we can support our application at other contexts than root, for example.
For anyone else that is having this issue, here's a workaround. Specify your blockReplacement however you like (in this case, we had to prepend a JSP context root onto the outputted path):
grunt.initConfig({
config: {
root: 'src/main/webapp/'
},
usemin: {
html: ['<%= config.root %>/WEB-INF/{jsp,tags}/**/*.{jsp,jspf,tag}'],
options: {
blockReplacements: {
css: function (block) {
return '<link rel="stylesheet" href="${contextPath}' + block.dest + '"/>';
},
js: function (block) {
return '<script src="${contextPath}' + block.dest + '"></script>';
}
}
}
}
});
Then, create a custom task that also replaces the filerev map with the prefixed data. Note that you need to stick the prefix after the root path on the filesystem. In our case, it was src/main/webapp/
and it was configured in the config.root
property in grunt.initConfig
. Your case may be different, but you can use the same string replacement method that I'm using here:
grunt.registerTask('remapFilerev', function(){
var root = grunt.config().config.root;
var summary = grunt.filerev.summary;
var fixed = {};
for(key in summary){
if(summary.hasOwnProperty(key)){
var orig = key.replace(root, root+'${contextPath}/');
var revved = summary[key].replace(root, root+'${contextPath}/');
fixed[orig] = revved;
}
}
grunt.filerev.summary = fixed;
});
Finally, insert this task between filerev and usemin in your build task:
grunt.registerTask('build', ['default', 'useminPrepare', 'filerev', 'remapFilerev', 'usemin']);
Really hokey, and it took me a long time to figure out. Hopefully this issue gets fixed so you can just use the blockReplacement
method. On the plus side, I did get to learn about the excellent Node debugger.
@monitorjbl @leocwolter regarding the remapFilerev
implementation, are you trying to add a contextPath
to each revved assets ?
If this is the case, I think you should rewrite all you revved assets after the usemin process is complete using any grunt plugin like grunt-cdnify
.
Waiting for your answer.
The goal was to append the ${contextPath}
prefix to all referenced assets. In the application, this would be a JSP variable filled in at runtime with the absolute root path of the server.
Does your suggestion still apply? I'm not that familiar with other Grunt plugins.
@monitorjbl there are plugins like grunt-cdn or grunt-cdnify. The idea is to run the task after usemin task has completed.
@monitorjbl I do not want to say that's a better to use another plugin. Your solution to create your own grunt task is good too.
CC @sindresorhus what do you think about it ? CDN or rewriting assets with a base path/url, might not be usemin priority, but filerev give us a hasmap with all revved assets. Using another grunt plugin should be the way to go IMO, but these plugins seems to have some issues with parsing.
I encountered this issue as well while trying to use usemin with filerev in a Django project. I could use something like grunt-cdn
but I'd rather not. Django already handles linking to its static assets via the configured settings. Whether the static assets would eventually end up on S3, or on the server's file system should be handled by Django.
Basically, I want my grunt workflow to be agnostic about where the files will eventually end up being hosted. Though, my use case might just be too specific. That is, trying to use usemin for Django templates.
Ahh I just found this after posting a similar issue. I've attempted to use grunt-cdn
but it's not working out for me. Did anyone else come up with a reliable solution? I could definitely see this being a useful feature to incorporate some sort of build prefix.
After I spent 1.5 days fixing this problem, I thought I share my solution for the simplest usecase: I wanted to prepend the revved url paths with the cdn base url/the app's base url (for the local devenv).
module.exports = function( grunt ) {
var options = {
routes: {
'static': 'myapp/static',
'dist': 'myapp/dist',
'tmp': '.tmp'
},
paths: {
baseTemplateSource: 'myapp/templates/layout/base_src.html',
baseTemplateTarget: 'myapp/templates/layout/base.html',
baseTemplateStatic: 'myapp/static/base.html'
}
};
grunt.initConfig({
options: options,
usemin: {
html: ['<%= options.paths.baseTemplateStatic %>'],
css: ['<%= options.routes.dist %>/css/*.css'],
options: {
assetsDirs: ['<%= options.routes.dist %>', '<%= options.routes.dist %>/css'],
blockReplacements: {
css: function (block) {
var originalRevvedDest = grunt.filerev.summary[options.routes.dist + block.dest];
var customDest = originalRevvedDest.replace(options.routes.dist, '{{ STATIC_BASE_URL }}');
return '<link rel="stylesheet" href="' + customDest + '">'
},
js: function (block) {
var originalRevvedDest = grunt.filerev.summary[options.routes.dist + block.dest];
var customDest = originalRevvedDest.replace(options.routes.dist, '{{ STATIC_BASE_URL }}');
return '<script src="' + customDest + '"></script>';
}
}
}
}
});
};
(Note I'm serving my templates with Flask, so {{ STATIC_BASE_URL }}
is for jinja2, but can be replaced with url prefixes)
Luckily there's a PR waiting for reviewers: https://github.com/yeoman/grunt-usemin/pull/613
When using filerev before usemin, the output given to a
blockReplacements
function is the original filename instead of the filerev-adjusted file name (suffixed with a hash). To properly use this option, theblockReplacements
functions should be called after the filrev-linking has been done and the hashed filenames are available.