Grunt-contrib-sass not working with compass - javascript

I'm new to Grunt, and am trying to configure grunt-contrib-sass to work alongside Compass.
I'm using the grunt-contrib-sass plugin, as I need to export my .scss files to two separate destinations and I couldn't get that to work with grunt-contrib-compass.
The problem that I'm having, is that on compile of .scss files I get 'ERROR: Cannot load compass' in the terminal.
Here's a copy of my gruntfile.js;
module.exports = function(grunt){
grunt.initConfig({
uglify: {
my_target: {
files: {
'wp-content/themes/mytheme/js/functions.js' : [ 'components/js/*.js' ]
}
}
}, // uglify
sass:{
dist:{
files: {
'wp-content/themes/mytheme/style.css' : 'components/sass/style.scss',
'wp-content/themes/mytheme/css/ie.css' : 'components/sass/ie.scss '
},
options: {
compass: true,
}
}
},
watch: {
scripts : {
files: ['components/js/*.js'],
tasks: ['uglify']
},
css: {
files: [ 'components/sass/*.scss'],
tasks: [ 'sass' ],
options: { livereload: true }
},
livereload: {
options: { livereload: true },
files: ['wp-content/themes/mytheme/'],
},
} // watch
})
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-sass');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask( 'default', 'watch' );
} // exports
Thanks!

Grunt-contrib-sass doesn't support Compass versions less than v1.0.0 (which is in alpha at the time of writing).
After updating Compass with;
gem install compass --pre
everything appears to work fine on compilation. The same gruntfile.js was used as above.

Removing all versions of sass except of known working version 3.2.19 solved the problem for me.
$ sudo gem uninstall sass
Select gem to uninstall:
1. sass-3.2.3
2. sass-3.2.5
3. sass-3.2.19
4. sass-3.3.5
5. All versions
> 4

According to the grunt-contrib-compass github page you need to have Ruby, Sass and Compass installed as prerequisite. You are using grunt-contrib-sass instead of grunt-contrib-compass. See examples on the contrib-compass github.

I found another way to get compass to work without the ruby gem. (it is a bit of work though).
Go to https://github.com/Compass/compass and get the code.
Copy the contents of core/stylesheets/compass into your sass/scss folder. Now you can use the normal import-rules from the compass-website.
BUT:
You probably have to change some imports from compass like import "compass/support"; in _transitions.scss to import "../support";

grunt-contrib-sass perfectly works with compass, just add compass: true to options. I read this point on oficial git repository.
Example
sass: {
dist: {
options: {
style: 'expanded',
compass: true
},
files: [
{
expand: true,
cwd: 'ipa-framework/src/css/scss',
src: ['*.scss'],
dest: 'ipa-framework/src/css',
ext: '.css'
}
]
}
}

So none of the answers worked exactly for me but it did help me solve the issue.
When you install compass using
gem install compass --pre
it installs another version of sass, so dont install sass at all let the compass install do it for you.
So to get it to work
gem uninstall sass
gem install compass --pre
And for reference this is the npm libraries I needed to have to get this working
npm install -g grunt grunt-contrib-sass grunt-contrib-watch grunt-livereload sass grunt-contrib-cssmin grunt-contrib-compass

Related

How can I remove bower from this project and use requirejs with yarn (noob)?

