Adding CoffeeScript support for Grunt Delta? - gruntjs

I was able to edit my Gruntfile to process my CoffeeScript files using the grunt command by adding:
grunt.initConfig({
coffee: {
compile: {
options: {
bare: true,
join: true,
sourceMap: true
},
files: {
'src/coffee.js' : ['src/app/**/*.coffee', 'src/components/**/*.coffee']
}
}
},
...
But I can't seem to figure out how to add CoffeeScript processing to the Grunt Delta command as I don't want to have to manually "grunt" every time I make a change and test. My current delta file. Would love some direction on how to get the delta working with CoffeeScript.
delta: {
/**
* By default, we want the Live Reload to work for all tasks; this is
* overridden in some tasks (like this file) where browser resources are
* unaffected. It runs by default on port 35729.
*/
options: {
livereload: true
},
/**
* When the Gruntfile changes, we just want to lint it. That said, the
* watch will have to be restarted if it should take advantage of any of
* the changes.
*/
gruntfile: {
files: 'Gruntfile.js',
tasks: [ 'jshint:gruntfile' ],
options: {
livereload: false
}
},
/**
* When our source files change, we want to run most of our build tasks
* (excepting uglification).
*/
src: {
files: [
'<%= src.js %>'
],
tasks: [ 'jshint:src', 'karma:unit:run', 'concat:dist', 'ngmin:dist', 'uglify:dist' ]
},
/**
* When assets are changed, copy them. Note that this will *not* copy new
* files, so this is probably not very useful.
*/
assets: {
files: [
'src/assets/**/*'
],
tasks: [ 'copy' ]
},
/**
* When index.html changes, we need to compile just it.
*/
html: {
files: [ '<%= src.html %>' ],
tasks: [ 'index' ]
},
/**
* When our templates change, we only add them to the template cache.
*/
tpls: {
files: [
'<%= src.atpl %>',
'<%= src.ctpl %>'
],
tasks: [ 'html2js', 'concat:dist', 'ngmin:dist', 'uglify:dist' ]
},
/**
* When the CSS files change, we need to compile and minify just them.
*/
sass: {
files: [ 'src/**/*.scss' ],
tasks: 'compassCompile'
},
envs: {
files: [
'environment.json'
],
tasks: ['build']
},
/**
* When a unit test file changes, we only want to linit it and run the
* unit tests. However, since the `app` module requires the compiled
* templates, we must also run the `html2js` task.
*/
unittest: {
files: [
'<%= src.unit %>'
],
tasks: [ 'jshint:test', 'karma:unit:run' ],
options: {
livereload: false
}
}
}

This is what I came up with:
coffeesrc: {
files: [
'src/app/**/*.coffee', 'src/components/**/*.coffee'
],
tasks: [ 'coffee' ]
},
Seems to work.

Related

How to use array variable properly in gruntfile.js

Trying to use a predefined array inside of a grunt file, thought using this.js_paths would work, but doesn't seem to work as I'm getting the error, "Cannot read property IndexOf of undefined" when it comes to trying to uglify the scripts. How can I link the js_paths variable to the files src property properly instead of copying the array into the files. Would like to define it separately at the top. Is this possible?
module.exports = function(grunt) {
// loadNpmTasks from package.json file for all devDependencies that start with grunt-
require("matchdep").filterDev("grunt-*", './package.json').forEach(grunt.loadNpmTasks);
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
js_paths: [
'inc/header1/js/*.js',
'!inc/header1/js/*.min.js',
'inc/header2/js/*.js',
'inc/header2/js/*.js',
'!inc/header2/js/*.min.js',
'js/*.js',
'!js/*.min.js'
],
uglify: {
options: {
mangle: true
},
build: {
files: [{
expand: true,
src: this.js_paths,
rename: function(dst, src) {
return src.replace('.js', '.min.js');
}
}]
}
},
watch: {
scripts: {
files: ['inc/header1/js/*.js', 'inc/header2/js/*.js', 'js/*.js'],
tasks: ['uglify'],
options: {
spawn: false,
}
}
}
});
grunt.registerTask('default', ['uglify', 'watch']);
};
Preferrably would like to use the same array js_paths in the watch files (since it's required there), if that makes sense? Still kinda new to using gruntfile.js
Utilize the Templates syntax. It's described in the docs as following:
Templates
Templates specified using <% %> delimiters will be automatically expanded when tasks read them from the config. Templates are expanded recursively until no more remain.
Essentially, change this.js_paths to '<%= js_paths %>' in your uglify task.
For instance:
// ...
uglify: {
options: {
mangle: true
},
build: {
files: [{
expand: true,
src: '<%= js_paths %>', // <-----
rename: function(dst, src) {
return src.replace('.js', '.min.js');
}
}]
}
},
// ...
Likewise for your watch task too.
For instance:
watch: {
scripts: {
files: '<%= js_paths %>', // <-----
tasks: ['uglify'],
options: {
spawn: false,
}
}
}

Webpack CSS Output Is Always Minified

For my specific project, I need to control the minification of my CSS and only minify certain files. I am very close to a working solution using OptimizeCSSAssetsPlugin where I use the assetNameRegExp option to choose the CSS files I want to minify.
I have spent a while now trying to figure out why all my other CSS files are still being minified. It turns out that sass-loader will always minify your CSS when in production mode whether you want it to or not.
Here is my full webpack.config.js.
const CopyWebpackPlugin = require('copy-webpack-plugin');
const FixStyleOnlyEntriesPlugin = require('webpack-fix-style-only-entries');
const FractalWebpackPlugin = require('fractal-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const path = require('path');
const PrettierPlugin = require('prettier-webpack-plugin');
const StyleLintPlugin = require('stylelint-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
module.exports = (env, argv) => {
/**
* Determine if is production mode from the command executed
*/
const isProduction = argv.mode === 'production';
/**
* Common paths
*/
const paths = {
src: 'src',
dev: 'public',
prod: 'public'
};
/**
* Generate the settings for webpack depending on if it is
* development or production mode.
*/
const settings = {
mode: isProduction ? 'production' : 'development',
outputDir: isProduction ? paths.prod : paths.dev,
fractal: {
mode: isProduction ? 'build' : 'server',
sync: isProduction ? false : true
}
};
return {
// Mode is set by --mode property in command
mode: settings.mode,
/**
* 3 entries:
* designSystem: This is Design System UI specific CSS
* website: This is website & component specific CSS
* app: This is the website & component specific JS
*/
entry: {
/**
* Main website and Design System CSS files
*/
designSystem: path.resolve(__dirname, `./${paths.src}/theme/scss/theme.scss`),
website: path.resolve(__dirname, `./${paths.src}/scss/styles.scss`),
/**
* Specific enteries for all comonents to generate a CSS file specific to that component
*/
headings: path.resolve(__dirname, `./${paths.src}/patterns/01-branding/03-typography/02-headings/headings.scss`),
paragraphs: path.resolve(__dirname, `./${paths.src}/patterns/01-branding/03-typography/03-paragraphs/paragraphs.scss`),
inlineElements: path.resolve(__dirname, `./${paths.src}/patterns/01-branding/03-typography/04-inline-elements/inline-elements.scss`),
ordered: path.resolve(__dirname, `./${paths.src}/patterns/01-branding/03-typography/05-lists/ordered/ordered.scss`),
unordered: path.resolve(__dirname, `./${paths.src}/patterns/01-branding/03-typography/05-lists/unordered/unordered.scss`),
images: path.resolve(__dirname, `./${paths.src}/patterns/01-branding/06-images/images.scss`),
spacers: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/01-layout/02-spacers/spacers.scss`),
primaryButton: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/02-buttons/primary-button/primary-button.scss`),
secondaryButton: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/02-buttons/secondary-button/secondary-button.scss`),
tertiaryButton: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/02-buttons/tertiary-button/tertiary-button.scss`),
checkboxes: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/03-form-elements/checkboxes/checkboxes.scss`),
inputs: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/03-form-elements/inputs/inputs.scss`),
labels: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/03-form-elements/labels/labels.scss`),
radios: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/03-form-elements/radios/radios.scss`),
selects: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/03-form-elements/selects/selects.scss`),
textareas: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/03-form-elements/textareas/textareas.scss`),
footer: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/04-footer/footer.scss`),
navigation: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/05-navigation/navigation.scss`),
informationPanel: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/06-information-panel/information-panel.scss`),
informationPill: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/07-information-pill/information-pill.scss`),
modal: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/08-modal/modal.scss`),
/**
* Main website and Design System JS files
*/
app: [
'regenerator-runtime/runtime',
'core-js/modules/es6.array.from',
'core-js/modules/es6.array.for-each',
'core-js/modules/es6.object.assign',
'core-js/modules/es6.promise',
path.resolve(__dirname, `./${paths.src}/js/app.js`)
]
},
/**
* JS output goes into the scripts folder and depending on mode will
* either go into the public or the dist folder with it's chunks
*/
output: {
path: path.resolve(__dirname, `./${settings.outputDir}`),
filename: 'scripts/[name].js',
chunkFilename: 'scripts/[name].chunk.js'
},
module: {
rules: [
{
parser: {
amd: false
}
},
{
/**
* Load JS files with Babel Loader and set to transpile code to work
* in IE10 and above.
*/
test: /\.(js)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
configFile: './babel.config.js',
presets: [
[
'#babel/preset-env',
{
useBuiltIns: 'entry',
corejs: '^3.1.4',
targets: {
browsers: ['defaults, ie >= 10']
}
}
]
]
}
},
{
loader: 'eslint-loader',
options: {
configFile: '.eslintrc.json'
}
}
]
},
{
/**
* Load SASS files with 2 loaders
* PostCSS: This converts the SCSS to CSS, adds in polyfills for flexbox,
* auto prefixes and adds in normalise CSS.
* SASS Loader: This generates source maps for CSS.
*/
test: /\.(scss|sass)$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
{
loader: 'css-loader',
options: {
sourceMap: true
}
},
{
loader: 'postcss-loader',
options: {
plugins: () => [
require('postcss-flexbugs-fixes'),
require('postcss-preset-env')({
autoprefixer: {
flexbox: 'no-2009'
},
stage: 3
}),
require('autoprefixer')()
],
sourceMap: true,
minimize: false
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
minimize: false,
outputStyle: 'uncompressed'
}
}
]
},
{
/**
* This looks for all images and uses the File Loader to move them to
* the output directory. It excludes the fonts directory so there is no
* duplication of SVG files
*/
test: /\.(png|jpg|jpeg|gif|svg)$/,
exclude: /fonts/,
use: [
{
loader: 'file-loader',
options: {
name: '[folder]/[name].[ext]',
outputPath: '/images'
}
}
]
},
{
/**
* This looks for all font files and uses the File Loader to
* move hem to the output directory. It excludes the images directory
* so there is no duplication of SVG files
*/
test: /\.(woff|woff2|eot|ttf|otf|svg)$/,
exclude: /images/,
use: [
{
loader: 'file-loader',
options: {
name: '[folder]/[name].[ext]',
outputPath: '/fonts'
}
}
]
}
]
},
plugins: [
/**
* This prevents webpack from generating a JS file for SCSS entries
*/
new FixStyleOnlyEntriesPlugin(),
/**
* Runs SASS linting
*/
new StyleLintPlugin({
configFile: '.stylelintrc.json',
context: 'src',
files: '**/*.scss',
failOnError: false,
quiet: false,
emitErrors: true
}),
/**
* This outputs SCSS entires into CSS files and thier chunks
*/
new MiniCssExtractPlugin({
filename: 'style/[name].css',
chunkFilename: 'style/[name].chunk.css'
}),
/**
* Runs Fractal in either server mode for dev and build mode for
* production.
*/
new FractalWebpackPlugin({
mode: settings.fractal.mode,
sync: settings.fractal.sync
}),
/**
* Copies images over to the output directory
*/
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, `./${paths.src}/images`),
to: 'images'
}
]),
// new PrettierPlugin()
],
/**
* This only runs when in production mode and will minify JS and CSS
*/
optimization: {
minimize: true,
minimizer: [
new OptimizeCSSAssetsPlugin({
assetNameRegExp: /style\/(website|designSystem).css/,
cssProcessor: require('cssnano')
}),
new TerserPlugin({
include: /\/js/,
exclude: /\/scss/
})
]
},
/**
* Generates source maps
*/
devtool: 'source-maps'
};
};
I finally figured out my issue and wanted to post the answer so if anyone else in the future comes across this issue they can solve it.
Despite what my question says, to start with I actually didn't know which loader was causing the issue, after doing some research I initially thought css-loader was the culprit. I did some digging into the code and found that there is no minification in css-loader. The next loader to look into was sass-loader, after lots of research I eventually figured out sass-loader was doing the minification. Looking into the sass-loader docs I didn't seem to find any information about minification or how to stop it. After lots of googling, I eventually found the very poorly documented option outputStyle.
From what I can find outputStyle takes 3 options:
outputStyle: 'compressed'
outputStyle: 'uncompressed'
outputStyle: 'expanded'
This was my magic option, while sass-loader seems to take no notice of minimize: false in webpack.config.js it will listen to the outputStyle option. This will turn off the minification for all CSS files. This then allows OptimizeCSSAssetsPlugin to come into play and minify the filed you need.
Here if the new sass-loader code:
{
loader: 'sass-loader',
options: {
sourceMap: true,
minimize: false,
outputStyle: 'expanded'
}
}
Here is the full webpack.config.js
const CopyWebpackPlugin = require('copy-webpack-plugin');
const FixStyleOnlyEntriesPlugin = require('webpack-fix-style-only-entries');
const FractalWebpackPlugin = require('fractal-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const path = require('path');
const PrettierPlugin = require('prettier-webpack-plugin');
const StyleLintPlugin = require('stylelint-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
module.exports = (env, argv) => {
/**
* Determine if is production mode from the command executed
*/
const isProduction = argv.mode === 'production';
/**
* Common paths
*/
const paths = {
src: 'src',
dev: 'public',
prod: 'public'
};
/**
* Generate the settings for webpack depending on if it is
* development or production mode.
*/
const settings = {
mode: isProduction ? 'production' : 'development',
outputDir: isProduction ? paths.prod : paths.dev,
fractal: {
mode: isProduction ? 'build' : 'server',
sync: isProduction ? false : true
}
};
return {
// Mode is set by --mode property in command
mode: settings.mode,
/**
* 3 entries:
* designSystem: This is Design System UI specific CSS
* website: This is website & component specific CSS
* app: This is the website & component specific JS
*/
entry: {
/**
* Main website and Design System CSS files
*/
designSystem: path.resolve(__dirname, `./${paths.src}/theme/scss/theme.scss`),
website: path.resolve(__dirname, `./${paths.src}/scss/styles.scss`),
/**
* Specific enteries for all comonents to generate a CSS file specific to that component
*/
headings: path.resolve(__dirname, `./${paths.src}/patterns/01-branding/03-typography/02-headings/headings.scss`),
paragraphs: path.resolve(__dirname, `./${paths.src}/patterns/01-branding/03-typography/03-paragraphs/paragraphs.scss`),
inlineElements: path.resolve(__dirname, `./${paths.src}/patterns/01-branding/03-typography/04-inline-elements/inline-elements.scss`),
ordered: path.resolve(__dirname, `./${paths.src}/patterns/01-branding/03-typography/05-lists/ordered/ordered.scss`),
unordered: path.resolve(__dirname, `./${paths.src}/patterns/01-branding/03-typography/05-lists/unordered/unordered.scss`),
images: path.resolve(__dirname, `./${paths.src}/patterns/01-branding/06-images/images.scss`),
spacers: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/01-layout/02-spacers/spacers.scss`),
primaryButton: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/02-buttons/primary-button/primary-button.scss`),
secondaryButton: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/02-buttons/secondary-button/secondary-button.scss`),
tertiaryButton: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/02-buttons/tertiary-button/tertiary-button.scss`),
checkboxes: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/03-form-elements/checkboxes/checkboxes.scss`),
inputs: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/03-form-elements/inputs/inputs.scss`),
labels: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/03-form-elements/labels/labels.scss`),
radios: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/03-form-elements/radios/radios.scss`),
selects: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/03-form-elements/selects/selects.scss`),
textareas: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/03-form-elements/textareas/textareas.scss`),
footer: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/04-footer/footer.scss`),
navigation: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/05-navigation/navigation.scss`),
informationPanel: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/06-information-panel/information-panel.scss`),
informationPill: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/07-information-pill/information-pill.scss`),
modal: path.resolve(__dirname, `./${paths.src}/patterns/02-ui-components/08-modal/modal.scss`),
/**
* Main website and Design System JS files
*/
app: [
'regenerator-runtime/runtime',
'core-js/modules/es6.array.from',
'core-js/modules/es6.array.for-each',
'core-js/modules/es6.object.assign',
'core-js/modules/es6.promise',
path.resolve(__dirname, `./${paths.src}/js/app.js`)
]
},
/**
* JS output goes into the scripts folder and depending on mode will
* either go into the public or the dist folder with it's chunks
*/
output: {
path: path.resolve(__dirname, `./${settings.outputDir}`),
filename: 'scripts/[name].js',
chunkFilename: 'scripts/[name].chunk.js'
},
module: {
rules: [
{
parser: {
amd: false
}
},
{
/**
* Load JS files with Babel Loader and set to transpile code to work
* in IE10 and above.
*/
test: /\.(js)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
configFile: './babel.config.js',
presets: [
[
'#babel/preset-env',
{
useBuiltIns: 'entry',
corejs: '^3.1.4',
targets: {
browsers: ['defaults, ie >= 10']
}
}
]
]
}
},
{
loader: 'eslint-loader',
options: {
configFile: '.eslintrc.json'
}
}
]
},
{
/**
* Load SASS files with 2 loaders
* PostCSS: This converts the SCSS to CSS, adds in polyfills for flexbox,
* auto prefixes and adds in normalise CSS.
* SASS Loader: This generates source maps for CSS.
*/
test: /\.(scss|sass)$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
{
loader: 'css-loader',
options: {
sourceMap: true
}
},
{
loader: 'postcss-loader',
options: {
plugins: () => [
require('postcss-flexbugs-fixes'),
require('postcss-preset-env')({
autoprefixer: {
flexbox: 'no-2009'
},
stage: 3
}),
require('autoprefixer')()
],
sourceMap: true,
minimize: false
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
minimize: false,
outputStyle: 'expanded'
}
}
]
},
{
/**
* This looks for all images and uses the File Loader to move them to
* the output directory. It excludes the fonts directory so there is no
* duplication of SVG files
*/
test: /\.(png|jpg|jpeg|gif|svg)$/,
exclude: /fonts/,
use: [
{
loader: 'file-loader',
options: {
name: '[folder]/[name].[ext]',
outputPath: '/images'
}
}
]
},
{
/**
* This looks for all font files and uses the File Loader to
* move hem to the output directory. It excludes the images directory
* so there is no duplication of SVG files
*/
test: /\.(woff|woff2|eot|ttf|otf|svg)$/,
exclude: /images/,
use: [
{
loader: 'file-loader',
options: {
name: '[folder]/[name].[ext]',
outputPath: '/fonts'
}
}
]
}
]
},
plugins: [
/**
* This prevents webpack from generating a JS file for SCSS entries
*/
new FixStyleOnlyEntriesPlugin(),
/**
* Runs SASS linting
*/
new StyleLintPlugin({
configFile: '.stylelintrc.json',
context: 'src',
files: '**/*.scss',
failOnError: false,
quiet: false,
emitErrors: true
}),
/**
* This outputs SCSS entires into CSS files and thier chunks
*/
new MiniCssExtractPlugin({
filename: 'style/[name].css',
chunkFilename: 'style/[name].chunk.css'
}),
/**
* Runs Fractal in either server mode for dev and build mode for
* production.
*/
new FractalWebpackPlugin({
mode: settings.fractal.mode,
sync: settings.fractal.sync
}),
/**
* Copies images over to the output directory
*/
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, `./${paths.src}/images`),
to: 'images'
}
]),
// new PrettierPlugin()
],
/**
* This only runs when in production mode and will minify JS and CSS
*/
optimization: {
minimize: true,
minimizer: [
new OptimizeCSSAssetsPlugin({
assetNameRegExp: /style\/(website|designSystem).css/,
cssProcessor: require('cssnano')
}),
new TerserPlugin({
include: /\/js/,
exclude: /\/scss/
})
]
},
/**
* Generates source maps
*/
devtool: 'source-maps'
};
};

Grunt Watch LiveReload on site on server

I am developing a WordPress site on a server (not local). I want to refresh the page in my browser whenever I modify a sass file. I've got some grunt tasks listed, but right now I just want it to refresh on any sass modification. Right now, it catches whenever a file is modified, but it does not refresh the page.
Gruntfile:
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
watch: {
scripts: {
options: { livereload: true },
files: ['**/*.scss'],
//tasks: ['criticalcss:front', 'criticalcss:page', 'cssmin', 'postcss'],
}
},
postcss: {
options: {
processors: [
require('autoprefixer')({browsers: 'last 6 versions'}), // add vendor prefixes
//require('cssnano')() // minify the result
]
},
dist: {
src: 'style.css',
dest: 'style.css'
}
},
criticalcss: {
front : {
options: {
url: "https://grandeurflooring.ca/grand_dev/",
minify: true,
width: 1500,
height: 900,
outputfile: "critical_css/critical-front.css",
filename: "style.css",
buffer: 800*1024,
ignoreConsole: true
}
},
page : {
options: {
url: "https://grandeurflooring.ca/grand_dev/sample-page/",
minify: true,
width: 1500,
height: 900,
outputfile: "critical_css/critical-page.css",
filename: "style.css",
buffer: 800*1024,
ignoreConsole: true
}
}
},
cssmin: {
target: {
files: [{
expand: true,
cwd: 'critical_css',
src: ['*.css', '!*.min.css'],
dest: 'critical_css',
ext: '.min.css'
}]
}
}
});
// Load the plugin that provides the "critical" task.
grunt.loadNpmTasks('grunt-criticalcss');
// Load the plugin that provides the "cssmin" task.
grunt.loadNpmTasks('grunt-contrib-cssmin');
// Load the plugin that provides the "watch" task.
grunt.loadNpmTasks('grunt-contrib-watch');
// Load the plugin that provides the "PostCSS" task.
grunt.loadNpmTasks('grunt-postcss');
// Critical task.
grunt.registerTask('critical', ['criticalcss:front']);
};
In footer.php, before wp_footer(), I put the script:
<script src="http://localhost:35729/livereload.js"></script>
You can configure Grunt to watch the compiled css file in your dist directory, which would be updated every time the Sass is recompiled.
Here is my watch configuration which is achieving what you want:
watch: {
options: {
livereload: true,
},
html: {
files: ['index.html'],
},
js: {
files: ['js/**/*.js'],
tasks: ['jshint'],
},
sass: {
options: {
livereload: false
},
files: ['css/scss/**/*.scss'],
tasks: ['sass'],
},
css: {
files: ['dist/css/master.css'],
tasks: []
}
}
You might need to change spawn: false to spawn: true depending on your setup as well.
EDIT: Additionally, you can use the grunt-contrib-watch plugin which allows you to:
Run predefined tasks whenever watched file patterns are added, changed or deleted
This plugin contains numerous additional options for live-reloading, watching, etc. which you may find useful.

Grunt less won't replace css file

I use grunt-contrib-less with grunt-contrib-watch to compile my less files automatically upon change.
When the css is not present, grunt compiles it ok. When a css already exists and watch sees the less file changed, the css file is not modified. I have to remove it every time and let grunt recreate it with the modifications.
less config:
less: {
options: {
banner: '<%= meta.banner %>'
},
dev: {
options: {
sourceMap: true,
sourceMapFileInline: true,
compress: true
},
src: '<%= meta.dev.less %>/main.less',
dest: '<%= meta.prod.css %>/main.css'
},
prod: {
options: {
plugins: [
new( require( 'less-plugin-clean-css' ) )( {
'advanced': true,
'compatibility': 'ie9'
} )
],
},
src: '<%= meta.dev.less %>/main.less',
dest: '<%= meta.prod.css %>/main.css'
}
},
I'm under Windows 10 and every user have the rights to modifiy/delete the files in my dist folder.
How can I let grunt modify the css file?
EDIT
watch config
watch: {
options: {
livereload: 6325
},
js: {
files: [ '<%= meta.dev.js %>/main.js', '<%= meta.dev.js %>/plugins/*.js' ],
tasks: [ 'newer:concat' ]
},
images: {
files: '<%= meta.dev.img %>/**/*.{png,jpg,gif,svg}',
tasks: [ 'newer:imagemin' ]
},
css: {
files: '<%= meta.dev.less %>/**/*.less',
tasks: [ 'newer:less:dev' ]
}
}
Registration
grunt.registerTask( 'default', [ 'less:dev', 'concat', 'imagemin', 'copy', 'watch' ] );
Grunt output (verbose)
>> File "dev\less\elements\menu.less" changed.
Initializing
Command-line options: --verbose
Reading "Gruntfile.js" Gruntfile...OK
Registering Gruntfile tasks.
Reading package.json...OK
Parsing package.json...OK
Initializing config...OK
Loading "Gruntfile.js" tasks...OK
+ default, prod
Running tasks: newer:less:dev
Loading "grunt-newer" plugin
Registering "D:\[...]\static\node_modules\grunt-newer\tasks" tasks.
Loading "newer.js" tasks...OK
+ any-newer, newer, newer-clean, newer-postrun
Running "newer:less:dev" (newer) task
Options: cache="D:\\[...]\\static\\node_modules\\grunt-newer\\.cache", override=undefined
Files: dev/less/main.less -> dist/css/main.css
No newer files to process.
Here's what happens:
you modify menu.less
watch detects that and runs newer:less:dev
less:dev uses file main.less as only source (not menu.less)
that file hasn't changed, so newer concludes it doesn't need to run the task again
I suppose main.less includes menu.less, but newer doesn't know it.
So my suggested fix would be to get rid of the newer part.
Have you added correct watch config for less ?
watch: {
less: {
files: ['less/**/*.less'], // which files to watch
tasks: ['less'],
options: {
nospawn: true
}
}
}
To run grunt with your profile : grunt.registerTask('myprofile', ['less:dev', 'watch']);

jshint grunt targets generate message: 0 files linted. Please check your ignored files

I have multiple jshint configurations in my gruntfile.
I tested each configuration, and it works great.
However, when I define a target in the gruntfile for each configuration, jshint stops working and all I can see is :
0 files linted. Please check your ignored files.
This is how my jshint configuration looks like with targets:
jshint: {
backend: {
options: {
jshintrc: '.jshintrc'
},
all: [
'Gruntfile.js',
'server.js',
'*.js',
'backend/{,*/}*.js'
]
},
test: {
options: {
jshintrc: 'test.jshintrc'
},
all: [
'test/{,*/}*.js'
]
}
}
For multiple tasks changing:
'all' : {...}
to
'files': { src: [...] }
should fix it. It would seem that 'all' is a shorthand for a single task, with multiple tasks, jshint will be looking for files in files->src ie:
backend: {
options: {
jshintrc: '.jshintrc'
},
'files': {
'src': [
'Gruntfile.js',
'server.js',
'*.js',
'backend/{,*/}*.js'
]
}
},
test: {
options: {
jshintrc: 'test.jshintrc'
},
'files': {
'src': [
'test/{,*/}*.js'
]
}
}
My team found out this works, we are using it on a project of ours.
Even though I don't recommend using this method, it taught me something about how grunt works, and how you can programatically invoke tasks and change options at runtime so I find it relevant.
jshint: {
options: {
jshintrc: '.jshintrc'
},
all: [
'Gruntfile.js',
'<%= yeoman.app %>/scripts/{,*/}*.js'
],
backend: [
'server.js'
]
},
....
grunt.registerTask('backend', function() {
grunt.config.set('jshint.options.jshintrc', '.backendhintrc');
grunt.task.run('jshint:backend');
});

Resources