Capture and reuse a glob - sass

I am new to Gulp programming.
I need to define a "dynamic" scss task that compiles multiple source directories in multiple destination directories
src/main/scss/
app.scss (global resource)
modules/ (modules resources)
admin/
*.scss
ftt/
*.scss
The above is the directory layout of the source files.
I am interested in compiling each set of scss files under modules directory (which I may not know in advance) into a directory tree that includes the module itself
src/main/scss/modules/admin/*.scss ==> webapp/secure/admin/common/common.css
src/main/scss/modules/ftt/*.scss==> webapp/secure/ftt/common/common.css
I can write a glob that captures src/main/scss/modules/*/*.scss but how to reuse the star representing the directory? If I was running regex I'd capture and use numbered group $1

For a longer working code version of looping through an array of folders to build folder-based bundles, see Processing arrays within Gulp to create bundles in each directory with ordered files
I would suggest looking at glob.sync. Do a search here for [gulp] glob.sync user:836330. That's me. I have answered a few questions here similar to yours. See particularly running a gulp task on separate folders. It runs the same gulp task on different folders and then uses the folder names to set unique destinations.
glob.sync is great for something like this.
Pseudo code follows (not tested):
const moduleFolders = glob.sync('src/main/scss/modules');
// perhaps your app.scss is supposed to be bundled into each module's css?
// if so, just add a second source to the gulp.src below
const sassSrc = 'common.scss'; // or your main scss file that does the imports in each module
gulp.task('default', () => {
let stream;
// work on each folder separately
moduleFolders.forEach(function (module) {
stream = gulp.src( module + sassSrc )
.pipe(sass())
//.pipe(concat('style.min.css'))
//.pipe(autoprefixer())
//.pipe(cssmin())
.pipe(gulp.dest( "webapp/secure/" + module + '/common' ));
});
return stream;
});

Related

Gulp not compiling ALL sass files

Gulp Function:
function style() {
//1.where is my scss
return gulp.src('src/scss/**/*.scss') //gets all files ending with .scss in src/scss
//2. pass that file through sass compiler
.pipe(sass().on('error',sass.logError))
//3. where do I save the compiled css file
.pipe(gulp.dest('src/css'))
//4. stream change to all browsers
.pipe(browserSync.stream());
}
Folder Structure:
Expected output:
syles.css will have styles written in syles.scss and vendor.scss
Actual Output:
syles.css will have styles written in syles.scss alone. vendor.scss styles are not added in styles.css
Your actual output is correct. You need to #use a partial into your styles.scss if you want only one file styles.css output containing the vendor.scss content.
Modules
You don't have to write all your Sass in a single file. You can split
it up however you want with the #use rule. This rule loads another
Sass file as a module, which means you can refer to its variables,
mixins, and functions in your Sass file with a namespace based on the
filename. Using a file will also include the CSS it generates in your
compiled output!
from https://sass-lang.com/guide
so in your styles.scss at the top:
#use 'vendor;
and then rename vendor.scss to _vendor.scss

gulp doesn't watch my subdirectories

I'm trying to set up gulp to watch all my sass files, but I'm having trouble with my subdirectories.
This is my file structure in the scss folder:
default.scss
-base
-components
My gulpfile is set up like this:
const SCSS_SRC = './src/assets/scss/**/*.scss';
const SCSS_DEST = './src/assets/css';
gulp.task('sass', function () {
return gulp.src(SCSS_SRC)
.pipe(sass().on('error', sass.logError))
.pipe(minifyCSS())
.pipe(rename({ suffix: '.min' }))
.pipe(changed(SCSS_DEST))
.pipe(gulp.dest(SCSS_DEST))
});
gulp.task('default', function () {
gulp.watch(SCSS_SRC, ['sass']);
});
When I run gulp the first time, everything is compiled normally, but if i make changes in my sass files in the subdirectories they are not compiled.
If I make a change in the default style, the files in the subdirectories are compiled too though. But I don't want to have to update the default file everytime I update the other files.
This is the first time I use gulp, so I'm sorry if I'm missing something obvious.
I suggest simply removing the pipe(changed()) call as changed to usually used to filter the stream immediately after gulp.src. Unless you have a huge project I just don't see that it could be very useful right before gulp.dest. It is an easy thing to try to see if it helps.

Combine multiple JS files into two files

I have 3 main JS files:
base.js
notLoggedIn.js
loggedIn.js
base.js contains all of the basic needs for my application and the other two files are self-explanatory.
What I need to do is this:
Combine base.js and notLoggedIn.js into file1.js.
Combine base.js, notLoggedIn.js, and loggedIn.js into file2.js.
And I need it in this order.
Here is what my gulpfile.js currently looks like:
elixir(function(mix) {
mix.sass('app.scss')
.browserify('base.js');
});
How do I modify the file to meet my needs?
Assuming that all three scripts you mention are located in the resources/assets/js directory, you can do the following:
elixir(function(mix) {
mix.scripts(['base.js', 'notLoggedIn.js'], 'public/js/file1.js')
.scripts(['base.js', 'notLoggedIn.js', 'loggedIn.js'], 'public/js/file2.js');
});

Webstorm 6 - How to make the scss file watcher ignore files