How can I switch this to avoid using bower?
I installed yeoman for the first time and the generator for knockoutjs use bower. Now I read bower support is limited and bootstrap use popper.js which in v2 will deprecate support for bower. I would like to avoid the headache now and learn at the same time.
RequireJS and every client side libraries is in /src/bower_modules.
If I install bootstrap using npm or yarn it will install them in /node_modules, which the browser doesn't have access.
Do I then use gulp to transfer the dist folder to my /src/bower_modules folder?
Folder structure:
/src/
|--bower_modules/
|--app/
|--require.config.js
/node_modules/
/gulpfile.js
gulpfile.js:
var requireJsRuntimeConfig = vm.runInNewContext(fs.readFileSync('src/app/require.config.js') + '; require;'),
requireJsOptimizerConfig = merge(requireJsRuntimeConfig, {
out: 'scripts.js',
baseUrl: './src',
name: 'app/startup',
paths: {
requireLib: 'bower_modules/requirejs/require'
},
include: [
'requireLib',
'components/nav-bar/nav-bar',
'components/home-page/home',
'text!components/about-page/about.html'
],
insertRequire: ['app/startup'],
bundles: {
// If you want parts of the site to load on demand, remove them from the 'include' list
// above, and group them into bundles here.
// 'bundle-name': [ 'some/module', 'another/module' ],
// 'another-bundle-name': [ 'yet-another-module' ]
}
}),
transpilationConfig = {
root: 'src',
skip: ['bower_modules/**', 'app/require.config.js'],
babelConfig: {
modules: 'amd',
sourceMaps: 'inline'
}
},
babelIgnoreRegexes = transpilationConfig.skip.map(function(item) {
return babelCore.util.regexify(item);
});
app/require.config.js:
var require = {
baseUrl: ".",
paths: {
"bootstrap": "bower_modules/bootstrap/js/bootstrap.min",
"crossroads": "bower_modules/crossroads/dist/crossroads.min",
"hasher": "bower_modules/hasher/dist/js/hasher.min",
"popper": "bower_modules/popper.js/dist/popper",
"jquery": "bower_modules/jquery/dist/jquery",
"knockout": "bower_modules/knockout/dist/knockout",
"knockout-projections": "bower_modules/knockout-projections/dist/knockout-projections",
"signals": "bower_modules/js-signals/dist/signals.min",
"text": "bower_modules/requirejs-text/text"
},
shim: {
"bootstrap": { deps: ["popper", "jquery"] }
}
};
Sidenote: The origin of the issue is that I require popper for bootstrap and bootstrasp.bundle is not included in the bower version is seems. Also popper doesn't like bower very much and won't be supported very long. I also have multiple errors trying to include it. I would also like to learn the good way and since bower will not be around long I wouldn't mind not working with it at all.
Bower itself posted a blog about this recently: https://bower.io/blog/2017/how-to-migrate-away-from-bower/.
Here's the key takeaways:
Manually move any packages from bower.json to package.json that are available from both Bower and NPM
For any items that are only available via Bower you can use the bower-away NPM package to install those with NPM instead of Bower
Write a task runner script (Grunt/Gulp/etc...) to move the package(s) file(s) to your dist directory
Something like this should do it.
gulp.task('injectNpmPackages', function () {
return gulp.src([
path.join('/node_modules/my-package/build/my-package.min.js')
])
.pipe(gulp.dest('/dist/vendor/'));
});

Referencing a module / script when using npm and grunt

I'm looking into npm, grunt and bower, and I've made my first task which looks like this.
module.exports = function(grunt){
grunt.initConfig({
concat: {
options: {
separator: ';',
},
dist: {
src: ['node_modules/jquery/dist/jquery.js', 'node_modules/handlebars/dist/handlebars.js'],
dest: 'dist/scripts.js',
},
},
});
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.registerTask('default', ['concat']);
};
I was wondering if there's an easier/better way of adding the scripts. So that instead of typing the whole path you could just do src: [jquery, 'handlebars'],
and if bower is of any use regarding this?
Thank you.

Grunt imagemin error: Cannot read property 'contents' of undefined

