Bundle vendor CSS with compiled SCSS to create one CSS file using Gulp 4 - gulp

I have already compiled css files for external libraries like bootstrap, datatable etc. inside a css folder. These files will never be changed at any point so I don't want to compile their scss files and build out every time, hence the use of their css version.
However, I have a scss folder where all the styles for the application are written. What I want to achieve is, every time a change is made to a scss file, compile the scss and generate a css and then bundle this css with the two vendor css files (bootstrap, datatable) to create one single stylesheet and copy it over to the bundles folder.
wwwroot
--- bundles
--- css
--- bootstrap.css, datatables.css
--- js
--- scss
--- components
--- comp1.scss
--- comp2.scss
--- layout
--- header.scss
--- footer.scss
--- main.scss
const {src,dest,watch,series,parallel} = require('gulp');
const sass = require('gulp-sass')(require('sass')),
prefix = require('gulp-autoprefixer'),
minify = require('gulp-clean-css'),
concat = require('gulp-concat'),
sourcemaps = require('gulp-sourcemaps');
function compileScss() {
return src('wwwroot/scss/main.scss')
.pipe(sourcemaps.init())
.pipe(sass({
errLogToConsole: true
}))
.pipe(prefix())
.pipe(sourcemaps.write('.'))
.pipe(dest('wwwroot/css/'));
}
function cssBundle() {
return src([
'wwwroot/css/bootstrap.min.css',
'wwwroot/css/dataTables.css',
'wwwroot/css/main.css'
])
.pipe(concat('styles.css'))
.pipe(dest('wwwroot/bundles/'));
}
function watchTask() {
watch('wwwroot/scss/**/*.scss',
parallel(compileScss));
}
exports.default = series(
parallel(compileScss),
cssBundle,
watchTask
);
The above code works fine first time when I run the >gulp command but any subsequent changes I make to scss files only work as far as compiling and generating the main.css and not bundling with the other two files as watch task continues to run in the background.
Just wondered how I can tell the task to compile the scss, then bundle with the vendor files and copy to the bundles folder every time a change is made to scss.
Thanks in advance

Related

How do I compile Magento 2 LESS media queries with Gulp