I would like the file watcher for SCSS files to ignore files with file names starting with an underscore, for example _buttons.scss.
How would I do that?
Start by adding a _ to a file that you want to be ignored... Done! From the documentation:
Partials
If you have a SCSS or Sass file that you want to import but don’t want
to compile to a CSS file, you can add an underscore to the beginning
of the filename. This will tell Sass not to compile it to a normal CSS
file. You can then import these files without using the underscore.
For example, you might have _colors.scss. Then no _colors.css file
would be created, and you can do
#import "colors";
So adding an underscore will do the job. Just don't import.
Be careful naming your files because if you have a style.scss and _style.scss Sass will see these as the same filename and trow an error:
>>> Change detected to: /Users/allcaps/test/style.scss
WARNING: In /Users/allcaps/test:
There are multiple files that match the name "style.scss":
_style.scss
style.scss
A simple workaround will be to add two underscores: __style.scss.
#LazyOne has the right idea. A Scope can be created that excludes files that being with an underscore (_). The page at http://www.jetbrains.com/phpstorm/webhelp/scopes.html#d437174e402 has more information about this, but basically you select the folder you want after creating a custom scope and then in the scope field append it again with && ! between the two and exclude files starting with an underscore.
For example:
file:website/css//* && !file:website/css//_*

How do I write an Albacore zip task that includes only certain folders and the folders themselves?

I'm trying to zip up the artifacts of a rake build, using Albacore's ZipTask. The solution I'm building has three projects that have artifacts that need to be zipped up individually, but only the ASP.NET MVC project will be mentioned here. Here's the directory structure of the solution:
rakefile.rb
solution.sln
src/
(other projects that are not relevant)
website/
(various folders I don't want included in the artifacts)
bin/
Content/
Scripts/
Views/
Default.aspx
Global.asax
web.config
At first I wrote this task:
website_directory = File.join '.', 'src', 'website'
website_project_name = 'website'
zip :zip => [ :run_unit_tests, :less ] do |zip|
zip.directories_to_zip = [ 'bin', 'Content', 'Scripts', 'Views' ].map{ |folder| File.join website_directory, folder }
zip.additional_files = [ 'Default.aspx', 'favicon.ico', 'Global.asax', 'web.config'].map{ |file| File.join website_directory, file }
zip.output_file = get_output_file_name
zip.output_path = get_artifacts_output_path website_project_name
end
Problem is, the output of this task is a zip file containing the contents of those folders, not the folders themselves, which is obviously undesirable.
Next, I tried flipping the flatten_zip field to false (which is not a documented field but you can find it in the source). This produced a zip that contained the above folders, but at the bottom of the whole ./src/website/ folder hierarchy. I want the above folders at the root of the zip, so that's not working either.
So my next shot was this, using exclusions, which is also not documented:
zip :zip => [ :run_unit_tests, :less ] do |zip|
zip.directories_to_zip website_directory
zip.exclusions = [ /.git/, /.+\.cs/, /App_Data/, /Attributes/, /AutoMapper/, /Controllers/, /Diagrams/, /Extensions/, /Filters/, /Helpers/, /Models/, /obj/, /Properties/, /StructureMap/, /Templates/, /CompTracker.Web.csproj/, /Default.aspx.cs/, /Global.asax.cs/, /Publish.xml/, /pdb/ ]
zip.output_file = get_output_file_name
zip.output_path = get_artifacts_output_path website_project_name
end
This worked for me, but when I recently added /AutoMapper/ and /StructureMap/ to the exclusions array, it also caused AutoMapper.dll and StructureMap.dll to (of course) also be excluded from the bin folder.
How should I edit any of the above tasks to have only the folders and files I want at the root of my zip?
You can copy all the files and folders you need into a temp directory and then zip that up. In other words, set the property directories_to_zip to one folder which has all the correct files already copied in - where the copying code is what does all the filtering for you. I think that's the unspecified expected usage (and the way I use it). I'll just contrast the two ideas to make it clear.
Strategy A: Copy the folder structure
Copy what you need into a temp directory. This way, you set the 'directories_to_zip' property to one folder eg:
directories_to_zip = 'ziptemp/all.my.stuff.copied.here/'
Strategy B: Use a filter
(This is your current strategy)
Use the directories_to_zip property as a filter on an original directory (it is an array that takes multiple directories, so you couldn't be blamed for assuming it should work this way). You then use various properties to filter the files/folders you need.
Possible Resolution
To solve your issue, then, you could adopt Strategy A. Actually, unless there's any extraordinary issues with this (slow PC, amazingly low on disk space), I would have thought this would be a slightly more robust way of going about it because you can be sure that what you are zipping is exactly what you are copying, which can be verified by checking the ziptemp directory.
Incidentally, I can be sure Strategy A works because I use it (with Albacore) to zip files for our installers.
I had the same problem using 'albacore', I wanted to zip a folder called 'tools' (not just the contents), store it in a folder called 'out' and name the zip 'tools.zip ... so instead I used this;
require 'zip/zipfilesystem'
Zip::ZipFile::open("out/tools.zip", Zip::ZipFile::CREATE) { |z|
Dir['{tools}/**/*'].each { |f|
z.add(f, f)
}
}
I know its late but I hope this helps someone.

Resources