Grunt imagemin throws the following error when I try to run it:
Running "imagemin:dynamic" (imagemin) task
Fatal error: Cannot read property 'contents' of undefined
Here's my package.json file:
{
"name": "project1",
"version": "0.1.0",
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-imagemin": "^1.0.0",
"grunt-contrib-uglify": "^0.11.0",
"imagemin" : "4.0.0"
}
}
And here's my Gruntfile.js
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
uglify: {
build: {
src: 'views/js/src/main.js',
dest: 'views/js/build/main.js'
}
},
imagemin: {
dynamic: {
files: [{
expand: true,
cwd: 'views/images/src/',
src: ['**/*.{png,jpg,gif}'],
dest: 'views/images/build/'
}]
}
}
});
// 3. Where we tell Grunt we plan to use this plug-in.
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-imagemin');
// 4. Where we tell Grunt what to do when we type "grunt" into the terminal.
grunt.registerTask('default', ['uglify', 'imagemin']);
};
The issue was flagged and evidently resolved in a prior version of imagemin. But the agreed upon solution was to update grunt-contrib-imagemin to version 1.0.0 and imagemin to 4.0.0, which I've done and it still isn't working.
Just update the gurnt-contrib-imagemin to 1.0.0 or latest, you may be having older version probably 0.9.x
The GitHub solution (https://github.com/gruntjs/grunt-contrib-imagemin/issues/344), instead of downgrading grunt-contrib-imagemin, is adding "vinyl-fs": "2.2.1" in your package.json.
vinyl-fs seems to be anywhere in the dependency tree. But there was a breaking version change of vinyl-fs from 2.2.1 to 2.3.0, which will brake the build process. So the version should be "forced" to 2.2.1.
I resolved the issue by changing my grunt-contrib-imagemin in my package.json to grunt-contrib-imagemin": "0.9.1"
For me worked updating grunt-contrib-imagemin to version ^1.0.0 and adding dependencies imagemin version ^4.0.0 and vinyl-fs version ^2.1.1

React and Grunt - Envify NODE_ENV='production' and UglifyJS

I am using Grunt to build a React project and I want to have 'dev' and 'prod' flavours. As react docs says:
To use React in production mode, set the environment variable NODE_ENV to production.
A minifier that performs dead-code elimination such as UglifyJS is
recommended to completely remove the extra code present in development mode.
I am very new using grunt, browserify and stuff but let's see. First problem I have is with envify, I use it as a transform:
browserify: {
options: {
transform: ['reactify'],
extensions: ['.jsx']
},
dev:{
options: {
watch: true //Uses watchify (faster)
},
src: ['js/app.js'],
dest: 'js/bundle.js'
},
/**
* To use React in production mode, set the environment variable NODE_ENV to production.
* A minifier that performs dead-code elimination such as UglifyJS is
* recommended to completely remove the extra code present in development mode.
**/
prod: {
options: {
transform: ['envify'] //How to set up NOD_ENV='production' ?
},
src: ['js/app.js'],
dest: 'js/bundle.js'
}
},
Ok, doing grunt:dev works just fine. So when running grunt:prod... How can I set NODE_ENV: 'production'? I mean, I know I am passing 'envify' as a transform but... No idea how to use that.
After this, I also have an uglify task:
uglify: {
prod: {
files: {
'js/bundle.min.js': ['js/bundle.js']
}
}
}
So after calling grunt:prod, what it creates is two files (bundle.js and bundle-min.js). In production I will like to only have bundle.min.js. I know I can do:
js/bundle.js': ['js/bundle.js']
But mmm I don't know if there is a way to just rename it to bundle.min.js, I guess so... the problem is that in the html I have:
<script src="js/bundle.js"></script>
Is there here also a trick to make it accepts either bundle.js or bundle.min.js?
Thanks in advance.
Transforms are local, and well made packages put their transforms in their package.json file. Unless you're using envify in your own code, you don't need to do anything with it.
What you do need is grunt-env, or another way to set environmental variables.
Here's an alternative by using package.json:
{
"scripts": {
"build": "NODE_ENV=development grunt build-dev",
"dist": "NODE_ENV=production grunt dist"
}
},
"devDependencies": {
"grunt": "...",
"grunt-cli": "..."
}
The benefit here is that the person using your package doesn't even need to install grunt globally. npm run build will run ./node_modules/.bin/grunt build-dev with the correct environmental variable set.
Both John Reilly's and FakeRainBrigand 's answers did not work for me. What worked for me was the following:
Step 1 - Run this command where your package.json is
npm i grunt-env --save-dev
Step 2 - Add the code in "evn:" to your Gruntfile.js within grunt.initConfig like so:
grunt.initConfig({
...
env: {
prod: {
NODE_ENV: 'production'
}
},
...
});
Step 3 - Add the grunt task to your Gruntfile.js
grunt.loadNpmTasks('grunt-env');
Step 4 - Call it before browserify like so:
grunt.registerTask("default", ["env", "browserify"]);
Just an addition to the great answer by FakeRainBrigand, if you're running on Windows (like me) then you need a subtly different syntax in your scripts section:
{
"scripts": {
"build": "SET NODE_ENV=development&&grunt build-dev",
"dist": "SET NODE_ENV=production&&grunt dist"
}
},
"devDependencies": {
"grunt": "...",
"grunt-cli": "..."
}

How can I make 'grunt less' automatically run autoprefixer?

I have a working Gruntfile with less and autoprefixer. I also have 'grunt watch' working fine.
Before I was using autoprefixer, I was using less mixins for vendor prefixes. Running 'grunt less' would build working CSS with all my prefixes.
Now I have autoprefixer, but if I want to do a once-off build of my styles, I now have to run 'grunt less' then 'grunt autoprefixer' to get working CSS with prefixes.
How can I modify 'grunt less' so it build working, prefixes less again?
I've read the docs, and I know I could add an additional task to do both these things. However:
'grunt less' now doesn't have usable output. A task should always produce usable output.
I don't want to have to tell other people that 'grunt less' doesn't produce usable output
An additional task should not be required to replace one that doesn't work
I.e., I just want grunt less to produce working CSS (with prefixes).
module.exports = function(grunt) {
// Load Grunt tasks declared in the package.json file
require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
// Configure Grunt
grunt.initConfig({
less: {
development: {
options: {
paths: ["./less"],
yuicompress: false
},
files: {
"./public/css/style.css": "./public/less/style.less"
}
}
},
autoprefixer: {
development: {
browsers: ['last 2 version', 'ie 9'],
expand: true,
flatten: true,
src: 'public/css/*.css',
dest: 'public/css'
}
},
watch: {
less: {
files: ["./public/less/*"],
tasks: ["less", "autoprefixer:development"],
options: {
livereload: true
}
}
},
});
};
For using autoprefixer as plugin for LESS, you must install npm-package less-plugin-autoprefix:
npm install grunt-contrib-less less-plugin-autoprefix --save-dev
Gruntfile.js
module.exports = function(grunt) {
"use strict";
var gruntConfig = {
less : {
options : {
plugins : [ new (require('less-plugin-autoprefix'))({browsers : [ "last 2 versions" ]}) ]
},
main : {
files: {
'src/css/desktop/bootstrap-theme.css' : 'src/less/desktop/bootstrap-theme.less',
'src/css/desktop/company.css' : 'src/less/desktop/company.less',
'src/css/desktop/index.css' : 'src/less/desktop/index.less',
'src/css/desktop/login.css' : 'src/less/desktop/login.less'
}
}
}
};
grunt.initConfig(gruntConfig);
grunt.loadNpmTasks('grunt-contrib-less');
grunt.registerTask('default', [ 'less' ]);
};
Grunt can't do what you describe in the question as tasks do not know about each other inherently. You have to glue tasks together using aliases, (easy) or functions (for when you want a bit more control), but there's no way of modifying the way one of these tasks behaves without changing the source.
As an example, you could fork grunt-contrib-less and add the code to run the auto prefixing directly into the task, around here: https://github.com/gruntjs/grunt-contrib-less/blob/master/tasks/less.js#L69 - inject this line here https://github.com/nDmitry/grunt-autoprefixer/blob/master/tasks/autoprefixer.js#L56 and then use your fork instead of the official plugin.
The easiest and best way is to register a new task that does the job of these two tasks but in the one command, i.e:
grunt.registerTask('buildless', ['less', 'autoprefixer']);
I do this with all my own tasks - SASS compilation, JS concat + uglify, webfont generation etc. Just tell the others in your team to run those tasks and not grunt less or grunt autoprefixer on their own.
Better still, use my Grunt plugin available tasks. With this (and the filter config) you will be able to produce a trimmed down list of tasks whenever someone runs grunt availabletasks although I prefer to alias this with tasks for quicker typing. If you're like me and have been bitten by the automation bug (and have registered loads of plugins in your Gruntfile), this can really help a newcomer to the project with which tasks should be run.

Categories