Cache files using Grunt task. - caching

I encountered the following code when reading a project's gruntfile.js , as the comment indicates, the code is used for Renames files for browser caching purposes, but how? What will be the new names for those files?
// Renames files for browser caching purposes
rev: {
dist: {
files: {
src: [
'<%= config.dist %>/assets/js/{,*/}*.js',
'<%= config.dist %>/assets/css/{,*/}*.css',
'<%= config.dist %>/images/{,*/}*.*',
'<%= config.dist %>/styles/fonts/{,*/}*.*',
'<%= config.dist %>/*.{ico,png}'
]
}
}
},

You appear to be using grunt-rev based upon the Gruntfile.js snippet.
As the project GitHub page describes, the rev task will change file names so that browsers are forced to download fresh copies (as opposed to use stale cached copies).
In the project docs on 'Basic Asset Revving', you'll see that the task simply renames the file to an eight character hash. In the docs, they give the example of js/9becff3a.app.js.
Thus, each time you run a grunt task that includes the revving, a new set of 'cache-busting' file names will be generated using the 8-character hashed rename.

Related

Laravel Mix and SASS changing font directory

I'm using Laravel 5.4 and Laravel Mix to output SASS files.
In my font definitions I'm configuring them so that when the CSS is output it will point to files such as public/assets/fnt/font-name/filename.ext but the processor changes the output so that it will instead point to public/fonts/filename.ext. Is there a way to stop it from changing the output paths?
It makes little sense to me that it would do something like this by default.
Edit
I've seen that the defaults they're using in Mix are the culprit:
module.exports.module = {
rules: [
// ...
{
test: /\.(woff2?|ttf|eot|svg|otf)$/,
loader: 'file-loader',
options: {
name: 'fonts/[name].[ext]?[hash]',
publicPath: '/'
}
}
]
};
I've tried using null-loader instead of file-loader but instead it causes it to fail because it can't find the files in node_modules which is not where it should be looking in the first place.
Removing the rule in question results in a flood of errors from trying to open and evaluate the font files in question:
error in ./public/assets/fnt/fanfare-jf/fanfare-jf.ttf
Module parse failed: DIRECTORY\public\assets\fnt\fanfare-jf\fanfare-jf.ttf Unexpected character '' (1:0)
You may need an appropriate loader to handle this file type.
(Source code omitted for this binary file)
# ./~/css-loader!./~/postcss-loader!./~/resolve-url-loader!./~/sass-loader?sourceMap&precision=8!./resources/assets/sass/app.scss 6:2525-2590
# ./resources/assets/sass/app.scss
# multi ./resources/assets/js/app.js ./resources/assets/sass/app.scss
I can at least add emitFiles: false to options to prevent it from making copies of the file, but the paths are still being altered.
I ended up with the following configuration to at least get it to a working state.
let assetDir = 'assets/build';
mix.config.fileLoaderDirs.fonts = `${assetDir}/${mix.config.fileLoaderDirs.fonts}`;
mix.config.fileLoaderDirs.images = `${assetDir}/${mix.config.fileLoaderDirs.images}`;
mix.sass('resources/sass/app.scss', `public/${assetDir}/css`)
.js('resources/js/app.js', `public/${assetDir}/js`);
Updated:
In newer versions this has been made customizable via mix.options() and can be adjusted as below:
let assetDir = 'assets/build';
mix.options({
fileLoaderDirs: {
images: `${assetDir}/img`,
fonts: `${assetDir}/fonts`
}
});
// adjust build commands accordingly, for example:
mix.js('resources/js/app.js', `public/${assetDir}/js`);
The output you got is the intended behaviour due to your configuration.
You are using this configuration to load the file:
options: {
name: 'fonts/[name].[ext]?[hash]',
publicPath: '/'
}
Which says use the publicPath as public and create a file with the name fonts/[name].[ext]?[hash] and webpack knows about what these symbols '/', '.', '?' in the name do.
It just looks for the fonts directory and if there is no any fonts directory it creates a new one and place the files into that directory.
So, you need to use this configuration for your folder structure:
options: {
name: 'assets/fnt/font-name/[name].[ext]?[hash]',
publicPath: '/'
}
This should work for your configuration.
More on file-loader configuration:
https://github.com/webpack-contrib/file-loader#filename-templates
Edit:
Since Laravel Mix uses Webpack in it's background and Webpack doesn't have any knowledge of the fonts file when there is no any appropriate loader added to the configuration. So, the error:
Module parse failed: DIRECTORY\public\assets\fnt\fanfare-jf\fanfare-jf.ttf Unexpected character '' (1:0)
You may need an appropriate loader to handle this file type.
is occurred.
You need to tell the Webpack to load the fonts to your desired directory and the fonts linked in your SASS file will be linked by the Webpack without any more configurations.

Project file structure, how to reduce SASS compilation time in compass when you have a lot of pages?

