I'm using Yeoman and I can't find a way to trigger the CSS task upon file change.
I have a project structure like
\ app
-----\ module1
------- style.css
-----\ module2
------- style.css
-----\ module3
------- style.css
-----\ styles
------- main.css
and I'd like Yeoman to
watch all the CSS files within the modules;
trigger the CSS concat/minification task;
overwrite app/styles/main.css.
Here's my Gruntfile.js:
module.exports = function( grunt ) {
'use strict';
//
// Grunt configuration:
//
// https://github.com/cowboy/grunt/blob/master/docs/getting_started.md
//
grunt.initConfig({
// Project configuration
// ---------------------
// specify an alternate install location for Bower
bower: {
dir: 'app/components'
},
// Coffee to JS compilation
coffee: {
compile: {
files: {
// 'app/scripts/*.js': 'app/scripts/**/*.coffee',
// 'test/spec/*.js': 'test/spec/**/*.coffee'
}
}
},
// compile .scss/.sass to .css using Compass
compass: {
dist: {}
},
// default watch configuration
watch: {
reload: {
files: [
'Gruntfile.js',
'app/*.html',
'app/styles/**/*.css',
'app/scripts/**/*.js',
'app/images/**/*',
'app/app/**/*'
],
tasks: 'css reload'
}
},
// default lint configuration, change this to match your setup:
// https://github.com/cowboy/grunt/blob/master/docs/task_lint.md#lint-built-in-task
lint: {
files: [
'Gruntfile.js',
'app/scripts/**/*.js',
'spec/**/*.js'
]
},
// specifying JSHint options and globals
// https://github.com/cowboy/grunt/blob/master/docs/task_lint.md#specifying-jshint-options-and-globals
jshint: {
options: {
curly: true,
eqeqeq: true,
immed: true,
latedef: true,
newcap: true,
noarg: true,
sub: true,
undef: true,
boss: true,
eqnull: true,
browser: true
},
globals: {
angular: true
}
},
// Build configuration
// -------------------
// the staging directory used during the process
staging: 'temp',
// final build output
output: 'dist',
mkdirs: {
staging: 'app/'
},
// Below, all paths are relative to the staging directory, which is a copy
// of the app/ directory. Any .gitignore, .ignore and .buildignore file
// that might appear in the app/ tree are used to ignore these values
// during the copy process.
// concat css/**/*.css files, inline #import, output a single minified css
css: {
'app/styles/main.css': ['app/styles/*.css', 'app/app/**/*.css']
},
// renames JS/CSS to prepend a hash of their contents for easier
// versioning
rev: {
js: 'scripts/**/*.js',
css: 'styles/**/*.css',
img: 'images/**'
},
// usemin handler should point to the file containing
// the usemin blocks to be parsed
'usemin-handler': {
html: 'index.html'
},
// update references in HTML/CSS to revved files
usemin: {
html: ['**/*.html'],
css: ['**/*.css']
},
// HTML minification
html: {
files: ['**/*.html']
},
// Optimizes JPGs and PNGs (with jpegtran & optipng)
img: {
dist: '<config:rev.img>'
},
// rjs configuration. You don't necessarily need to specify the typical
// `path` configuration, the rjs task will parse these values from your
// main module, using http://requirejs.org/docs/optimization.html#mainConfigFile
//
// name / out / mainConfig file should be used. You can let it blank if
// you're using usemin-handler to parse rjs config from markup (default
// setup)
rjs: {
// no minification, is done by the min task
optimize: 'none',
baseUrl: './scripts',
wrap: true
}
});
// Alias the `test` task to run `testacular` instead
grunt.registerTask('test', 'run the testacular test driver', function () {
var done = this.async();
require('child_process').exec('testacular start --single-run', function (err, stdout) {
grunt.log.write(stdout);
done(err);
});
});
};
I am new to grunt, but what I did to write a custom watch task was this. First I registered a new task which included only the things I want to run while I am developing. I want my project to run against unminified js, for example. So I don't ask for the min or concat tasks to be executed. Just lint them, test them and rewrite the html for development mode using grunt-targethtml.
grunt.registerTask('devel', 'lint qunit targethtml');
Then I replace the default watch configuration to run the devel task
watch: {
files: '<config:lint.files>',
tasks: 'devel'
}
This is using the file list as defined for the lint task but you should be able to replace this with
files: ['app/**/*.css']
Related
Write a grunt file to validate js
files using jshint, minify html files, start the web server and watch the local web server.
Validate js files with jshint.
The source file is located in "src/js".
Minify the html files in "src" folder and place it inside "dest/src" folder with same file
name.
After html minification, setup and run a local web server.
Run the watch task to watch the webserver.
Use the IDE terminal to install
plugins.
Use official grunt plugins only.
Install necessary grunt commands for all the below tasks and make sure the commands are saved in packages.json and try this:
module.exports = function(grunt) {
require('jit-grunt')(grunt);
grunt.initConfig({
jshint: {
files: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js'],
options: {
globals: {
jQuery: true
}
}
},
htmlmin: { // Task
dist: { // Target
options: { // Target options
removeComments: true,
collapseWhitespace: true
},
files: { // Dictionary of files
'dest/src/form.html': 'src/form.html', // 'destination': 'source'
'dest/src/management.html': 'src/management.html'
}
}
},
watch: {
styles: {
files: ['less/**/*.less'], // which files to watch
tasks: ['less'],
options: {
nospawn: true
}
}
},
connect: {
server: {
options: {
port: 9000,
base: 'app',
keepalive: false
}
}
}
});
grunt.registerTask('default', ['htmlmin','jshint','connect','watch']);
};
I've got several projects that each use an identical Gruntfile to run tasks and put the output in their own dist folder. Folder setup:
MyProjects
- Project1
- src
- dist
- Project2
- src
- dist
.....
I can't figure out how to run Grunt at the top level (MyProjects) and still have the output generated in the correct dist folder dynamically.
Is there a way I can have Grunt put the output in the correct dist folder without having to hard code it into the Gruntfile? Something like:
dist: {
files: {
// destination : source js
'<% ProjectName %>/dist/app.js': '<% ProjectName %>/src/app.js'
},
Thanks
module.exports = function (grunt) {
require('load-grunt-tasks')(grunt);
// Project configuration.
grunt.initConfig({
watch: {
scripts: {
files: ['src/**/*.js'],
tasks: ['browserify', 'file_append', 'concat'],
options: {
spawn: false
}
},
sass: {
files: "src/scss/*.scss",
tasks: ['sass', 'file_append', 'concat']
}
},
sass: {
dist: {
options: {
style: 'expanded'
},
files: {
// destination // source file
"format/css/styles.css": "src/scss/styles.scss"
}
},
options: {
sourcemap: "none",
style: "compact",
noCache: true
}
},
file_append: {
default_options: {
files: [
// Development build
{
append: "",
prepend: "",
input: "format/app.js",
output: "format/dev.app.js"
},
{
append: "</style>`)",
prepend: "document.body.insertAdjacentHTML('afterbegin', `\n<style>\n",
input: "format/css/styles.css",
output: "format/css/dev.styles.html"
},
// Production build
{
append: "</script>",
prepend: "<script>\n",
input: "format/app.js",
output: "format/prod.app.html"
},
{
append: "</style>",
prepend: "<style>\n",
input: "format/css/styles.css",
output: "format/css/prod.styles.html"
}
]
}
},
concat: {
options: {
seperator: '\n'
},
// Development build
dev: {
src: ['format/dev.app.js', 'format/css/dev.styles.html'],
dest: 'dev/dev.app.js'
},
// Production build
prod: {
src: ['format/prod.app.html', 'format/css/prod.styles.html'],
dest: 'dist/prod.app.html'
}
},
browserify: {
dist: {
files: {
// destination for transpiled js : source js
'format/app.js': 'src/app.js'
},
options: {
transform: [
[
'babelify', {
presets: "es2015",
comments: false,
plugins: "transform-object-rest-spread"
}
]
],
browserifyOptions: {
debug: false
}
}
}
}
});
grunt.registerTask('default', [
'sass',
'browserify:dist',
'file_append',
'concat',
'watch'
]);
};
There's a couple ways you can tackle this.
One option is to overload the arguments you pass to the task & include the folder name you wish to target.
grunt sass:dist:Project1
The additional argument is accessible via lodash templates which are a part of the GruntJS framework, and allows the configuration to be set at the time the task is ran:
sass: {
dist: {
options: {
style: 'expanded'
},
files: {
// destination // source file
"MyProjects/<%= grunt.task.current.args[0] %>/format/css/styles.css": "MyProjects/<%= grunt.task.current.args[0] %>/src/scss/styles.scss"
}
},
options: {
sourcemap: "none",
style: "compact",
noCache: true
}
}
This approach works in the context of the function that's executing, but it wouldn't continue to pass the args to the next task. To do that, we need to add a custom task which will set a configuration object before executing the task list:
grunt.registerTask("build", (project) => {
const buildConfig = { project };
grunt.config.set("build", buildConfig);
grunt.task.run([
'sass',
'browserify:dist',
'file_append',
'concat',
'watch'
]);
});
Now when we run grunt build:Project1, your custom task build will run and set the property we passed in the grunt config object. We can then reference that value in our other grunt config objects using lodash like we did for the first option. To access config values with lodash templates, we just have to provide the config pointer in json notation:
files: {
"MyProjects/<%= build.project %>/format/css/styles.css": "MyProjects/<%= build.project %>/src/scss/styles.scss"
}
Grunt compiles the configs required for a task at the time they're run & will process the lodash templates then, allowing you to inject your project name into a task. Since we stored the value in the config object, the value will persist through until grunt completes and exits.
I am having an issue trying to get my Grunt.js file to work. Currently I have it set up to just concatenate all my php function files, and decided since a lot of my work projects use Bootstrap, to concatenate only the javascript files I'll be using. However, when I set it up, hoping I did set it up correctly, my grunt execution does not create/edit the javascript final destination file, nor the php functions file. I am not sure what I have done incorrectly but here is the following code:
module.exports = function (grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
concat: {
js: {
options: {
separator: 'rn'
},
dist: {
src: [
// Comment or uncomment any Bootstrap JS files
// you will not be using
'wp-content/themes/base_theme/assets/js/required/bootstrap/plugins/alert.js',
'wp-content/themes/base_theme/assets/js/required/bootstrap/plugins/button.js',
'wp-content/themes/base_theme/assets/js/required/bootstrap/plugins/carousel.js',
'wp-content/themes/base_theme/assets/js/required/bootstrap/plugins/collapse.js',
'wp-content/themes/base_theme/assets/js/required/bootstrap/plugins/dropdown.js',
'wp-content/themes/base_theme/assets/js/required/bootstrap/plugins/modal.js',
'wp-content/themes/base_theme/assets/js/required/bootstrap/plugins/phantom.js',
'wp-content/themes/base_theme/assets/js/required/bootstrap/plugins/popover.js',
'wp-content/themes/base_theme/assets/js/required/bootstrap/plugins/qunit.js',
'wp-content/themes/base_theme/assets/js/required/bootstrap/plugins/scrollspy.js',
'wp-content/themes/base_theme/assets/js/required/bootstrap/plugins/tether.js',
'wp-content/themes/base_theme/assets/js/required/bootstrap/plugins/tab.js',
'wp-content/themes/base_theme/assets/js/required/bootstrap/plugins/tooltip.js'
],
dest: 'wp-content/themes/base_theme/assets/js/required/bootstrap/bootstrap.min.js'
}
},
php: {
options: {
stripBanners: true,
separator: '\n?>\n',
},
dist: {
src: [
// To create a new location, follow pattern below
// Comment out what you don't need a re-concat
'wp-content/themes/base_theme/assets/functions/basic.php',
'wp-content/themes/base_theme/inc/custom-header.php',
'wp-content/themes/base_theme/inc/customizer.php',
'wp-content/themes/base_theme/inc/extras.php',
'wp-content/themes/base_theme/inc/jetpack.php',
'wp-content/themes/base_theme/inc/template-tags.php',
'wp-content/themes/base_theme/inc/wpcom.php',
'wp-content/themes/base_theme/assets/functions/bootstrap-nav.php',
'wp-content/themes/base_theme/assets/functions/enqueue.php'
'wp-content/themes/base_themey/assets/functions/custom-post-type.php',
'wp-content/themes/base_theme/assets/functions/internal-template.php',
'wp-content/themes/base_theme/assets/functions/custom-taxonomy.php',
'wp-content/themes/base_theme/assets/functions/acf.php',
'wp-content/themes/base_theme/assets/functions/custom.php'
'wp-content/themes/base_theme/assets/functions/custom-sidebar.php'
],
dest: 'wp-content/themes/base_theme/functions-mod.php'
}
}
}
});
// Load the plugins
grunt.loadNpmTasks('grunt-contrib-concat');
// Default task(s).
grunt.registerTask('default', ['concat']);
};
My package.json is the following (I know I'm not using jshint or uglify as of yet in my grunt.js, I am just testing one at a time).
{
"name": "base_theme",
"version": "0.1.0",
"devDependencies": {
"grunt": "~0.4.5",
"grunt-contrib-concat": "~1.0.0",
"grunt-contrib-jshint": "~0.8.0",
"grunt-contrib-uglify": "~0.2.7"
}
}
I've tried reading through the documentation on grunt's website, but either I"m not understanding something correctly, or I am just doing something completely wrong
Your config for Gruntfile.js is almost correct.
To fix it, simply avoid nesting src and dest in a dist object for both the js and php targets. For example:
Updated Gruntfile.js:
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
concat: {
js: {
options: {
separator: 'rn'
},
//dist: { <-- REMOVE the 'dist' object.
src: [
// Comment or uncomment any Bootstrap JS files
// you will not be using
'wp-content/themes/base_theme/assets/js/required/bootstrap/plugins/alert.js',
'wp-content/themes/base_theme/assets/js/required/bootstrap/plugins/button.js',
'wp-content/themes/base_theme/assets/js/required/bootstrap/plugins/carousel.js'
// ...
],
dest: 'wp-content/themes/base_theme/assets/js/required/bootstrap/bootstrap.min.js'
},
php: {
options: {
stripBanners: true,
separator: '\n?>\n',
},
//dist: { <-- REMOVE the 'dist' object here too.
src: [
// To create a new location, follow pattern below
// Comment out what you don't need a re-concat
'wp-content/themes/base_theme/assets/functions/basic.php',
'wp-content/themes/base_theme/inc/custom-header.php',
'wp-content/themes/base_theme/inc/customizer.php'
// ...
],
dest: 'wp-content/themes/base_theme/functions-mod.php'
}
}
});
// Load the plugins
grunt.loadNpmTasks('grunt-contrib-concat');
// Default task(s).
grunt.registerTask('default', ['concat']);
};
Further info:
Take a look at the example config for multiple-targets in the grunt-contrib-concat documentation and Task Configuration and Targets in the grunt documentation for further info.
Note: If you encounter any issues when you uglify the concatenated resultant files you may need to include a semicolon in your separator values. See here for more info. It reads:
Concatenated files will be joined on this string. If you're post-processing concatenated JavaScript files with a minifier, you may need to use a semicolon ';\n' as the separator.
I am using grunt-contrib-watch and this sublime package sublime-grunt.
I am using the sublime-grunt package to start a watch session and livereload with the Chrome extension. Everything works great however once a 'watch' session is started what is the command to stop/kill/cancel a watch. I tried using a command in the sublime-grunt package called 'Grunt Kill Running Processes' and it tells me something has been canceled but if I change my style.scss file and save it, it compiles and updates are made to my html page, so 'watch' is still in effect. Right now I have to close down Sublime Text to kill the 'watch' session.
I am trying to use a variable for a path to my theme root directory but when I try to concat the variable with a string I received this error. What type of syntax should I use, do I need to create a variable in the package.json file?
Code
var theme_path = 'wp-content/themes/twentyfifteen/';
// Sass plugin
sass: {
dist: {
files: {
theme_path + 'style.css': theme_path + 'sass/style.scss',
}
}
},
// Error
Loading "Gruntfile.js" tasks...ERROR
>> SyntaxError: C:\wamp\www\grunt\Gruntfile.js:31
>> theme_path + 'style.css': 'wp-content/th
emes/twentyfifteen/sass/style.scs
>> ^
>> Unexpected token +
Warning: Task "default" not found. Use --force to continue.
Here is my Gruntfile.js:
module.exports = function(grunt) {
// Theme Directory Path
var theme_path = 'wp-content/themes/twentyfifteen/';
// Configure main project settings
grunt.initConfig({
// Basic settings and info about our plugins
pkg: grunt.file.readJSON('package.json'),
// Watch Plugin
watch: {
sass: {
files: 'wp-content/themes/twentyfifteen/sass/*.scss',
tasks: ['sass','postcss','uglify'],
options: {
livereload: true,
},
},
},
// Sass plugin
sass: {
dist: {
files: {
'wp-content/themes/twentyfifteen/style.css': 'wp-content/themes/twentyfifteen/sass/style.scss',
}
}
},
// Postcss plugin
postcss: {
options: {
map: true, // inline sourcemaps
// or
map: {
inline: false, // save all sourcemaps as separate files...
},
processors: [
require('pixrem')(), // add fallbacks for rem units
require('autoprefixer')({browsers: 'last 2 versions'}), // add vendor prefixes
require('cssnano')() // minify the result
]
},
dist: {
src: 'wp-content/themes/twentyfifteen/style.css'
}
},
// Minify JS Uglify
uglify: {
dist: {
files: {
'wp-content/themes/twentyfifteen/js/functions.min.js': ['wp-content/themes/twentyfifteen/js/functions.js']
}
}
}
});
// Load the plugin
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-sass');
grunt.loadNpmTasks('grunt-postcss');
grunt.loadNpmTasks('grunt-contrib-uglify');
// Run plugin
grunt.registerTask('default', ['watch'] );
}
I think that tasks options can't have variable assigned, i don't have any source at the moment but i can suggest another way to do it:
you can use task params:
watch: {
sass: {
files: '<%= grunt.task.current.args[0] %>/sass/*.scss',
tasks: ['sass:<%= grunt.task.current.args[0] %>','postcss','uglify'],
options: {
livereload: true,
},
},
},
sass: {
dist: {
files: {
'<%= grunt.task.current.args[0] %>/style.css': '<%= grunt.task.current.args[0] %>/sass/style.scss',
}
}
},
and than
grunt.registerTask('default', ['watch:'+theme_path] );
This is a problem that i have already meet to make dynamic watch tasks
I have a simple Jekyll site, and am using grunt to compile LESS files.
I want to build in the ability to continue compiling .less files, building the jekyll site & serving it locally. I also have a task to watch and copy compiled css files into the jekyll _site folder.
However the Grunftile I have at the moment isn't quite working:
module.exports = function (grunt) {
grunt.initConfig({
// compile set less files
less: {
development: {
options: {
paths: ["assets/less"],
yuicompress: true,
compress: true
},
files: {
"assets/css/site.css": ["assets/less/*.less", "!assets/less/_*.less"]
}
}
},
// watch changes to less files
watch: {
styles: {
files: ["less/**/*"],
tasks: ["less", "copy:css"]
},
options: {
livereload: true,
spawn: false,
},
},
// copy compiled css to _site
copy: {
css : {
files: {
cwd: './assets/css/',
src: 'site.css',
dest: './_site/assets/css',
expand: true
}
}
},
// run jekyll command
shell: {
jekyll: {
options: {
stdout: true
},
command: 'jekyll build'
}
},
// jekyll build
jekyll: {
files: [
'*.html', '*.yml', 'assets/js/**.js',
'_posts/**', '_includes/**'
],
tasks: 'shell:jekyll',
options: {
livereload: true
}
},
exec: {
server: {
command: 'jekyll serve -w'
}
},
concurrent: {
options: { logConcurrentOutput: true },
server: {
tasks: ['watch', 'exec:server']
}
}
});
// Load tasks so we can use them
grunt.loadNpmTasks("grunt-contrib-watch");
grunt.loadNpmTasks("grunt-contrib-less");
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-shell');
grunt.loadNpmTasks('grunt-concurrent');
// the default task will show the usage
grunt.registerTask("default", "Prints usage", function () {
grunt.log.writeln("");
grunt.log.writeln("Using Base");
grunt.log.writeln("------------------------");
grunt.log.writeln("");
grunt.log.writeln("* run 'grunt --help' to get an overview of all commands.");
grunt.log.writeln("* run 'grunt dev' to start watching and compiling LESS changes.");
});
grunt.registerTask("dev", ["less:development", "watch:styles", "copy:css", "shell:jekyll", "concurrent:server"]);
};
It's probably better to have Grunt also building Jekyll, using grunt-jekyll https://github.com/dannygarcia/grunt-jekyll. I suspect you're having issues with Jekyll cleaning the output directory after your copy task has placed your compiled LESS output there, so it's important your tasks are run in the correct sequence.
There's an excellent Yeoman generator with a complete Jekyll / Grunt workflow that's also worth checking out; https://github.com/robwierzbowski/generator-jekyllrb and if you don't want to use Yeoman then you will at least find some helpful pointers in the Gruntfile https://github.com/robwierzbowski/generator-jekyllrb/blob/master/app/templates/Gruntfile.js