Gulp src glob with multiple exclude - gulp

I'm very new to Gulp, trying to figure out how to exclude more than one file from a glob... for instance this works for a single file:
return gulp.src(['assets/js/src/!(app)*.js'])
But is it possible / what would the syntax be for excluding multiple files? E.g. return gulp.src(['assets/js/src/!(app,test)*.js']) but obviously this doesn't work...
EDIT - I am later adding back in the files app.js & test.js so they are added at the end of the minified file.
e.g. (this works for a single file only:) return gulp.src(['assets/js/src/!(app)*.js', 'assets/js/src/app.js'])
I am looking for a solution to add multiple files back in at the end so I can control the order of the minified file. Also, it's important that I can use a glob to catch all files that will be added in future so I don't want to list them explicitly.

In glob the OR pattern is defined like {A,B}. So, this should work:
gulp.src(['assets/js/src/*.js', '!assets/js/src/*{app,test}*.js'])

[You added some crucial information to your original post that completely changes the answer! You should edit your post with the new condition. So, with thanks to #dloeda glob negation:
Now you might try gulp-filter
const gulp = require('gulp');
// const uglify = require('gulp-uglify');
const filter = require('gulp-filter');
gulp.task('default', () => {
// Create filter instance inside task function
const f = filter(['assets/js/src/*.js', '!assets/js/src/*{app,test}*.js'], {restore: true});
return gulp.src('src/**/*.js')
// Filter a subset of the files
.pipe(f)
// Run them through a plugin
// .pipe(uglify())
// Bring back the previously filtered out files (optional)
.pipe(f.restore)
.pipe(gulp.dest('dist'));
});
However, it is not clear to me from the gulp-filter documentation that the f.restore adds the filtered files at the end of the stream or back in their original location in the src stream. If you find that it doesn't put it at the end, let me know and it could be modified to do so by another method.
Also see Contra's answer to adding to src if you are using gulp4.0 it is very easy to add to the src.
Alternatively, gulp-add-src looks very promising and I just discovered it so you could try this alternative code:
var addsrc = require('gulp-add-src');
gulp.task('build', function () {
// start with excluding app.js and test.js
return gulp.src(['assets/js/src/*.js', '!assets/js/src/*{app,test}*.js'])
// .pipe(whatever)
.pipe(addsrc.append('assets/js/src/app.js')) // append app.js to the end of the stream
.pipe(uglify()) // we minify everything
.pipe(gulp.dest('dist')); // and write to dist
});

Related

gulp.dest() is not creating an output file

I have the following code in a gulp task. It's not writing an output file.
const player = {
player: {
src: 'x',
tpl: '<style>%s</style>'
}
}
gulp.src('.src/index.html')
.pipe(replace(player))
.pipe(gulp.dest('./app/));
This has one of those 'well duh' answers. You've left a slash out of your source path. It should be ./src/index.html. Since gulp.src() doesn't throw an error, it doesn't occur to you to check it.
There are two issues in your code.
1. Incorrect path
Your first mistake is that you have gotten an incorrect path.
In the gulp.src() function, you are passing a path to a folder called .src. However, it is most likely supposed to be redirecting to ./src. See the code below for the solution.
gulp.src("./src/index.html");
2. Missing end quote (")
Your other mistake is that you've forgotten to end your string in the .pipe() method (the second one).
The code below should work properly.
.pipe("./app/");
In conclusion, there were two issues in your code.
Incorrect path
Missing end quote (")
When these two are fixed, your code should run correctly.

Gulp concatenation with custom iteration ordering

I am attempting to concat a number of js files within a nested directory structure to a single file in a different location. They have to be concatenated in a specific order and I cannot find a way of changing the default order in which gulp's glob search retrieves nested files. I have tried various glob patterns to no avail.
My directory structure is as follows:
components
- componentA
- controllers
- controllerA1.js
- controllerA2.js
- services
- serviceA1.js
- configA.js
- moduleA.js
- componentB
- controllers
- controllerB1.js
- controllerB2.js
- services
- serviceB1.js
- configB.js
- moduleB.js
I want the files to concatenate to a single file in the following order:
configA.js
moduleA.js
controllerA1.js
controllerA2.js
serviceA1.js
configB.js
moduleB.js
controllerB1.js
controllerB2.js
serviceB.js
So that gulp iterates into each component and iterates down through as far as it can go before moving onto the next component and doing the same.
Instead it concatenates in the following order:
configA.js
moduleA.js
configB.js
moduleB.js
controllerA1.js
controllerA2.js
serviceA1.js
controllerB1.js
controllerB2.js
serviceB1.js
In other words it goes into a top level directory, iterates through each of the top level files in that directory and then jumps to the next top level directory and does the same, before returning to the first top level directory and iterating through the next level down etc etc.
I've tried a couple of different methods which have each presented problems.
I have tried using the gulp-recursive-folder plugin to customise the iteration order as follows:
gulp.task('generateTree', recursivefolder({
base: './components',
exclude: [ // exclude the debug modules from thus build
//'debug-modules'
]
}, function(folderFound){
//This will loop over all folders inside pathToFolder main and recursively on the children folders, secondary
//With folderFound.name gets the folderName
//With folderFound.path gets all folder path found
//With folderFound.pathTarget gets the relative path beginning from options.pathFolder
return gulp.src(folderFound.path + "/**/*.js")
.pipe($.concat("app.js"))
.pipe(gulp.dest('./build/assets/js/'));
}));
This iterates in the order I want but I believe it is writing the first top level dir as one stream and then writing the second dir as another stream so that the second stream overwrites the first. So I am left with only the following files being concatenated:
configB.js
moduleB.js
controllerB1.js
controllerB2.js
serviceB.js
So I've also tried using the add-stream plugin to recursively add to the same stream before writing to file. I won't bore anyone with the details but basically I can't get this to work as desired either. Can anyone recommend a post/tutorial/plugin? Thanks.
gulp.src() respects the ordering of globs that are passed to it and emits files in the same order. That means if you explicitly pass a glob for each component to gulp.src() it will first emit the files for the first component, then for the second component and so on:
gulp.task('default', function() {
return gulp.src([
'components/componentA/**/*.js',
'components/componentB/**/*.js'
])
.pipe($.concat('app.js'))
.pipe(gulp.dest('./build/assets/js/'));
});
Obviously you don't want to maintain that array manually. What you want to do is generate the array based on the components that are available in your project. You can use the glob module for that:
var glob = require('glob');
gulp.task('default', function() {
return gulp.src(glob.sync('components/*').map(c => c + '/**/*.js'))
.pipe($.concat('app.js'))
.pipe(gulp.dest('./build/assets/js/'));
});

Using require on a .json file will return an empty array if file is being required by another function at the same time

I don't have much experience with node but I've run into a pitfall when running code that handles I/O (a simplification of my code):
I have data.json which contains ['foo','bar'] with many functions that read and parse this file like so:
// foo.js
module.exports = function() {
// do stuff
var data = require("path/to/data.json");
return data;
};
// bar.js
module.exports = function() {
// do stuff
var data = require("path/to/data.json");
return data;
};
However when I call them:
// main.js
var foo = require('foo');
var bar = require('bar');
console.log(foo()); // gives ['foo','bar']
console.log(bar()); // gives []
I suspect while foo is reading data.json, it "locks" the file then preventing bar from reading it, but I'm not sure why bar still returns an empty array instead of undefined.
Using require to read a json file was a bad idea as I have them littered throughout my entire codebase. Is there an easy fix for something like this? What would be the preferred method of reading json files knowing that at any given moment that file might be accessed by another function?
As we know, require() will always cache the content of the loaded module (or file, in this case). The next time require() is called again, it will restore it from the cache instead of reading it again.
In your case, you was reading the file once for each foo.js and bar.js. Here, foo had changed a value from the JSON, and because it’s content was cached by require(), the changed value was loaded into bar, in which I was expecting it to be the original value. But, since foo already read it till end, you are at EOF. So, bar returns empty array [there is nothing to read, but file is valid].
SOLUTION:
Stick with fs module when reading JSON files.

Laravel Elixir Gulp mix two separate less files

In Laravel 5 I am trying to create two different css files for my frontend site and backend site (cms). The source files are in two different directories.
The default value for assets in
first the backend
elixir.config.assetsDir = 'resources/backend/';
elixir(function (mix) {
mix.less('backend.less');
});
Second the frontend
elixir.config.assetsDir = 'resources/frontend/';
elixir(function (mix) {
mix.less('frontend.less');
});
Both are in the same gulpfile.js.
These are the directories (Laravel 5)
resources
backend
less
backend.less
frontend
less
frontend.less
Only the frontend file is compiled to public/css/frontend.css.
I also tried
mix.less('frontend.less', null, 'resources/frontend/');
though this is working for mixing script files it is not working for mixing less files.
**Update 28-3-2015 **
There seems to be no solution for my problem. When I do:
elixir.config.assetsDir = 'resources/frontend/';
mix.less('frontend.less');
elixir.config.assetsDir = 'resources/backend/';
mix.less('backend.less');
Only the last one (backend) is executed. When I place the last two lines in comments the first one (frontend )is executed. It's Ok for now because the backend styles should not change very often but it would be very nice to mix multiple less files from multiple resource folders to multiple destination folders.
Try:
elixir(function(mix) {
mix.less([
'frontend/frontend.less',
'backend/backend.less'
], null, './resources');
});
Instead of your variant:
elixir(function(mix) {
elixir.config.assetsDir = 'resources/frontend/';
mix.less('frontend.less');
elixir.config.assetsDir = 'resources/backend/';
mix.less('backend.less');
});
Try this code:
elixir.config.assetsDir = 'resources/frontend/';
elixir(function(mix) {
mix.less('frontend.less');
});
elixir.config.assetsDir = 'resources/backend/';
elixir(function(mix) {
mix.less('backend.less');
});
I have been playing around with this for a couple days and the best option I've found so far is as follows.
First leave your resources files in the default location, so for less files look in resources/assets/less. Then to separate the files into your front and back end resources add sub folders in the specific resource folder like so,
resources/assets/less/frontend/frontend.less
resources/assets/less/backend/backend.less
Now call each one like so..
mix.less('frontend/frontend.less', 'public/css/frontend/frontend.css');
mix.less('backend/backend.less', 'public/css/backend/backend.css');
The second parameter provided to each mix.less can point to wherever you want it to.
You can't split at the highest level directly in the resource root, but it still allows some separation, and everything compiled in one gulp.
I have found the following to work:
elixir(function (mix) {
mix
.less(['app.less'], 'public/css/app.css')
.less(['bootstrap.less'], 'public/css/bootstrap.css');
});
The key things to notice:
provide the file name in the destination, i.e. writing public/css/app.css instead of public/css/
chain the .less calls instead of making two separate mix.less() calls
Works for me with laravel-elixir version 3.4.2

Upload Files to custom location before date folder

I have built a custom contenttype with an image field in Bolt 2.0.
image:
type: image
If no folder is specified the uploaded file goes to a folder named by the year-month
Result: 2014-11/myFileName.jpg
With the tag upload I can change this to something else.
image:
type: image
upload: "News/"
Result: News/myFileName.jpg
Is it possible to get the year-month folders after my costom path?
Result: News/2014-11/myFileName.jpg
The answer to this is yes, but not very simply so if you want a configurable way to do this you need to wait for 2.1 of Bolt where we're going to add variables to the upload: setting.
If you don't mind setting up your own bootstrap file and modifying the application then you can do it now.
The date prefix is generated by the $app['upload.prefix'] setting and currently returns the date string. What you need to do to modify this is change this to your own closure. I haven't tested this on a project so tweak if needed but after:
$app->initialize();
// Redefine the closure
$app['upload.prefix'] = function() {
$setting = $app['request']->get('handler');
$parts = explode('://', $setting);
$prefix = rtrim($parts[0], '/') . '/';
return $prefix.date('Y-m') . '/';
};
$app->run();
What we're doing here is reading the setting which is passed in the request and then concatenating the default date prefix onto the end of it.
As mentioned earlier 2.1 will see variable support introduced into the paths so options like
upload: news/{%month%}/{%day%}
upload: uploads/{%contenttype%}/{%id%}
will be easily definable in the contenttypes.yml file so If you don't mind waiting for a couple of months then this is obviously much simpler.
As of 3.2.9 this {%id%} principle doesn't seem to work yet ... :(