For a project I am using SASS 3.2.19 and Compass 0.12.5 combined with the last version of Grunt.
My file structure looks like this :
styles/
css/
page1.css
page2.css
page3.css
...
sass/
page1.scss
page2.scss
page3.scss
...
generics/
_general.scss
_menu.scss
_ie.scss
...
partials/
_sectionBegin.scss
_sectionClients.scss
...
In each pages{number}.scss file I import the scss blocks I actually need like this :
#import "generics/general"; // inside this file _ie.scss is imported
#import "generics/menu";
#import "partials/sectionBegins";
#import "partials/sectionClients";
.additionalStyles {
background: url(/example/example-cover.jpg) no-repeat;
}
And finally, here is my Gruntfile.js :
compass: {
dev: {
options: {
sassDir: ['styles/sass'],
cssDir: ['styles/css'],
outputStyle: 'expanded',
noLineComments: true,
environment: 'development'
}
},
...
grunt.registerTask('default', ['compass:dev' , 'watch']);
So, what I am doing here is setting Grunt to watch the sass/ repository. As soon as it detects some changes the page.css will be overwrite.
Well, this project structure actually works perfectly when there are only a few pages but now that I have more than 40 pages the compilation time is taking approximately 1min.
Indeed supposed that I edit a .scss file which is used by all the pages, all the pages will have to be overwritten.
So, what I am missing here ? How can I improve my project file structure and do you have some good examples of a gruntfile conf in a similar scenario ?
We also have a Sass project with a lot of partials. We still haven't figured out what to do when modifying a partial that is used by a lot of .scss files; there really isn't a way to get around having to compile all of them (eventually, when you deploy; sometimes you're only working on one page and really do only need one to compile in the short term). You could set up grunt tasks to compile each of your pages individually so you at least have something to run when you only need to compile a single .scss file.
The best thing to do in your case might be to think outside the box here...what if that partial WASN'T required by a lot of .scss files? What if it was only imported into one main.scss file that compiled into a minified main.css that was included on every page of your project (as the first script on the page, so its styles would get overwritten by any more specific page styles)? We have one script that includes our generic styles for things like buttons, forms, panels...stuff that's on pretty much every page, and isn't too large a burden to load in on pages that don't have a form or a button, especially if minified.
For the cases where modifying a partial only needs to prompt compilation of a few Sass files, we have figured out a solution using the Gruntfile. You can use grunt-contrib-watch to run different tasks depending on where a change was detected. For example, we have the following 2 tasks set up for grunt-contrib-sass:
sass: {
dev_mainstyles: {
options: {
sourcemap: true,
trace: true,
style: 'expanded',
compass: true,
lineNumbers: true
},
files: {
'...css/main.css': '...sass/main.scss',
},
},
dev_customerstyles: {
options: {
sourcemap: true,
trace: true,
style: 'expanded',
compass: true,
lineNumbers: true
},
files: [{
expand: true,
cwd: '.../sass/',
src: ['customers/**/*.scss'],
dest: '.../css/',
ext: '.css'
}],
},
}
I have set up the following tasks for grunt-contrib-watch:
watch: {
sassmain: {
files: ['.../sass/*.scss'],
tasks: ['sass:dev_mainstyles'],
},
sasscustomers: {
files: ['.../sass/customers/**/*.scss'],
tasks: ['sass:dev_customerstyles'],
},
}
By listing both files and directories you can get as specific as you need to and hopefully you'll be able to set up watch tasks that only compile what is needed whenever something changes! Good luck!
We're still looking for suggestions on how to make this whole process even faster, by the way, this is by no means a definitive answer, it's just some tricks we've figured out so far.

Grunt-contrib-compass: Unclear configuration error while trying to work with 2 projects

I am trying to get use of great David Hererra's advice on how to use grunt-contrib-compass with Wordpress parent and child themes. You can find his tutorial here: https://gist.github.com/dlh01/5726683
But to my question: I have 2 projects (parent theme and child theme) with 2 different importPaths. My gruntfile.js for both of them is sitting on the root of my web project. I am receiving following error:
Nothing to compile. If you're trying to start a new project, you have left off the directory argument.
I'm not entirely sure what the error means - there is no "directory argument" in plugin documentation. Although I am sure I must be missing something obvious. :) Here goes the relevant part of my gruntfile.js:
compass: {
options: {
// Directories
sassDir: 'sass/dev/',
imagesDir: 'img/public/',
javascriptsDir: 'js/public/',
fontsDir: 'font/',
// Options
environment: 'development',
outputStyle: 'expanded',
//relativeAssets: true
},
parent: {
options: {
importPath: 'web/app/themes/wpgrouse-theme-parent/assets/sass-parent/dev/',
httpPath: 'web/app/themes/wpgrouse-theme-parent/assets/',
cssDir: '/'
}
},
child: {
options: {
importPath: 'web/app/themes/wpgrouse-theme-parent/assets/sass/dev/',
httpPath: 'web/app/themes/lifeforce/assets/',
cssDir: '/'
}
}
},
I've tried various "voodoo" sollutions, but none of them work. After some jerking around in arguments, I've even received this:
RuntimeError on line 52 of /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/tempfile.rb: cannot generate tempfile `/style.css20140702-6925-1cg6d1c-9'
Can you shed a little light on what I am doing wrong? Thank you. Quick response would be very appreciated, as I am way behind my deadline and this is very frustrating. :)
Thanks, P!
Edit
It is also probably good to add, that when I was working with one project, everything went fine, so there must be a problem with the "2 projects configuration" part of my gruntfile.js I've posted here.
Edit 2
If I specify basePath argument under each project (parent and child) pointing to same directory as httpPath argument, I am receiving previously mentioned error about tempfile. Does this help?
While running 'grunt watch' and trying to force my sass to compile, I was also getting the error:
cannot generate tempfile `./.sass-cache/..."
It turned out to be a problem with my permissions settings on the server. I didn't have permission to write to the .sass-cache folder. All I had to do was run
sudo chmod -R 777 .sass-cache/
and the error went away!

Is it possible for Compass to output files to multiple locations from Grunt?

I have a SCSS build working from Grunt that takes files in a "build" directory and outputs them to a "deploy" directory.
Is it possible to split off a single file -- the primary CSS file -- and have it output not only to the deploy directory but also on to a production server? That's the only file that will be changed now that the site is live.
I know Capistrano can do something like this, but it's probably not worth it on our end to add more technology to the workflow. So is it possible within Grunt?
Rather than modify the configuration of your css generation task which could result in a second copy being compiled, you can utilize an additional entry under grunt-copy:
styles: {
expand: true,
dot: true,
cwd: 'deploy/styles',
dest: 'other/styles',
src: 'filename.css'
}
Take care that you aren't calling the entire copy task elsewhere in your Gruntfile, and when you call this instance you'll use 'copy:styles'.

grunt-contrib-imagemin output "Fatal error: ENOENT, no such file or directory"

The command grunt imagemin output the following to a random file.
Fatal error: ENOENT, no such file or directory 'app/public/assets/img/epg/recordseries.png'
What's funny is that each time I run the command grunt imagemin again, it manages to process a few more files and ends by outputting the same error about another file.
I'm using
node v0.10.24
npm 1.3.21
grunt#0.4.2
grunt-contrib-imagemin#0.5.0 node_modules/grunt-contrib-imagemin
+-- filesize#2.0.0
+-- async#0.2.9
+-- chalk#0.4.0 (has-color#0.1.2, ansi-styles#1.0.0, strip-ansi#0.1.1)
+-- image-min#0.1.2 (mkdirp#0.3.5, cache-file#0.1.2, mout#0.7.1, optipng-bin#0.3.1, jpegtran-bin#0.2.3, gifsicle#0.1.4)
Here is my grunt config for imagemin task:
grunt.config('imagemin', {
options: {
optimizationLevel: 3, // 0 to 7, default =7)
// pngquant: true
},
dynamic: { // Multiple target
files: [{
expand: true, // Enable dynamic expansion
cwd: '<%= context.source %>/assets/img/', // equal to app/wesource/assets/img/
src: ['!**/*-'+arrayToRegexStr(platformIgnoreList)+'**', '**/*.{png,jpg,jpeg,gif}'], // Actual patterns to match //
dest: '<%= context.public %>/assets/img/' // equal to app/public/assets/img/
}]
}
});
Uninstalling version 0.5.0 and going back to version 0.3.0 with the following commands should restore the prior functionality:
npm uninstall grunt-contrib-imagemin
npm install --save-dev grunt-contrib-imagemin#0.3.0
There is an issue, https://github.com/gruntjs/grunt-contrib-imagemin/issues/140, that is being worked on, and when it is fixed it should be safe to upgrade.
The following solutions works on...
Ubuntu Linux 13.10 x64
npm --version = 1.3.11
node --version = v0.10.21
grunt-contrib-imagemin = 0.5.0
This is a hack of a solution, but I found the task fails when it looks at the the target directory to see if the PNG image already exists and is optimized. The task would consistently finish when I ran it over and over, each time it would complete a few more images. And I could repeat the problem by running grunt clean, then grunt imagemin over and over.
The error I saw was:
bash
Fatal error: ENOENT, no such file or directory 'build-production/path-to/some-image.png'
Solution
Copy the images to the target dir immediately before optimizing them. This way, the check passes and unoptimized images that are copied are replaced by their optimized equivalent.
task
grunt.task.run(
'copy:imagemin',
'imagemin'
);
copy configuration
copy: {
imagemin: {
files: [{
expand: true,
cwd: '<%= exponential.client.src %>',
src: ['images/**/*.{png,jpg,gif}'],
dest: '<%= exponential.client.buildProduction %>'
}]
}
}
imagemin configuration
imagemin: {
buildProduction: {
files: [{
expand: true,
cwd: '<%= exponential.client.src %>',
src: ['images/**/*.{png,jpg,gif}'],
dest: '<%= exponential.client.buildProduction %>'
}]
}
}
Try to use
cache: false
worked for me.
I was able to solve the problem by uninstalling optipngthat I had accidentally installed system wide.
I had the same issue with grunt-contrib-imagemin and it was because I was running grunt with sudo.
My fix was to do a chown and a chmod on the entire structure then run grunt without sudo...
what worked for me was a clean install of the node modules
I remove the node_modules dir and did npm install
after that it worked again for me

Resources