I've written a gulp script that basically compiles all of my custom styling on top of my magento 2 theme. And it compiles all of the css apart from the css that is in the LESS Media query mixin:
.media-width(#extremum, #break) when (#extremum = 'max') and (#break = #screen__s) {
I've tried quite a lot from googling the problem to reading and understanding how the mixin works. I find it odd that I don't get an error in my terminal.
function compile(done) {
const brandPaths = ["gcn", "gtn", "embn", "gmbn"];
brandPaths.forEach(brand => {
src(`app/design/frontend/Playsports/theme_frontend_${brand}/web/css/source/_base-theme.less`)
.pipe(less())
.pipe(minifyCSS())
.pipe(rename({ suffix: ".min" }))
.pipe(dest(`app/design/frontend/Playsports/theme_frontend_${brand}/Magento_Theme/web/`));
done();
});
}
function watchChange(done) {
watch("app/design/frontend/Playsports/**/*.less", series(compile));
done();
}
I would expect my gulp script to compile the media queries as well but this is the problem I'm having
If you are looking for something that stays with core magento style and structures, our team has developed this bobmotor/magento-2-gulp that supports:
default magento 2 project structure with theme config inside dev/tools/grunt/configs/themes.js
installation with composer
.less
browsersync and liverreload
compiling es6+ with Babel
creating svg sprites
compiling critical.css (Magento 2.3.3)

Gulp suddenly stopped watching changes, compiling scss to css and opening and reloading page

I have been working on a project for a while, using Gulp for compiling SCSS to CSS (making one CSS file from several SCSS files), minifying CSS, also watching file changes and reloading page with Browser Sync.
While changing some scss and html code and not doing anything to the gulpfile and not renaming any files, page in a browser has suddenly failed and said that it cannot find a page.
I tried to reload the page with "gulp" command and it didn't help.
Now I have several problems. Gulp:
- stopped watching changes;
- compiling scss to css;
- opening and reloading page.
All these worked perfectly before this problem.
Here's my code for Gulp:
var gulp = require("gulp");
var sass = require("gulp-sass");
var watch = require("gulp-watch");
var csso = require("gulp-csso");
var concat = require("gulp-concat");
var browserSync = require("browser-sync").create();
/* Static Server + watching scss/html files */
gulp.task("serve", ["sass"], function() {
browserSync.init({
server: "./"
});
gulp.watch("*.html").on("change", browserSync.reload);
gulp.watch("sass/*.scss", ["sass"]).on("change", browserSync.reload);
});
/* Compile Sass into CSS & auto-inject into browsers */
gulp.task("sass", function() {
return gulp.src("sass/*.scss")
.pipe(sass().on('error', sass.logError))
.pipe(gulp.dest("css"))
.pipe(browserSync.stream());
});
/* Concatenate and minify CSS */
gulp.task("css:build", function() {
gulp.watch("css/*.css").on("change", function() {
return gulp.src("css/*.css")
.pipe(concat("style.concat.css"))
.pipe(csso({
comments: false
}))
.pipe(gulp.dest("css_result"));
});
});
gulp.task("default", ["serve", "css:build"]);
If I run "gulp" in command line now it shows this:
enter image description here
Why could it happen and what steps should I do now?
Solved
Problem's solved. There was a mistake inside one sass file. After a correction everything started working without any other changes.
I would simplify this:
gulp.watch("sass/*.scss", ["sass"]).on("change", browserSync.reload);
to
gulp.watch("sass/*.scss", ["sass"]);
since you are already calling browserSync.stream() at the end of your 'sass' task. Also, try this instead of the browserSync.stream() call:
.pipe(browserSync.reload({stream: true}));
I assume your html file being served by browserSync has the css links produced by the 'sass' task NOT the css produced by the 'css:build' task. Otherwise you will have other problems, probably race issues since your 'css:build' task is running after the 'sass' task produced css is reloaded into the browser.
Let me know if this works for you.
Problem's solved. There was a mistake inside one sass file. After a correction everything started working without any other changes.

How to import bootstrap 4 sass/scss from node_modules using gulp

I'm trying to #import some bootstrap 4 sass files from node_modules but my gulp watcher isn't picking up any changes to those node_modules bootstrap files.
In my main sass file I'm importing bootstrap via:
#import "bootstrap-grid";
#import "bootstrap-reboot";
#import "custom";
Then I also import some "local" sass files (outside of node_modules):
#import "some-file";
#import "some-other-file";
etc.
These local sass files are watched fine, I get recompilation when I do my edits/file save.
My sass gulp task looks like this:
//compile sass
gulp.task('sass', function() {
return gulp.src('src/css/scss/**/*.scss')
.pipe(sass({
includePaths: ['node_modules/bootstrap/scss/']
}))
.pipe(gulp.dest('src/css/'));
});
The key part for me to pick up the bootstrap files was to use the includePaths part.
I am getting the bootstrap grid and what I'm wanting to do is update the node_modules/bootstrap/scss/_custom.scss (which I'm importing) to place bootstrap overrides in.
I'm not quite sure how to get the bootstrap to recompile when I edit/save any node_modules bootstrap files.
I tried updating the includePaths to:
includePaths: ['node_modules/bootstrap/scss/**/*.scss']
But that throws an error, "file to import not found" (bootstrap-grid) which also seems odd to me because it seems like it should be adding/watching sass files (and any sub-directories) down in bootstrap/scss.
My file structure at this point is very simple:
root
|
| node_modules
| bootstrap
| scss
| src
| css
| scss
gulpfile.js
Try adding the sass files from the node_modules to gulp.watch:
gulp.watch([
'node_modules/bootstrap/scss/**/*.scss',
'src/css/scss/**/*.scss'
], ['sass']);
Hope that helps.

Gulp SASS Sourcemap sources are incorrect

