CSS cache update and CDNs - html

When I develop web applications, I'm used to add a ?ver=XXX at the end of my CSS URIs.
I'm updating a wordpress theme and I found a filter that removes any ?ver= from "static ressources" :
add_filter( 'script_loader_src', 'mb_remove_script_version', 15, 1 );
add_filter( 'style_loader_src', 'mb_remove_script_version', 15, 1 );
Searching the web I found that without removing thoses ver=, CDN may not work and do not cache the CSS files ! That's a big surprise to me as I used it everywhere.
I use this version to force browsers to update their cache when I modify the CSS (by versionning up).
How do you force browser to understand the file must be downloaded again without using a ver= ?
--
Thank you
Nicolas.

You can use a tool such as Grunt (or gulp) to rev your assets:
https://www.npmjs.com/package/grunt-wp-assets
https://www.npmjs.com/package/gulp-rev

Thank to your answers, here is the full answer :
In my theme there is this file "theme-functions.php" in the ~theme/lib directory.
This is the file that loads the css file using the enqueue_style function :
wp_enqueue_style( '_mbbasetheme-style', get_template_directory_uri() . '/style.min.css' );
Using grunt as suggested, I was able to achieve the following steps :
Compass the SASS file and make a unique css file ==> style.css
Minify my unique css file to make it lighter ==> style.min.css
Version my css file to make a unique file name ==> style.4c72.min.css
These steps use the following grunt-plugins :
grunt-contrib-compass : with this grunt rule in Gruntfile.js
compass: {
dist: {
options: {
config: 'config.rb'
}
}
},
grunt-contrib-cssmin : with this grunt rule in Gruntfile.js
cssmin: {
options: {
keepSpecialComments: 1
},
minify: {
expand: true,
cwd: '',
src: ['*.css', '!*.min.css'],
dest: '',
ext: '.min.css'
}
},
grunt-wp-assets : with this grunt rule in Gruntfile.js
version: {
assets: {
options: {
algorithm: 'sha1',
length: 4,
format: false,
rename: false,
minify: true,
manifest: 'manifest.json'
},
files: {
'lib/theme-functions.php': ['style.min.css']
}
}
},
As you can see, the last one takes a file in argument to update the reference to the css file. After the grunt execution (actually a grunt-contrib-watch rule), the theme-functions.php is updated to :
wp_enqueue_style( '_mbbasetheme-style', get_template_directory_uri() . '/style.4c72.min.css' );

Related

kagnax/html-minifier grunt plugin how to use multiple targets

