I am using node-sass to mock my CDN builds and I am converting my CSS to
a modular Sass design. Basically my setup involves brand sites overwriting
the common styles.
I want to do something like this in the brand folder
#import "../common/global-config";
#import "brand-config";
#import "../common/common";
// brand specific styles here
this file would live at /css/brand-name/brand.scss
the other files would live in /css/common/_common.scss
my node-sass setup looks something like this
function compileSassFile(includes, path, callback) {
if (!fs.existsSync(path)) {
return null;
}
var css = sass.renderSync({
file: path,
success: callback,
outputStyle: 'expanded',
includePaths: includes
});
return css;
}
// bundlePath = 'css', dirName = '/brand-name'
compileSassFile([path.join(bundlePath), path.join(bundlePath, 'common'), path.join(bundlePath, dirName)], path.join.apply(bundlePath, [dirName, 'brand.scss']));
Related
First of all I'd like you guys to be gentle. I haven't been coding much in recent year and since gulp update when then changed syntax to writing functions and exporting I somehow made it work then and left with no changes up to this point, no clue if they changed something else. I've been happy with what it is right now, but I have no idea how to make it work the other way.
So anyway I'm working on a project right now, where there will be many htmls, and each one will have quite different styles, but some will be common. I want to make a main.scss file with common styles for each html, but I want to make a separate scss with styles specific to each html. This way in the end I want to have a separate css file made from a specific scss with same name combined with main.scss, so that it won't have to download a single large file, but only styles I need.
Example:
main.scss
01.scss
02.scss
03.scss
will compile to:
01.css ( main.scss + 01.scss )
02.css ( main.scss + 02.scss )
03.css ( main.scss + 03.scss )
This is my gulpfile right now:
const gulp = require('gulp');
const sass = require('gulp-sass');
const browserSync = require('browser-sync').create();
function style() {
return gulp.src('./scss/**/*.scss')
.pipe(sass().on('error', sass.logError))
.pipe(gulp.dest('./css'))
.pipe(browserSync.stream());
}
function watch() {
browserSync.init({
server: {
baseDir: './'
}
});
gulp.watch('./scss/**/*.scss', style);
gulp.watch('./*.html').on('change', browserSync.reload);
gulp.watch('./js/**/*.js').on('change', browserSync.reload);
}
exports.style = style;
exports.watch = watch;
If you have an idea how to do it in a better way I would really appreciate it.
I think you will have to import your main.scss into each of your other files and exclude main.scss from your gulp.src.
function style() {
return gulp.src(['./scss/**/*.scss', '!./scss/**/main.scss'])
.pipe(sass().on('error', sass.logError))
.pipe(gulp.dest('./css'))
.pipe(browserSync.stream());
}
'!./scss/**/main.scss' this negates or excludes that file from being passes into this task - I assumed main.scss was in the same folder as your other scss files, if that is not the case you will have to modify the path.
Then #import main.scss into each of your 01.scss, 02.scss, etc. files:
#import "main.scss"; // also assumes in same folder
You can put this import statement anywhere in the file, if it is first any of main.scss styles will be overridden by conflicting styles in the rest of the 0x.scss file. If you put the import statement at the end, then main.scss styles will override any previous conflicting styles.
Note: you should really be using #use instead of #import and gulp-dart-sass instead of gulp-sass at this point. See sass #use rule.
// in your gulpfile.js
const sass = require('gulp-dart-sass'); // once installed
#use "main.scss"; // must be at top of each scss file, such as 01.scss
How do I correctly import a non-plugin npm module into Ember?
I'm trying to use the sass version of flag-icon-css with ember-cli so that the sass is being built during deploy with the rest of ember-cli-sass, but I can't figure out how to do it in an automated fashion (e.g. without manually copying files over to public).
Using ember-auto-import seems like a good place to start but it is more tailored towards javascript imports.
I have tried this configuration in ember-cli-build.js:
'sassOptions': {
includePaths: [
'node_modules/flag-icon-css/sass' // flag-icon.scss
]
},
It will add the styles, but it doesn't include the images used in the styles.
I have read this documentation, but it doesn't specify something more complicated than a single file.
Just use ember-cli-sass:
first add it to includePaths in your ember-cli-build.js
new EmberApp({
sassOptions: {
includePaths: [
'node_modules/flag-icon-css/sass'
]
}
});
use it with #import "flag-icon";
Have a look in the readme.
now while this will sucessfully add the compiled sass output to your /assets/app-name.js there is no automated way to add any kind of assets to your dist folder.
In the case of flag-icon-css it will just add background-image: url(../flags/4x3/gr.svg); to your dist/assets/app-name.css, but not add the svg itself. You can manually do this with broccolis Funnel and MergeTrees:
install broccoli-funnnel and broccoli-merge-trees
import them in ember-cli-build.js:
const Funnel = require('broccoli-funnel');
const MergeTrees = require('broccoli-merge-trees');
use them by replacing return app.toTree() in your ember-cli-build.js with
const flagIcons = Funnel('node_modules/flag-icon-css', { include: ['flags/**/*'] });
return new MergeTrees([app.toTree(), flagIcons]);
so your entire ember-cli-build.js could look like this:
'use strict';
const EmberApp = require('ember-cli/lib/broccoli/ember-app');
const Funnel = require('broccoli-funnel');
const MergeTrees = require('broccoli-merge-trees');
module.exports = function(defaults) {
let app = new EmberApp(defaults, {
// Add options here
sassOptions: {
includePaths: [
'node_modules/flag-icon-css/sass'
]
}
});
const flagIcons = Funnel('node_modules/flag-icon-css', { include: ['flags/**/*'] });
return new MergeTrees([app.toTree(), flagIcons]);
};
a short sidenote: I would usually recommend to put assets into the assets folder of your output, but in this case this wont work because the flag-icon-css expects the flags folder to be in the parent directory of the .css.
I figured this out, but I'm not sure it's the best or easiest way. It has some drawbacks.
const EmberApp = require('ember-cli/lib/broccoli/ember-app')
const Funnel = require('broccoli-funnel')
module.exports = function(defaults) {
const app = new EmberApp(defaults, {
'sassOptions': {
includePaths: [
'node_modules/flag-icon-css/sass'
]
}
})
const flags = new Funnel('node_modules/flag-icon-css/', {
srcDir: 'flags',
destDir: '/flags',
})
return app.toTree([flags])
}
The drawback is that the css image urls are not processed, and hardlinked to ../flags, so I have to funnel them into /flags, which is not the convention, as these assets should be compiled into public/assets/images.
This is a two-step implementation (or more steps if the npm module would be more complex). It would be preferred to include just the scss and have (an) Ember (plugin) automatically fetch the dependent resources.
I'm developing a lightweight Wordpress theme and I'd like to use the required style.css file as my only CSS file.
My requirements are:
It must have the Wordpress stylesheet header,
and CSS code on it should be minified.
I'm using SASS and I'm transpiling it with gulp-sass. Right now, I'm doing:
/* gulpfile.babel.js */
const base = {
src: 'src',
dest: 'my-theme'
};
const routes = {
sass: {
src: `${base.src}/scss/style.scss`,
dest: `${base.dest}/`
}
};
gulp.task('styles', () => {
return gulp.src(routes.sass.src)
.pipe(plumber((err) => {
console.error(err.message);
}))
.pipe(sass())
.pipe(autoprefixer())
.pipe(gulp.dest(routes.sass.dest));
});
And my style.scss contains:
/*
Theme Name: My Theme Name
Theme URI: http://example.com/my-theme
Author: My name
Author URI: http://example.com/
Description: My theme description
Version: 1.0
License: GNU General Public License v3 or later
License URI: http://www.gnu.org/licenses/gpl-3.0.html
Tags: custom, lightweight
Text Domain: textdomain
This theme, like WordPress, is licensed under the GPL.
Use it to make something cool, have fun, and share what you've learned with others.
*/
#import 'common';
This works but it doesn't fit my 2nd requirement (minified CSS). If I add
.pipe(sass({outputStyle: 'compressed'}))
then I'm loosing the header. I can't find any option on gulp-sass or node-sass to both minify & preserve /* … */ comments.
Has anyone figured out a solution for this?
Don't use the compress option to minify your css. Use the gulp-cssnano plugin instead. It's better anyway and it supports a discardComments options that you can set to false in order to preserve comments:
var cssnano = require('gulp-cssnano');
gulp.task('styles', () => {
return gulp.src(routes.sass.src)
.pipe(plumber((err) => {
console.error(err.message);
}))
.pipe(sass())
.pipe(autoprefixer())
.pipe(cssnano({discardComments:false}))
.pipe(gulp.dest(routes.sass.dest));
});
My suggestion is you can use gulp-concat and run-sequence to achieve your requirement. You can separate the header into another file, wait for the sass task finishes, and concat it and the header file together.
var gulp = require('gulp');
var runSequence = require('run-sequence');
var concat = require('gulp-concat');
/**
* Gulp task to run your current styles and
* the task to append the header in sequence
*/
gulp.task('stylesWithHeader', function(callback) {
runSequence('styles', 'prepend-header', callback);
});
/**
* Gulp task to generate the styles.css file with theme header
*/
gulp.task('prepend-header', function(callback) {
return gulp.src([HEADER_FILE.txt, COMPILED_STYLES_WITHOUT_HEADER.css])
.pipe(concat("styles.css"))
.pipe(gulp.dest(PATH_TO_YOUR_TEMPLATE))
;
});
Gulp concat: https://www.npmjs.com/package/gulp-concat.
Gulp run sequence: https://www.npmjs.com/package/run-sequence
I want to organize my HTML, JS, and LESS by module. I'm already using Grunt to compile *.js and *.html from my source folders.
So I configured grunt as follows:
grunt.initConfig({
less: {
ALL: {
files: { 'compiled.css': '**/*.less' }
}
}
}
But this runs into a major problem: constants and mixins from my /helper/*.less files are not accessible to other .less files.
It seems like grunt-contrib-less compiles each individual .less file, and then combines the output, but doesn't compile anything "globally".
The only solution I can think of is to create and maintain a master.less that #imports each individual .less file. But I'm trying to achieve an extremely modular build process, and I don't have to list any HTML or JS files, so I'm really hoping to find a *.less solution too!
Thanks to #seven-phases-max for the following answer!
less-plugin-glob
Allows you to use wildcards in #import statements! Works perfectly!
// master.less
#import "helpers/**/*.less";
#import "modules/**/*.less";
And all you need to add to your Grunt configuration is the plugins option:
// Gruntfile.js
grunt.initConfig({
less: {
'MASTER': {
src: 'master.less',
dest: 'master.css',
options: {
plugins: [ require('less-plugin-glob') ]
}
}
}
});
And, don't forget, npm install less-plugin-glob.
Here's one way to achieve an effortless development experience.
However, it requires a generated file and a custom task.
Auto-generate the master.less file
Create a task that generates master.less by writing an #import statement for each *.less file:
grunt.registerTask('generate-master-less', '', function() {
generateFileList({
srcCwd: 'modules',
src: '**/*.less',
dest: 'less/master.less',
header: '// THIS FILE IS AUTOMATICALLY GENERATED BY grunt generate-master-less\n',
footer: '// THIS FILE IS AUTOMATICALLY GENERATED BY grunt generate-master-less\n',
template: '#import "<%= filename %>";\n',
join: ''
});
});
function generateFileList(options) {
var _ = grunt.util._;
var files = grunt.file.expand({ cwd: options.srcCwd }, options.src);
var results = files.map(function (filename) {
return _.template(options.template, { 'filename': filename });
});
var result = options.header + results.join(options.join) + options.footer;
grunt.file.write(options.dest, result);
}
Then, use grunt-contrib-less to just build master.less.
I'm using gulp-ruby-sass to compile my js and sass.
I ran into this error first TypeError: Arguments to path.join must be strings
Found this answer and it was because I was using sourcemaps with gulp-sass and the answer recommended using gulp-ruby-sass instead.
Next I tried to compile all my SASS files using this syntax:
gulp.task('sass', function () {
return sass('public/_sources/sass/**/*.scss', { style: 'compressed' })
.pipe(sourcemaps.init())
.pipe(concat('bitage_public.css'))
.pipe(sourcemaps.write('./maps'))
.pipe(gulp.dest('public/_assets/css'))
.pipe(livereload());
});
Which produced this error:
gulp-ruby-sass stderr: Errno::ENOENT: No such file or directory - public/_sources/sass/**/*.scss
I then noticed in the answer I found the author wrote that globes ** aren't supported yet:
Also keep in mind, as of this writing when using gulp-ruby-sass 1.0.0-alpha, globs are not supported yet.
I did more digging and found a way to use an Array to specify the paths to my SASS files, so then I tried the following:
gulp.task('sass', function () {
return sass(['public/_sources/sass/*.scss',
'public/_sources/sass/layouts/*.scss',
'public/_sources/sass/modules/*.scss',
'public/_sources/sass/vendors/*.scss'], { style: 'compressed' })
// return sass('public/_sources/sass/**/*.scss', { style: 'compressed' })
.pipe(sourcemaps.init())
.pipe(concat('bitage_public.css'))
.pipe(sourcemaps.write('./maps'))
.pipe(gulp.dest('public/_assets/css'))
.pipe(livereload());
});
But still I'm getting Errno::ENOENT: No such file or directory and it lists all the dirs I put into that array.
How do you compile SASS in multiple directories with gulp?
SASS source folder structure:
_sources
layouts
...scss
modules
...scss
vendors
...scss
main.scss
Figured it out!
Well not 100%, still not sure why the multiple path array didn't work.
Anyways so I forgot that in my main web.scss file I already had multiple import statements setup:
#import "vendors/normalize"; // Normalize stylesheet
#import "modules/reset"; // Reset stylesheet
#import "modules/base"; // Load base files
#import "modules/defaults"; // Defaults
#import "modules/inputs"; // Inputs & Selects
#import "modules/buttons"; // Buttons
#import "modules/layout"; // Load Layouts
#import "modules/svg"; // Load SVG
#import "modules/queries"; // Media Queries
So I didn't actually need to try use Gulp the way I was trying, I just needed to target that 1 .scss file directly. So I did that here:
// Compile public SASS
gulp.task('sass', function () {
return sass('public/_sources/sass/bitage_web.scss', { style: 'compressed' })
.pipe(sourcemaps.init())
.pipe(sourcemaps.write('./maps'))
.pipe(gulp.dest('public/_assets/css'))
.pipe(livereload());
});
Now it works because it sees a specific file to target and compile
I was having trouble using '*.scss' too
In the git documentation (https://github.com/sindresorhus/gulp-ruby-sass) they use this sintax:
gulp.task('sass', function(){
return sass('public/_sources/sass/',
{ style: 'compressed'})
.pipe(sourcemaps.init())
});
I tested it and it works, it compiles all the files within the folder.
Just in case someone has the same problem