here's my gruntfile:
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
hologram: {
generate: {
options: {
config: 'config.yml'
}
}
},
libsass: {
files: {
src: 'src/scss/style.scss',
dest: 'templates/static/css/style.css'
}
},
connect: {
server: {
options: {
port: 8000,
hostname: 'localhost',
base: 'docs/',
livereload: 35729
}
}
},
watch: {
scss: {
files: ['src/scss/**/*.scss', 'templates/static/css/*.css'],
tasks: ['libsass','hologram'],
options: {
livereload: true
}
}
}
});
// Load plugins.
grunt.loadNpmTasks('grunt-libsass');
grunt.loadNpmTasks('grunt-hologram');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-contrib-watch');
// Default task(s).
grunt.registerTask('default', ['connect','libsass','hologram','watch']);
};
And here's my package file:
{
"name": "...",
"version": "1.0.0",
"description": "...",
"dependencies": {
"grunt": "^0.4.5"
},
"devDependencies": {
"connect-livereload": "^0.5.2",
"grunt": "^0.4.5",
"grunt-contrib-connect": "^0.9.0",
"grunt-contrib-watch": "^0.6.1",
"grunt-hologram": "0.0.4",
"grunt-libsass": "^0.2.0"
},
"repository": {
"type": "git",
"url": "..."
},
"author": "Yann Bettremieux",
"homepage": "..."
}
Everything seems to be working fine. When I go to http://localhost:8000/ I see my site and when I save my watched files the page reloads etc. But it doesn't actually reloads the previous changes. Meaning, the first time I edit a SCSS file to say color: blue, I see in the inspector that some CSS livereload files are loaded but there is no change on the page. If I change the CSS to color: red the page reload but show everything in blue… If I change it to green, it reloads and shows me the everything in red, etc. etc.
I tried tu use the chrome livereload extension insrtead but it didn't change anything.
I tried grunt-sass instead of libsass. Same behavior.
Not sure what else to try to resolve this issue. Any pointer in thr right direction much appreciated!
Livereload Readme already addresses the issue. See live-reload-with-preprocessors:
Any time a watched file is edited with the livereload option enabled,
the file will be sent to the live reload server. Some edited files you
may desire to have sent to the live reload server, such as when
preprocessing (sass, less, coffeescript, etc). As any file not
recognized will reload the entire page as opposed to just the css or
javascript.
The solution is to point a livereload watch target to your destination files.
You should enable livereload only for css files.
watch: {
scss: {
files: ['src/scss/**/*.scss'],
tasks: ['libsass','hologram']
},
css: {
files: ['templates/static/css/*.css'],
options: {
livereload: true
}
}
}
Related
I've put together a few pretty standard grunt tasks with a reasonable number of dependencies, but for some reason it takes 1-3 minutes to actually load the dependencies. I'm moderately new to grunt, but since most of the other questions about extreme slowness loading grunt dependencies cite times of a few seconds, I'm guessing I'm doing something very wrong.
Here's what my gruntfile looks like:
const path = require("path");
module.exports = function(grunt) {
require('jit-grunt')(grunt);
require('time-grunt')(grunt);
const ignoredSourceScriptPatterns = ['!**/*.debug.js', '!**/*.min.js', '!scripts/*', '!**/*.map'],
baseUIPath = 'presentation/ui',
scripts = grunt.file.expand({filter: 'isFile',
matchBase: true,
cwd: baseUIPath},
['*.js', ...ignoredSourceScriptPatterns]);
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
copy: {
build: {
cwd: 'presentation/',
src: 'ui/**',
dest: path.join('presentation', 'static'),
expand: true
}
},
uglify: {
options: {
sourceMap: true,
compress: false
},
build: {
cwd: baseUIPath,
files: function() {
var modules = grunt.file.expand({
filter: 'isDirectory',
expand: true,
cwd: 'presentation/ui/modules'
}, ['**', '!**/css', '!**/scripts', ...ignoredSourceScriptPatterns]),
components = grunt.file.expand({
filter: 'isFile',
expand: true,
cwd: 'presentation/ui'
}, ['components/!*.js', ...ignoredSourceScriptPatterns]),
files, componentFiles;
files = modules.map(function(path) {
var modulePath = `modules/${path}/scripts`,
moduleName = modulePath.split('/').reduce(function(result, next) {
var nameFragment;
switch(next) {
case "modules":
nameFragment = "Poptart.";
break;
case "scripts":
nameFragment = "min.js";
break;
default:
nameFragment = `${next.charAt(0).toUpperCase() + next.slice(1)}.`;
break;
}
return result + nameFragment;
}, "");
return {
src: grunt.file.expand({
filter: 'isFile'
}, [`${baseUIPath}/${modulePath}/*.js`, ...ignoredSourceScriptPatterns]).sort(
function(a, b) {
return a.length - b.length;
}
),
dest: `${baseUIPath}/${modulePath}/${moduleName}`
};
});
componentFiles = components.map(function(componentPath) {
return {
src: `${baseUIPath}/${componentPath}`,
dest: `${baseUIPath}/${componentPath.replace('.js', '.min.js')}`
};
});
files = [...files, ...componentFiles];
files.push({
src: grunt.file.expand({
filter: 'isFile'
}, [`${baseUIPath}/*.js`, ...ignoredSourceScriptPatterns]),
dest: `${baseUIPath}/poptart.min.js`
});
return files;
}(),
extDot: 'last',
expand: true
}
},
cssmin: {
options: {
sourceMap: true
},
build: {
cwd: 'presentation/static/ui/',
src: ['**/*.css', '!css/jquery-ui/**', '!css/ionicons/**', '!**/*.min.js'],
dest: 'presentation/static/ui/',
ext: '.min.css',
expand: true
}
},
eslint: {
options: {
configFile: 'presentation/build/eslint.json',
ignorePath: 'presentation/build/.eslintignore'
},
target: ['presentation/**/*.js', '!presentation/ui/scripts/*', '!presentation/static/**']
},
shell: {
test: {
command: 'python manage.py test -p "*tests.py"',
options: {
stdout: true,
failOnError: true
}
}
},
karma: {
unit: {
configFile: 'karma.conf.js',
singleRun: true
}
},
mochaTest: {
unit: {
options: {
reporter: 'spec'
},
src: ['presentation/test/server/*.js']
}
}
});
/*grunt.loadNpmTasks('grunt-shell');
grunt.loadNpmTasks('grunt-eslint');
grunt.loadNpmTasks('grunt-karma');
grunt.loadNpmTasks('grunt-mocha-test');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-newer');*/
grunt.registerTask('default', ['lint', 'test']);
grunt.registerTask('test', ['shell:test', 'mochaTest:unit', 'karma:unit']);
grunt.registerTask('lint', ['eslint']);
grunt.registerTask('build-static', ['uglify', 'copy', 'cssmin']);
};
And my dev dependencies from package.json:
"devDependencies": {
"chai": "^3.5.0",
"chai-jquery": "^2.0.0",
"eslint": "^3.7.1",
"grunt": "^1.0.1",
"grunt-contrib-copy": "^1.0.0",
"grunt-contrib-cssmin": "^1.0.2",
"grunt-contrib-uglify": "^2.0.0",
"grunt-eslint": "^19.0.0",
"grunt-karma": "^2.0.0",
"grunt-mocha-test": "^0.13.2",
"grunt-newer": "^1.2.0",
"grunt-shell": "^1.3.1",
"jit-grunt": "^0.10.0",
"jquery": "^3.1.1",
"karma": "^1.3.0",
"karma-chai": "^0.1.0",
"karma-chrome-launcher": "^2.0.0",
"karma-cli": "^1.0.1",
"karma-jquery-chai": "^0.1.3",
"karma-mocha": "^1.3.0",
"karma-phantomjs-launcher": "^1.0.2",
"karma-sinon": "^1.0.5",
"mocha": "^3.2.0",
"sinon": "^1.17.6",
"sinon-chai": "^2.8.0",
"time-grunt": "^1.4.0"
}
Here's what I've tried so far:
Using time-grunt to verify that loading tasks was actually the problem. It was. actually running tasks took very reasonable amounts of time.
using jit-grunt. This made no noticeable difference.
npm prune. This actually did make a fairly big (~30 seconds) difference, but still leaves me at a completely unreasonable time for task loading.
Removing and unloading some of the dependencies (uglify, copy, cssmin) I had added around the time that I started seeing this problem (originally, when I just had the testing/linting tasks, everything worked nice and fast). This also made no noticeable difference.
So. What else could be causing slowness on this scale?
Thanks for your help!
So it looks like the root cause of this was some inefficient file searching in the uglify task. I'd completely forgotten that I had made that giant blob of crazy and IEF, which explains why I was seeing the slowness even when I wasn't running the uglify task. I suppose it also explains why the time for the file search was getting lumped in with the loading tasks.
In any event, the main culprit was (predictably) where I was returning the source/dest paths for the dynamically found script modules, here:
return {
src: grunt.file.expand({
filter: 'isFile'
}, [`${baseUIPath}/${modulePath}/*.js`, ...ignoredSourceScriptPatterns]).sort(
function(a, b) {
return a.length - b.length;
}
),
dest: `${baseUIPath}/${modulePath}/${moduleName}`
};
Unspurprising because it is in a loop. In any event, I noticed it was missing a cwd. Adding that cut the time down to 7s. Still needs improving, but at least now I know what to improve.
Morals of this story:
add cwd's when search for files
Maybe just don't search for files if you don't have to
I tried running your Gruntfile and installed the dependencies manually, and the loading time of the Gruntfile was ~4 secs. Not fast, but not the minutes you talk about.
My guess is grunt.file.expand is working hard. Maybe presentation/ui folder is too big? What do you get by running tree presentation/ui | wc -l ? That shows the number of files you have there.
Otherwise, it would be helpful to also see your package.json and npm ls output.
i have a noob question about livereload with Grunt. I have the watch task configured with livereload: true
I added the tag at the bottom of the page and when i point the browser to localhost:port_number_i_can't_remember it shows a page with the .js server i guess...
how can i use livereload to reload the html i'm working on. where do i have to point the browser? I'm using sublime3 and added the livereload package. I also use brackets, been on/off between the two.
The grunt file:
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
sass: {
options: {
includePaths: ['sass/**/*.scss']
},
dist: {
options: {
outputStyle: 'compressed',
sourceMap: true
},
files: {
'css/materialize.css': 'sass/materialize.scss'
}
}
},
watch: {
grunt: {
options: {
livereload: true
},
files: [
'css/*.css',
'*.html'
]
},
sass: {
files: 'sass/**/*.scss',
tasks: ['sass']
},
}
});
grunt.loadNpmTasks('grunt-sass');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('build', ['sass']);
grunt.registerTask('default', ['build', 'watch']);
}
What am i doing wrong here guys?
There are several ways to enable it, and they're listed in the official wiki.
The easiest is the first one, include
<script src="//localhost:35729/livereload.js"></script>
before </body> in your HTML page.
If you have any question on one of these methods, please update the question accordingly
I'm encountering some confusing issues with getting the browser sync plugin for Grunt to work properly. I have thoroughly read the docs and followed examples but there are a couple of things that won't work:
1) I'm not getting any CSS injection. I know I am running the plugin alongside a watch task, but I have watchTask: true set and my terminal is showing that bS is identifying the change to my CSS, it's just not reloading the browser.
2) None of the ghost mode options seem to work for me. I have set them all to true but, much like the livereload feature, I'm not able to make it work.
Here is my current Gruntfile:
'use strict';
module.exports = function (grunt) {
grunt.initConfig({
watch: {
less : {
files: ['static/css/less/*.less'],
tasks: ['less']
},
html : {
files: ['*.html']
},
js : {
files: ['static/js/*.js']
}
},
less: {
development: {
options: {
paths: ["css"],
compress: true,
yuicompress: true,
optimization: 2
},
files: {
"static/css/styles.css": "static/css/less/styles.less"
}
}
},
browserSync: {
default_options: {
bsFiles: {
src: [
"static/css/*.css",
"*.html"
]
},
options: {
watchTask: true,
server: {
baseDir: "./"
},
ghostMode: {
clicks: true,
forms: true,
scroll: true
}
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-browser-sync');
// Launch BrowserSync + watch task
grunt.registerTask('default', ['browserSync', 'watch']);
};
Any help would be really appreciated
I'm trying to use GruntJS to make some improvements to my workflow - I've been using Compass for a while but I'm wanting to try out Bourbon and so I've been trying to get this working but failing.
I'm getting the following error when I run 'grunt':
ERROR: Cannot find module 'bourbon'
I've installed this through Node using 'npm install' with the following 'package.json' file:
{
"name" : "project",
"description": "description",
"version" : "0.0.1",
"dependencies" : {
"node-sass": "~0.8.4",
"node-bourbon": "~1.0.0",
"grunt": "~0.4.4",
"grunt-contrib-watch": "~0.6.1",
"grunt-sass": "~0.12.0",
"grunt-contrib-uglify": "~0.4.0",
"matchdep": "~0.3.0"
}
}
My grunt file looks like this:
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-sass');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.initConfig({
uglify: {
my_target: {
files: {
'assets/js/main.js': ['_/js/scripts.js']
} // files
} // my_target
}, // uglify
sass: {
dist: {
options: {
includePaths: require('bourbon').includePaths,
outputStyle: 'compressed'
},
files: {
'assets/css/main.css': '_/stylesheets/**/*.scss'
}
}
},
watch: {
options: { livereload: true },
grunt: { files: ['gruntfile.js'] },
scripts: {
files: ['_/js/scripts.js'],
tasks: ['uglify']
}, //script
sass: {
files: ['_/stylesheets/**/*.scss'],
tasks: ['sass']
}, //sass
php: {
files: ['**/*.php']
}
} //watch
}) //initConfig
grunt.registerTask('default', 'watch');
} //exports
I've also imported the file in the top of my SCSS stylesheets using:
#import 'bourbon';
Not sure what I'm doing wrong here, any help would be greatly appreciated!
Please let me know if you need any more info.
You are requiring the wrong package name. It should be:
includePaths: require('node-bourbon').includePaths
but you have:
includePaths: require('bourbon').includePaths
Install Bourbon manually:
Install the gem:
$ gem install bourbon
Install Bourbon into your project's stylesheets directory by generating the bourbon folder:
$ bourbon install
I am kinda new to grunt and want to use it with Jekyll and some LESS-compiling.
My problem now is, I already have fully functioning LESS-comipiling with live reload and watch task and can build my jekyll site through grunt, but how do I run something like the jekyll serve or grunt-connect and grunt watch simultaneously?
I want a grunt task that provides the watching of my LESS-files etc, builds the jekyll site and then runs a small web server with grunt-connect or whatever.
My Gruntfile.js so far:
'use strict';
module.exports = function (grunt) {
grunt.initConfig({
jshint: {
options: {
jshintrc: '.jshintrc'
},
all: [
'Gruntfile.js',
'js/*.js',
'!js/scripts.min.js'
]
},
less: {
dist: {
files: {
'css/styles.min.css': [
'less/app.less'
]
},
options: {
compress: true,
// LESS source map
// To enable, set sourceMap to true and update sourceMapRootpath based on your install
sourceMap: false,
sourceMapFilename: 'css/styles.min.css.map',
sourceMapRootpath: '/'
}
},
dev: {
files: {
'css/styles.min.css': [
'less/app.less'
]
},
options: {
compress: false,
// LESS source map
// To enable, set sourceMap to true and update sourceMapRootpath based on your install
sourceMap: true,
sourceMapFilename: 'css/styles.min.css.map',
sourceMapRootpath: '/'
}
}
},
uglify: {
dist: {
files: {
'js/scripts.min.js': [
'vendor/bootstrap/js/transition.js',
'vendor/bootstrap/js/alert.js',
'vendor/bootstrap/js/button.js',
'vendor/bootstrap/js/carousel.js',
'vendor/bootstrap/js/collapse.js',
'vendor/bootstrap/js/dropdown.js',
'vendor/bootstrap/js/modal.js',
'vendor/bootstrap/js/tooltip.js',
'vendor/bootstrap/js/popover.js',
'vendor/bootstrap/js/scrollspy.js',
'vendor/bootstrap/js/tab.js',
'vendor/bootstrap/js/affix.js',
'vendor/*.js',
'js/_*.js'
]
},
options: {
// JS source map: to enable, uncomment the lines below and update sourceMappingURL based on your install
// sourceMap: 'assets/js/scripts.min.js.map',
// sourceMappingURL: '/app/themes/roots/assets/js/scripts.min.js.map'
}
}
},
watch: {
less: {
files: [
'less/*.less',
'less/bootstrap/*.less'
],
tasks: ['less:dev']
},
js: {
files: [
'<%= jshint.all %>'
],
tasks: ['jshint', 'uglify']
},
livereload: {
// Browser live reloading
// https://github.com/gruntjs/grunt-contrib-watch#live-reloading
options: {
livereload: true
},
files: [
'_site/*'
]
}
},
clean: {
dist: [
'css/styles.min.css',
'css/styles.min.css.map',
'js/scripts.min.js',
'_site/*'
]
},
jekyll: { // Task
options: { // Universal options
bundleExec: true,
src : '<%= app %>'
},
dist: { // Target
options: { // Target options
dest: '<%= dist %>',
config: '_config.yml'
}
},
serve: { // Another target
options: {
serve: true,
drafts: true
}
}
},
connect: {
server: {
options: {
keepalive: true
}
}
}
});
// Load tasks
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-jekyll');
grunt.loadNpmTasks('grunt-contrib-connect');
// Register tasks
grunt.registerTask('default', [
'clean',
'less:dist',
'uglify',
'jekyll:dist'
]);
grunt.registerTask('dev', [
'watch'
]);
};
You need to tell connect what directory to serve up in the configuration using the "base" option, in this case it would be the static _site directory. You can also change the port to whatever you want, but you end up navigating to localhost:9009 with my example
connect: {
server: {
options: {
livereload: true,
base: '_site/',
port: 9009
}
}
}
You will also want to add a watch task for when you change your html templates. Something like this would work.
watch: {
html: {
files: ['**/*.html', '!_site/**/*.html'],
tasks: ['jekyll:dist']
}
}
Then create a "serve" task like Wallace suggested.
// Start web server
grunt.registerTask('serve', [
'jekyll:dist',
'connect:server',
'watch'
]);
Lastly run "grunt serve" in the command line and navigate to localhost with the port you specified.
As commented by #jiggy
The key change is to not set keepalive to true. Keepalive will block
all subsequent tasks from running. So long as connect is followed by
watch the server won't terminate.
I spent 2 days desperately trying every gruntfile-configuration I could find on the internet. Never worked. Then I found this https://stackoverflow.com/a/24765175/1541141.
Use grunt-contrib-connect, NOT grunt-connect. grunt-connect is blocking...
Hope it helps.
I think the heart of your solution is to create a new task or edit an existing task, like so:
// Start web server
grunt.registerTask('serve', [
'jekyll:dist',
'connect:livereload',
'watch'
]);
...which you would run with a $ grunt serve. less, jshint, uglify and connect are already included under watch.