Gulp.js: task based on forEach loop - javascript

I have an array of objects that looks like the following.
var bundles = [
{
src: 'js/my-component/*.js',
bundleName: 'my-component.js'
},
{
src: 'js/my-other-component/*.js',
bundleName: 'my-other-component.js'
}
]
I want the gulp task to process/concat every entry in the array, but it doesn't seem to work.
gulp.task('bundlejs', function(){
return bundles.forEach(function(obj){
return gulp.src(obj.src)
.pipe(concat(obj.bundleName))
.pipe(gulp.dest('js/_bundles'))
});
});

You should probably be merging the streams and returning the result, so that the task will complete at the appropriate time:
var es = require('event-stream');
gulp.task('bundlejs', function () {
return es.merge(bundles.map(function (obj) {
return gulp.src(obj.src)
.pipe(concat(obj.bundleName))
.pipe(gulp.dest('js/_bundles'));
}));
});

This solution does work, I had the wrong directory name. Doh.
https://github.com/adamayres/gulp-filelog helped me find the problem.

Related

Gulp - Async Completion with a Loop

I'm working with a Gulp file. In this file, I have two functions that perform two separate tasks. These functions are called using the following:
gulp.task('build', gulp.parallel(buildJs, buildCss));
When the build task is executed, I receive the following error:
The following tasks did not complete: default, build, buildCss
Did you forget to signal async completion?
My buildCss function is defined like this:
const files= [
{ input:'core.scss', output:'core.css' },
{ input:'theme.scss', output:'theme.css' },
{ input:'controls.scss', output:'controls.css'}
];
function buildCss() {
files.forEach(function(f) {
return gulp.src(`./scss/${f.input}`)
.pipe(sass())
.pipe(concat(f.output))
.pipe(gulp.dest('./'))
;
});
}
I suspect that each iteration of the loop is spinning up it's own thread. So, Gulp never knows when buildCss is finished. Which means, somehow, I need to know when all of the .css files are generated and call something. I'm unsure how to do the last piece if my understanding is correct though.
How do I address async completion of items in a loop in Gulp?
Thank you!
You can use .on('end') and create a Promise for each task, and then check that all promises went ok, sth like this should work:
function buildCss() {
return Promise.all(files.map(task => {
return new Promise((resolve,reject) => {
return gulp.src(`./scss/${task.input}`)
.pipe(sass())
.pipe(concat(task.output))
.pipe(gulp.dest('./'))
.on('end', () => resolve())
;
});
}));
}

Cannot find name 'jQuery' error in controller.js

I am developing a UI5 app in VS Code.
I added a new count function to the *.controller.js file, and in order to display the count from the server, I am using jQuery like in the following code:
jQuery.each(this._mFilters, function (sFilterKey, oFilter) {
oModel.read("/portfolios/$count", {
filters: oFilter,
success: function (oData) {
var sPath = "/" + sFilterKey;
oViewModel.setProperty(sPath, oData);
}
});
});
Unfortunately, I get the following error:
Does anyone know why was the error triggered and how it can be fixed?
Any help or suggestion is much appreciated.
I assume this._mFilters is an object. In that case, try with:
Object.keys(this._mFilters).map(sFilterKey => {
const oFilter = this._mFilters[sFilterKey];
oModel.read("/portfolios/$count", {
filters: [ oFilter ],
success: function(sCount) {
const sPath = `/${sFilterKey}`;
oViewModel.setProperty(sPath, +sCount);
},
});
});
Also the parameter filters awaits an array instead of a single Filter instance.
If jQuery is still preferred, include "sap/ui/thirdparty/jquery" (formerly "jquery.sap.global") to the dependency list of the controller.
sap.ui.define([
"sap/ui/core/mvc/Controller",
// ...,
"sap/ui/thirdparty/jquery",
], function(Controller,/*...,*/ jQuery) {
// jQuery is here available
});

Meteor/mongoDb find and update