I am trying to use html-minifier grunt plugin (https://github.com/gruntjs/grunt-contrib-htmlmin) and the documentation says we can use multiple targets; That is, we can specify different options for different build environment. In the below example 2 targets are configured 'dist' and 'dev'
grunt.initConfig({
htmlmin: {
dist: {
options: {
removeComments: true,
collapseWhitespace: true
},
files: {
'dist/index.html': 'src/index.html'
}
},
dev: {
files: {
'dist/index.html': 'src/index.html'
}
}
}
});
But my question is, while using grunt how can I instruct the plugin to use specific target? For example, for a production build I want to use "dist" target specified in plugin config. I can do grunt htmlmin but it triggers 'dev' target only.

grunt-contrib-cssmin: css source map appears empty in dev tools

I am using grunt with cssmin to minify and concatenate css files.
Css files are well concatenated and minified but when I try to watch the non minified files in chrome dev tools under 'Sources' tab, files appears empty.
Here is my cssmin task:
cssmin: {
options: {
report: 'gzip',
keepSpecialComments: 0,
sourceMap: true,
outputSourceFiles: true
},
target: {
files: {
'web/assets/dist/css/vendors.min.css': [
'bower_components/bootstrap/dist/css/bootstrap.min.css',
'bower_components/chosen/chosen.min.css',
'bower_components/slabText/css/slabtext.css',
'bower_components/video.js/dist/video-js.css',
'bower_components/video.js/dist/video-js.css'
],
'web/assets/dist/css/app.min.css': [
'app/Resources/assets/css/jumbotron-narrow.css',
'app/Resources/assets/css/custom.css',
],
}
}
},
Source map setting is enabled under chrome.
web/assets/dist/css/app.min.css.map looks like this:
{
"version":3,
"sources":["app/Resources/assets/css/jumbotron-narrow.css","app/Resources/assets/css/custom.css"],
"names":[],
"mappings":"AAeA,QAdA,KAeI,eAAgB,KADpB,QA6BA,WAEI,cAAe,IAAI,MAAM,QA7C7B,KACI,YAAa,KCUb,YAAa,eAAkB,WDHnC,QAFA,QACA,WAEI,cAAe,KACf,aAAc,KASlB,WACI,WAAY,EACZ,cAAe,EACf,YAAa,KAIjB,QACI,YAAa,KACb,MAAO,KACP,WAAY,IAAI,MAAM,QAI1B,yBACI,WACI,UAAW,OAGnB,qBACI,OAAQ,KAAK,EAIjB,WACI,WAAY,OAGhB,gBACI,QAAS,KAAK,KACd,UAAW,KAIf,WACI,OAAQ,KAAK,EAEjB,gBACI,WAAY,KAIhB,oCAII,QAFA,QACA,WAEI,cAAe,EACf,aAAc,EAGlB,QACI,cAAe,KAGnB,WACI,cAAe,GC3EvB,WACI,YAAa,eACb,IAAK,iCAAkC,mBAG3C,WACI,YAAa,YACb,IAAK,8BAA+B,mBAOxC,GACI,WAAY,KACZ,eAAgB,UAChB,YAAa,EACb,YAAa,YAAe,WAC5B,YAAa,EAAI,EAAI,IAAI,KAG7B,4BACI,QAAS,MACT,YAAa,KACb,aAAc,KACd,cAAe,IAGnB,UACI,UAAW,MACX,WAAY,KAIhB,oBACI,MAAO,IAGX,sBACI,gBAAiB,KACjB,YAAa,EAGjB,cACI,aAAc,QAIlB,iCACI,QAAS"
}
Version from my package.json:
"grunt-contrib-cssmin": "^0.12.0",
What am I doing wrong?
Edit: Firstly, try specifying a root in your options of the Gruntfile.js as follows:
// ...
cssmin: {
options: {
// ...
root: 'web/assets/dist/css/' // <-- Add this too.
},
target: {
// ...
}
/...
The Issue
The sourceMap file that grunt-contrib-cssmin is generating is incorrectly specifying the paths in the sources Array. The resultant sourceMap should be as follows:
app.min.css.map
{
"version":3,
"sources":[
"../../../../app/Resources/assets/css/jumbotron-narrow.css",
"../../../../app/Resources/assets/css/custom.css"
],
"names":[],
"mappings":"AAeA,QAdA,KAeI,eAAgB,KADpB,QA6BA,WAEI,cAAe,IAAI,MAAM,QA7C7B,KACI,YAAa,KCUb,YAAa,eAAkB,WDHnC,QAFA,QACA,WAEI,cAAe,KACf,aAAc,KASlB,WACI,WAAY,EACZ,cAAe,EACf,YAAa,KAIjB,QACI,YAAa,KACb,MAAO,KACP,WAAY,IAAI,MAAM,QAI1B,yBACI,WACI,UAAW,OAGnB,qBACI,OAAQ,KAAK,EAIjB,WACI,WAAY,OAGhB,gBACI,QAAS,KAAK,KACd,UAAW,KAIf,WACI,OAAQ,KAAK,EAEjB,gBACI,WAAY,KAIhB,oCAII,QAFA,QACA,WAEI,cAAe,EACf,aAAc,EAGlB,QACI,cAAe,KAGnB,WACI,cAAe,GC3EvB,WACI,YAAa,eACb,IAAK,iCAAkC,mBAG3C,WACI,YAAa,YACb,IAAK,8BAA+B,mBAOxC,GACI,WAAY,KACZ,eAAgB,UAChB,YAAa,EACb,YAAa,YAAe,WAC5B,YAAa,EAAI,EAAI,IAAI,KAG7B,4BACI,QAAS,MACT,YAAa,KACb,aAAc,KACd,cAAe,IAGnB,UACI,UAAW,MACX,WAAY,KAIhB,oBACI,MAAO,IAGX,sBACI,gBAAiB,KACjB,YAAa,EAGjB,cACI,aAAc,QAIlB,iCACI,QAAS"
}
Note the sourceRoot prefixes ../../../../ added to each path in the sources Array.
In the SourceMap Specification a section reads:
Resolving Sources
If the sources are not absolute URLs after prepending of the “sourceRoot”, the sources are resolved relative to the SourceMap (like resolving script src in a html document).
If specifying a root path, (as initially mentioned), does not resolve the issue then it indicates that this part of the specification is not being honoured by grunt-contrib-cssmin.
Alternate Solution
If the initial suggested fix does not work then consider adding a custom Task to invoke a Function which fixes each sources path after the sourceMap(s) have been created by grunt-contrib-cssmin.
You could do something like this:
Gruntfile.js
module.exports = function (grunt) {
grunt.initConfig( {
cssmin: {
options: {
report: 'gzip',
keepSpecialComments: 0,
sourceMap: true,
outputSourceFiles: true
},
target: {
files: {
'web/assets/dist/css/vendors.min.css': [
'bower_components/bootstrap/dist/css/bootstrap.min.css',
'bower_components/chosen/chosen.min.css',
'bower_components/slabText/css/slabtext.css',
'bower_components/video.js/dist/video-js.css'
],
'web/assets/dist/css/app.min.css': [
'app/Resources/assets/css/jumbotron-narrow.css',
'app/Resources/assets/css/custom.css'
]
}
}
}
});
/**
* Helper function prefixes sources paths in sourceMap files with a sourceRoot.
*
* `grunt-contrib-cssmin` does not apply the correct sourceRoot for each
* path in the `sources` Array. See github issue #248 for further info:
* (https://github.com/gruntjs/grunt-contrib-cssmin/issues/248)
*
* #param {String} filePath - The path to the sourceMap to fix.
* #param {String} sourceRootPrefix - The sourceRoot prefix e.g. ../../
*/
function prefixSourceMap(filePath, sourceRootPrefix) {
var json = grunt.file.readJSON(filePath);
json.sources = json.sources.map(function (_path) {
return sourceRootPrefix + _path;
});
grunt.file.write(filePath, JSON.stringify(json));
}
// Register Task to invoke function for fixing paths in each sourceMap file.
grunt.registerTask('fixSourceMaps', 'Fix paths in each sourceMap', function () {
prefixSourceMap('web/assets/dist/css/vendors.min.css.map', '../../../../');
prefixSourceMap('web/assets/dist/css/app.min.css.map', '../../../../');
});
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.registerTask("default", [
'cssmin',
'fixSourceMaps' // <-- Must be after cssmin tasks.
]);
};
Notes
The the custom grunt.registertask named fixSourceMaps invokes the prefixSourceMap function for each sourceMap file to fix.
Two arguments are passed to the prefixSourceMap function, namely:
filePath - The path to the sourceMap to fix.
sourceRootPrefix - The sourceRoot prefix e.g. ../../
For fixing both sourceMap files (vendors.min.css.map and app.min.css.map) the sourceRootPrefix argument is specified as ../../../../ - This is specified as four levels due to the relationship between the resultant .min.css file and it's location to the original unminified source .css file within your directory structure.
If you were to add another set of .css files to minify to your cssmin.target.files Task, in which the relationship between the resultant .min.css file and the unminified source .css file was not four levels, you will need to specify a different sourceRootPrefix value.
For example, lets say in cssmin.target.files the following css is to be minified:
// ...
target: {
files: {
//...
'web/assets/quux.min.css': [ // <-- Two levels deep
'path/to/file/foo.css',
'path/to/file/baz.css'
],
// ...
}
}
// ...
As the resultant quux.min.css is saved in the directory two levels deep then the sourceRootPrefix argument is passed to the prefixSoureMap functions as '../../'. For example:
//...
grunt.registerTask('fixSourceMaps', 'Fix paths in each sourceMap', function () {
prefixSourceMap('web/assets/quux.min.css.map', '../../');
//...
});
//...
as explained in comment above, there was 2 issues in my Gruntfile :
missing root directive as explained by #RobC
original assets were not accessible by the webserver, so I moved them in a location under the web root of my virtualhost. In my case web/assets. Here is my cssmin task that is now working:
cssmin: {
options: {
root: 'web/assets/dist/css/',
report: 'gzip',
keepSpecialComments: 0,
sourceMap: true,
outputSourceFiles: true
},
target: {
files: {
'web/assets/dist/css/app.min.css': [
'web/assets/css/jumbotron-narrow.css',
'web/assets/css/custom.css',
],
}
}
},

Grunt and grunt-contrib-uglify - Sources outside of localhost

Question Part 1
In my current setup, I have a folder that looks like this:
/wwwroot <-- Hosted in localhost
/_project <-- Contains gruntfile.js
/_dev <-- Contains Source Code
The wwwroot folder is hosted in XAMPP and open in my browser. The _project folder contains my gruntfile.js, and _dev contains all the JS and SCSS that is compiled into JS and CSS by Grunt.
This has worked fine for a year or two, but recently, I updated my packages, and the generated sourcemaps have begun breaking. Chrome shows a blank code panel in Sources, and Firefox Dev displays a 404 error's HTML in the sources code panel. The sources were now being looked for inside the /wwwroot folder. Because of this, the sources 404 and aren't shown, and I can't use sourcemap debugging which I rely on.
Relevant parts of Gruntfile:
uglify: {
common: {
options: {
mangle: false,
compress: true, // true or false or {}
preserveComments: 'all', // true or 'all' or 'some'
sourceMap : true
},
files: {
// '../wwwroot/Content/includes/js/libs.js': ['../_dev/js/common/libs/*.js'],
'../wwwroot/Content/includes/js/buildbar.js': ['../_dev/js/common/buildbar/*.js'],
'../wwwroot/Content/includes/js/framework.js': ['../_dev/js/common/framework/*.js'],
}
},
}
Short of painfully rearranging my directory structure... how can I fix this?
Question part 2:
I've tried using grunt-uglify-contrib's sourceMapRoot option as follows:
uglify: {
common: {
options: {
mangle: false,
compress: true, // true or false or {}
preserveComments: 'all', // true or 'all' or 'some'
sourceMap : true,
sourceMapRoot: "C:/Users/quint/Documents/Github/build-siteengine/a/a/a/a"
},
files: {
// '../wwwroot/Content/includes/js/libs.js': ['../_dev/js/common/libs/*.js'],
'../wwwroot/Content/includes/js/buildbar.js': ['../_dev/js/common/buildbar/*.js'],
'../wwwroot/Content/includes/js/framework.js': ['../_dev/js/common/framework/*.js'],
}
},
}
For some reason, though, the paths that show in the Sources panel in Firefox Dev are missing four directories, hence why I've added the /a/a/a/a. Why would this be happening?
This also doesn't solve my problem, since in Firefox Dev clicking on the line numbers open the file in the browser and don't take me to the line of code in the debugger, and in Chrome there is no effect.

-sass-debug-info at my css

I'm working on a code with css and I found every class wrote before it
#media -sass-debug-info{filename{font-family:file\:\/\/C\:\/www\/w-balls-html\/html_source\/lib\/_master\.scss}line{font-family:\00003640}}
I found the at the doc of saas something about it
- ({#to_s => #to_s}) debug_info
A hash that will be associated with this rule in the CSS document if the :debug_info option is enabled. This data is used by e.g. the FireSass Firebug extension.
Returns:({#to_s => #to_s}) [debug-info-documentation][1]
but couldn't know how to debug it or know how to convert to the normal #media
#media all and (max-width: 699px) and (min-width: 520px))
If you are using Grunt to run your application, you can edit the Gruntfile.js file. You are looking for the Compass section. I found it around line 175. In that section you want to modify the the Server debugInfo to false.
// Compiles Sass to CSS and generates necessary files if requested
compass: {
options: {
sassDir: '<%= yeoman.app %>/styles',
cssDir: '.tmp/styles',
generatedImagesDir: '.tmp/images/generated',
imagesDir: '<%= yeoman.app %>/images',
javascriptsDir: '<%= yeoman.app %>/scripts',
fontsDir: '<%= yeoman.app %>/styles/fonts',
importPath: './bower_components',
httpImagesPath: '/images',
httpGeneratedImagesPath: '/images/generated',
httpFontsPath: '/styles/fonts',
relativeAssets: false,
assetCacheBuster: false,
raw: 'Sass::Script::Number.precision = 10\n'
},
dist: {
options: {
generatedImagesDir: '<%= yeoman.dist %>/images/generated'
}
},
server: {
options: {
debugInfo: false
}
}
},
By changing the option to false you will not have the debug info in the file. I recommend that you leave the debug info while in development. When the site is finished and ready for production THEN remove the debug info.
Lastly, this will not remove the comments out of the CSS file. You may notice that Compass inserts a location comment at the beginning of each selector. (See below)
/* line 19, ../../bower_components/bootstrap-sass-official/assets/stylesheets/bootstrap/_normalize.scss */
body { margin: 0; }
In order to remove that you will need to use Minification. Grunt can also take care of that. You will need to make sure the Gruntfile.js is configured. (I found mine to be commented out with // before every line. I had to remove those lines) After that just run
grunt cssmin
These 2 steps took a 475 KB CSS file down to 110 KB.
Hope this helps!
I was trying to figure out how to use that information myself to edit the original SASS files and learned that it is used for developing using a FireSASS plugin.
If you want human readable debug line number you want the noLineComments grunt setting, like so:
debug: {
options: {
watch: false,
outputStyle: 'expanded',
debugInfo: false, // this generates browser debug info, not human friendly
noLineComments: false, // human friendly debug comments
}
},
Which will spit out something like:
/* line 18, ../../sass/config/_font-icons.scss */
[class^="icon"],
[class*=" icon"] {
font-family: "HW Icon Font";
font-weight: normal;
font-style: normal;
text-decoration: inherit;
-webkit-font-smoothing: antialiased;
}

Gruntfile to minify all HTML files of a folder?

I’m using https://github.com/jney/grunt-htmlcompressor to compress HTML files. But it’s requiring me to manually type-in all the HTML files which I want minified:
grunt.initConfig({
htmlcompressor: {
compile: {
files: {
'dest/index.html': 'src/index.html'
},
options: {
type: 'html',
preserveServerScript: true
}
}
}
});
Is there a way to specify that I want to minify all HTML files of the entire folder (and subfolders)?
Or, in case this html-compressor is limited, are you aware of a different npm package that does this HTML mification?
The glob pattern should be allowed for any grunt task by default. Then simply use dynamic files to build each one to your dest
Instead of:
files: {
'dest/index.html': 'src/index.html'
},
Go with:
files: [
{
expand: true, // Enable dynamic expansion.
cwd: 'src/', // Src matches are relative to this path.
src: ['**/*.html'], // Actual pattern(s) to match.
dest: 'dest/', // Destination path prefix.
},
],
As far as another plugin I would recommend grunts contrib version since it's more common and maintained by the grunt team.