Hi everyone,
I have a lot of css files in my project with a very complex structure so I had to replicate the structure of the folders containing css files at the root of the project.
So every time I save a scss file, grunt has to check each 160+ lines of config I gave him.
Is there a way to optimize this this configuration? Maybe an option to tell contrib-sass to compile the scss file with the same structure he's in?
Here is a simplified example of my code :
...
sass: {
dist: {
options: {
style: 'expanded',
sourcemap: 'none',
trace: true,
},
files: {
'./css/laptop.css': './scss/css/laptop.scss',
....
... (160 more lines)
....
'./css/player.css': './scss/css/player.scss'
}
}
},
...
Thanks!
You can pass parameters to your Grunt task using grunt.option. Take a look.
You can pass params to grunt using this syntax:
$grunt [task] myparam=myvalue
Then, from any place in your gruntfile (or sub-files) you can do that:
var myoption = grunt.option("myparam") || defaultvalue;
With that, you can create a task for compile only one scss file passing the name in the param for example or even if the param doesn't exist compile all.
...
var myoption = grunt.option("myparam") || defaultvalue;
sass: {
dist: {
options: {
style: 'expanded',
sourcemap: 'none',
trace: true,
},
files: {
if ( myoption == defaultvalue ) {
'./css/laptop.css': './scss/css/laptop.scss',
....
... (160 more lines)
....
'./css/player.css': './scss/css/player.scss'
} else {
}
}
}
},
...
After some research I discovered grunt-newer which can be used this way:
css:{
files: [
'./scss/**'
],
tasks: ['newer:sass'],
livereload: {
options: { livereload: true },
files: ['./**'],
},
}
It's not what I was trying to do exactly but It optimised perfectly the grunt process.
Really nice plugin!!
Related
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 currently have a custom location to which I want to output the generated css file from grunt-sass. In my GruntFile.js I have:
sass: {
options: {
includePaths: ['bower_components/foundation/scss']
},
dist: {
options: {
outputStyle: 'compressed'
},
files: {
'dist/assets/css/app.css': 'src/assets/scss/app.scss'
}
}
}
I want to replace 'dist/assets/css/app.css' with a custom location specified from command line. Is there any way to do this for grunt-sass?
Grunt provides applying command line parameters. Here is explanation: http://gruntjs.com/api/grunt.option
In your case solution may looks like:
Declare variable somewhere at the top of Gruntfile.js:
var myVariable = grunt.option('src')';
grunt.initConfig({
...
In your sass task change:
files: {
'dist/assets/css/app.css': 'src/assets/scss/app.scss'
}
to
files: [
{ src: ['src/assets/scss/app.scss'], dest: myVariable
]
And finally, in command line call:
grunt sass --src='your/new/src'
I'd like to make configuration of grunt tasks a bit easier. Currently I've got a lot of different configuration files, like a .csslintrc, jshintrc, bower.json and so on.
It would be really cool if I could concatenate all these configuration files into one single file. This configuration file could look something like
{
"csslint": {
"important": 1,
// ...
},
"jshint": {
//...
},
"bower": {
//...
}
}
My only solution so far would be using a preprocessor and simply insert the options in the tasks (I couldn't figure out how to insert options otherwise). But this doesn't seem to be a very beautiful way...
Most (all?) grunt tasks let you define options in the Gruntfile itself instead of their respective .*rc files.
So if you do that, you nearly get your one single configuration file for free.
For example:
jshint: {
dist: {
options: {
curly: true,
eqeqeq: true,
},
src: ['path/to/**/*.js']
}
},
csslint: {
dist: {
options: {
import: 2
},
src: ['path/to/**/*.css']
}
},
bower: {
install: {
options: {
targetDir: './lib',
layout: 'byType',
install: true,
verbose: false,
cleanTargetDir: false,
cleanBowerDir: false,
bowerOptions: {}
}
}
}
The example from grunt-contrib-less:
less: {
development: {
options: {
paths: ["assets/css"]
},
files: {
"path/to/result.css": "path/to/source.less"
}
},
production: {
options: {
paths: ["assets/css"],
plugins: [
new require('less-plugin-autoprefix')({browsers: ["last 2 versions"]}),
new require('less-plugin-clean-css')(cleanCssOptions)
],
modifyVars: {
imgPath: '"http://mycdn.com/path/to/images"',
bgColor: 'red'
}
},
files: {
"path/to/result.css": "path/to/source.less"
}
}
}
It provides two entries in the dictionary for less: development and production.
I don't know what to call these entries, perhaps smth like "sub-tasks for less".
Does the naming of these matter?
Is it possible to only run one of these. I've tried $ grunt less development, but that does not work.
The names matter and it's something you configure. These are like more like arguments than sub-tasks. Reference: http://gruntjs.com/api/grunt.task
Try grunt less:development
I'm using grunt 0.4.2 and grunt-contrib-less 0.9.0. I want my LESS to be compiled into CSS with support for source maps.
My LESS files are in public/less, and the main one is called main.less.
The compiling of public/less/main.less into public/css/main.css works, but source maps don't work.
What is wrong with my Grunt config below?
{
less: {
dev: {
options: {
compress: true,
yuicompress: true,
optimization: 2,
sourceMap: true,
sourceMapFilename: "public/css/main.css.source-map.json", //Write the source map to a separate file with the given filename.
sourceMapBasepath: "public/less", //Sets the base path for the Less file paths in the source map.
sourceMapRootpath: "/"//Adds this path onto the Less file paths in the source map.
},
files: {
"public/css/main.css": "public/less/main.less"
}
}
},
watch: {
styles: {
files: ["public/less/*"],
tasks: ['less'],
options: {
livereload: true,
nospaces: true
}
}
}
}
I don't want to have my CSS created in my /public/less folder; I want to put it into /public/css. Otherwise, I could use this other config, which works:
{
less: {
dev: {
options: {
compress: true,
yuicompress: true,
optimization: 2,
sourceMap: true,
sourceMapFilename: "public/less/main.css.map", //I DO NOT WANT THE CSS MAP HERE
sourceMapBasepath: "public/less", //Sets the base path for the Less file paths in the source map.
},
files: {
"public/less/main.css": "public/less/main.less"//I DO NOT WANT THE CSS HERE
}
}
},
watch: {
styles: {
files: ["public/less/*"],
tasks: ['less'],
options: {
livereload: true,
nospaces: true
}
}
}
}
I found the LESS site documentation to be more clear regarding params used by grunt-contrib-less.
LESS: Command Line Usage
http://lesscss.org/usage/#command-line-usage-installing-lessc
NPM: grunt-contrib-less
https://www.npmjs.org/package/grunt-contrib-less
File structure:
laravel/gruntfile.js
laravel/public/less/main.less
laravel/public/css/main.css
laravel/public/css/main.css.map
File 'main.css.map' note:
If you wish, you can rename to: main.css.source-map.json
I guess you have some server rule setup that doesn't server *.map files properly from the 'css' folder
Compression notes:
cleancss: true = will remove sourceMappingURL comment from main.css
yuicompress: true = will NOT remove sourceMappingURL comment from main.css
Gruntfile.js
less: {
dev: {
options: {
compress: true,
yuicompress: true,
optimization: 2,
sourceMap: true,
sourceMapFilename: 'public/css/main.css.map', // where file is generated and located
sourceMapURL: '/css/main.css.map', // the complete url and filename put in the compiled css file
sourceMapBasepath: 'public', // Sets sourcemap base path, defaults to current working directory.
sourceMapRootpath: '/', // adds this path onto the sourcemap filename and less file paths
},
files: {
'public/css/main.css': 'public/less/main.less',
}
}
},
watch: {
styles: {
files: ["public/less/*"],
tasks: ['less'],
options: {
livereload: true,
nospaces: true
}
}
},
laravel/public/css/main.css
.class{ compiled css here } /*# sourceMappingURL=/css/main.css.map */
laravel/public/css/main.css.map
{"version":3,"sources":["/less/main.less"], etc...
If you're still having trouble with it try setting the SourceMapURL to the full path, for example:
http://www.yourdomain.com/assets/css/styles.css.map
Obviously this is a bit of a pain as it's not relative, so when you move your site it will need to be changed. I had the same issue as you and this got it working for me.
Another point I discovered is that you cannot load the SourceMaps from the file system. It has to be from a web server. To get around the file system issue I believe you can inline the SourceMap.
This thread on GitHub has a lot of information.
https://github.com/less/less.js/issues/1050#issuecomment-25621390