I'm just learning Meteor and I made a little app but I have a problem with find() and update() collection on server side
For example:
if (Meteor.isServer) {
function getCollection1(){
return collection_1.find({}).fetch({});
}
....
Meteor.methods({
start: function(id) {
datas = getCollection1();
Collection2.update({_id:id}, {$set: {datas: datas}}); //sometimes it's ok(3/4)
}
...
}
Or when I await, I have an error
if (Meteor.isServer) {
async function getCollection1(){
return await collection_1.find({}).fetch({});
}
....
Meteor.methods({
start: function(id) {
getCollection1().then(function(datas){
Rooms.update({_id: id}, {$set: {datas: datas}},function(err){
console.log(err);//error: Meteor code must always run within a fiber
});
});
}
...
}
What did I do wrong?
EDIT
it seems to work well with Fiber()
if (Meteor.isServer) {
Fiber = Npm.require('fibers')
function getCollection1(){
return collection1.find({}).fetch({});
}
function setCollection2(id){
Fiber(function() {
datas = getCollection1();
collection2.update({_id: id}, {$set: {datas: datas}},function(err){
console.log(err);
});
}).run();
}
....
Meteor.methods({
start: function(id) {
setCollection2(id);
}
...
}
With the async/await version, you do not need to use Fiber. Instead you could this Meteor function: Meteor.bindEnvironment to make it work:
// ...
getCollection1().then(Meteor.bindEnvironment(function(datas){
Rooms.update(// ...);
}));
// ...
For a more understandable explanation, you could consult this video:
What is Meteor.bindEnvironment?
Based on the code you provided, my guess is that for the first example the "Collection2.update" is taking place before GetCollection1() is completed. If this is indeed the case, then on the client side when you subscribe to the collection be sure to have a way to "wait" for the subscription to complete.
For example something like this on the client side where "start()" is called...
const handle = Meteor.subscribe( 'collection_1' );
if ( handle.ready() ) {
Meteor.call('start');
} else {
const allusers = Meteor.users.find().fetch();
onData( null, {allusers} );
}
Again, this is my best guess as you did not post the error you received with your first code chunk and I can't speak for the second you in which you've attempted to implement this.

Using the parameter error to separate failed process's in async.mapLimit

I'm using async.mapLimit to make some concurrency procedures upon an array with limit of 10:
async.mapLimit(files, 10, function(file, callback) {
... etc...
}, function(error, files) {
... etc..
});
Inside the main function, i'm executing a async operation with child_process, and if everything happen as it should, i just call the callback:
callback(null, files);
But... when something bad happens, i also NEED call the callback passing the file, because i don't want end everything, i just assign the file with a error property and call the callback:
file.error = error;
callback(null, file);
So, when the second async.mapLimit callback is fired, i have an array of files:
, function(error, files) {
console.log(files);
});
output:
[
{
name: 'file_2',
error: 'something'...
},
{
name: 'file_1',
...etc
}
]
So, i need separate the files that failed, doing:
var failedFiles = [];
var okFiles = [];
files.forEach(function(file) {
if (file.error)
failedFiles.push(file);
else
okFiles.push(file;
});
I would like to know if isn't possible to return the files that failed as an array, and access then by the parameter error of the second async.mapLimit callback.
Thanks in advance :).
async.mapLimit() will stop immediately when an iteration "returns" an error, so it's not possible to do what you want.
As an alternative, instead of using async.mapLimit() you could use async.eachLimit() and push the file objects into the respective array inside the iterator function:
var failedFiles = [];
var okFiles = [];
async.eachLimit(files, 10, function(file, callback) {
if (SOME_ERROR) {
failedFiles.push(file);
} else {
okFiles.push(file);
}
callback();
}, function(err) {
...
});

Why is this causing a server error

I am try to publish posts created by the usernames in the following array each users has. I am adding this to the microscope practice app The error is I20140826-20:31:53.452(-4)? at Meteor.publish.Comments.find.postId [as _handler] (app/server/publications.js:2:13). Thanks in advanced here is the code.
publications.js
The loop is supposed to publish posts made by each username in the following array.
Meteor.publish('posts', function(options) {
for (u=0;u<this.user.profile.following.length;u++) {
f=profile.following[u].text();
return Posts.find({username:f}, options);
}
});
The Routes it will affect
Controllers
PostsListController = RouteController.extend({
template: 'postsList',
increment: 5,
limit: function() {
return parseInt(this.params.postsLimit) || this.increment;
},
findOptions: function() {
return {sort: this.sort, limit: this.limit()};
},
waitOn: function() {
return Meteor.subscribe('posts', this.findOptions());
},
posts: function() {
return Posts.find({}, this.findOptions());
},
data: function() {
var hasMore = this.posts().count() === this.limit();
return {
posts: this.posts(),
nextPath: hasMore ? this.nextPath() : null
};
}
});
NewPostsListController = PostsListController.extend({
sort: {submitted: -1, _id: -1},
nextPath: function() {
return Router.routes.newPosts.path({postsLimit: this.limit() + this.increment})
}
});
BestPostsListController = PostsListController.extend({
sort: {votes: -1, submitted: -1, _id: -1},
nextPath: function() {
return Router.routes.bestPosts.path({postsLimit: this.limit() + this.increment})
}
});
Router map
this.route('newPosts', {
path: '/new/:postsLimit?',
controller: NewPostsListController
});
this.route('bestPosts', {
path: '/best/:postsLimit?',
controller: BestPostsListController
});
Your publish function is wrong, are you aware that your loop is useless because it is exiting upon encountering the first return ?
Even if you were aggregating the cursors accumulated in the loop this wouldn't work because at the moment a publish function can only return multiple cursors from DIFFERENT collections.
You need to use the appropriate mongo selector here, which is probably $in.
Also, profile.following is not even defined in the publish function, and iterating over an array is done by checking the iterator variable against the array length (profile.following.length), or better yet using Array.prototype.forEach or _.each.
I think this is what you're trying to do :
Meteor.publish("posts",function(options){
if(!this.userId){
this.ready();
return;
}
var currentUser=Meteor.users.findOne(this.userId);
return Posts.find({
username:{
$in:currentUser.profile.following
}
},options);
});
You should definitely read resources about JavaScript itself before digging any further in Meteor, if you're following the Discover Meteor book I think they provide some good JS tutorials for beginners.

Categories