I am struggling to get my SASS sourcemaps to work correctly. The problem seems to be the "sources" attribute within the sourcemap and how my SASS files are nested.
I have a Gulp task that compiles SASS to CSS. Here is an example of that
var paths = {
styles: {
src: './Stylesheets/SCSS/',
files: './Stylesheets/SCSS/**/*.scss',
dest: './Stylesheets/CSS/'
}
}
gulp.task('compile-sass', function (){
return gulp.src(paths.styles.files)
.pipe(sourcemaps.init())
.pipe(sass({
outputStyle: 'compressed',
includePaths : [paths.styles.src]
}))
.pipe(prefix({
browsers: ['last 2 Chrome versions'],
cascade: false
}))
.pipe(sourcemaps.write('../Maps/', {
includeContent: false,
sourceRoot: '../SCSS'
}))
.pipe(gulp.dest(paths.styles.dest));
});
The above works for everything else - writing maps to disk, prefixing etc. I am using latest nodejs, gulpjs and relevant npm packages.
An example of folder/asset structure from within my Stylesheets folder:
SCSS/print.scss
SCSS/sectionA/style.scss
SCSS/sectionA/partial/_partialA.scss
SCSS/sectionA/partial/_partialB.scss
SCSS/sectionB/... etc
For SASS files in the root of SCSS/ the sourcemaps work properly. Chrome will show where the source styles are.
For SASS files in a subfolder within SCSS/ the sourcemaps do not work. The problem is the "sources": attribute has the wrong file listed in it.
The print.scss map for example will correctly have "sources":["print.scss"]. But sectionA/style.scss map will have "sources":["style.css"] instead of "sources":["partial/_partialA.scss", "partial/_partialB.scss"] as I would expect.
I have confirmed moving /SCSS/sectionA/style.scss to /SCSS/style.scss and amending any import paths does solve the issue. But I need it to be nested, not in the root of /SCSS.
If I can provide more detail please let me know. I have tried the answer from Path to source map is wrong and it does not solve my issue. I have also tried manipulating mapSources with no avail.
# Update 2019-05-24
My answer talks about using CSSNext. CSSNext was deprecated. The theory in my answer is still applicable using postcss-preset-env.
# Update 2017-03-08
After experimenting with PostCSS, I have used CSSNext to process the CSS after SASS has converted it. CSSNext auto-prefixes and doing it this way retains the connection to the original scss files in the sourcemap.
See my GitHub repo for an example.
After following Mark's feedback and investigating the gulp-autoprefixer module I believe this issue raised on the GitHub repo for gulp-autoprefixer is related to the incorrect sourceroot problem.
Using a variation of the hack from ByScripts I am able to get sourcemaps with the correct sourceroot for nested scss files. The hack used in the ByScripts gulpfile inits the sourcemaps function twice. Once before prefixing, and once after.
I have created a GitHub repo to try and illustrate a reduced test case and a workaround. Inspecting the css produced by the workaround shows the correct relationship back to the source scss.

Gulp watch all files but render only one (sass)

I want to make gulp watch for all changes on my work folders but to generate only one file. Because I use scss which imports all required files, there is no need to compile all .css files, only main one.
Now, my gulpfile.js contains:
var gulp = require('gulp');
var util = require('gulp-util');
var sass = require('gulp-sass');
gulp.task('sass', function () {
return gulp.src('./sass/style.scss')
.pipe(sass().on('error', sass.logError))
.pipe(gulp.dest('./dist/css'));
});
gulp.task('watch', function() {
gulp.watch('./sass/**/*.scss', ['sass']);
});
And I have to go in ./sass/style.scss and save it to triger gulp watch.
I want gulp to watch all files (something like ./**/*.scss) but to render only one - ./sass/style.scss. How to achieve that?
Solution to this is simple, just edit watch part of the gulpfile.js to:
gulp.task('watch', function() {
gulp.watch('./**/*.scss', ['sass']);
});
Which says: watch for all .scss and on change run 'sass' taks.
'sass' taks compiles only ./sass/style.scss'
No need to change anything in gulpfile.js. There is another simpler method you need only add underscore to all SCSS files that are being imported with #import statement (like _*.scss), this will forbid compiler to create separate CSS files.
Example:
mymodular.scss => _mymodular.scss
Guidelines from SCSS documentation
Partials
You can create partial Sass files that contain little snippets of CSS that you can include in other Sass files. This is a
great way to modularize your CSS and help keep things easier to
maintain. A partial is a Sass file named with a leading underscore.
You might name it something like _partial.scss. The underscore lets
Sass know that the file is only a partial file and that it should not
be generated into a CSS file. Sass partials are used with the #use
rule.