Pass data between gulp tasks without writing to disk - angularjs

I'm trying to annotate and minify a systemjs angular project. Systemjs comes with a build function, but it is not `'gulp-aware'. There is the possibility to pass the builder an option to minify, but there is not one for ng-annotate, so I will need gulp to do both for me instead.
gulp.task('bundle', function () {
var options = {}
builder.buildStatic('./assets/app/app.js', options)
.then(function(data) {
console.log("then called");
// make data available for another task
});
How can I combine the above with
gulp.task('productionApp', function() {
return [source the output from 'bundle']
.pipe(ngannotate())
.pipe(uglify())
.pipe(gulp.dest('./dist'));
});
I could just output the first task to a file, and then .src that in, but that can't be the best way?

The simplest way is to save it inside a buffer (actually, a simple object), then make a stream of and continue as you would with src.
Gulp's repository contains a recipe how it's done.
Note: you should make all those load-* tasks to run at the very beginning, you can either use run-sequence as they've done or make them as dependencies of the "real" tasks.

The yargs package on npm exports the object argv, wich is a very clever representation of the command-line params. For example, the invocation
gulp -a test -b 123 my-task
is represented during the run by a param argv with value
{ a: 'test', b: 123 }
which is passed to the gulp task my-task and, before it, to all its predecessors.
If one of the predecessors assigns a new prop to argv
argv.newProp = 'newValue'
this prop will be available to all its successors, including the task that you really want to execute.
The instruction const { argv } = require('yargs') is to be put at the start of the gulpfile, and it can be enriched with aliases and defaults. Reference is here

Related

Gulp Compiling Angularjs 1 Scripts in, incorrect order

Why does this happen? When I compile the scripts using GULP the console will display errors, explaining that my directives and/or my controllers are not registered. Then to correct this error I create the app variable within the controller file and it then renders a new error, then I put the app variable declaration back and everything works fine.
This is my Gulp Script
var gulp = require('gulp'),
plugins = require('gulp-load-plugins')({
pattern: ['gulp-*', 'gulp.*'],
replaceString: /\bgulp[\-.]/
});
var path = {
jsFiles: "./js/**",
scriptFile: "scripts.min.js",
output: "dist/assets/"
};
var options = {
ie8: true,
warnings: true,
mangle: true
};
gulp.task('scripts', function (cb) {
return gulp.src(path.jsFiles)
.pipe(plugins.sourcemaps.init())
.pipe(plugins.jsdoc3(cb))
.pipe(plugins.concat(path.scriptFile))
.pipe(plugins.babel())
.pipe(plugins.ngAnnotate())
.pipe(plugins.uglify(options))
.pipe(plugins.sourcemaps.write("../../maps"))
.pipe(gulp.dest(path.output))
})
TLDR: MY Gulp task sometimes compiles the AngularJS directives and controllers out of order rendering my app declaration undefined.
When you pass globe to the
gulp.src
No ordered is guaranteed, so it is possible to get wrong order time to time. But gulp.src also accepts array of the pathes you need to include and this should guarantee the order
So, try to split your bundle and pass path to the angular.min.js as a first element like this:
gulp.src(['path/to/angular.min.js', 'path/to/your/code'])
You should sort angular files, and there are some libs that does that.
https://www.npmjs.com/package/gulp-angular-filesort is one of them.

Can somebody explain the `clean` dependency in this gulpfile?

Trying to study https://github.com/jhades/angularjs-gulp-example/blob/master/gulpfile.js, and I have noticed that for the task build there is a dependency clean. However, for most of the other definitions clean is also specified as a dependency! So if I run build it will run clean, but then what about build-css and build-template-cache which both also have clean dependencies, etc... will it also run the clean for each of those dependencies? So basically will running the one command gulp build end up running clean more than once... wiping out the output from other dependencies.... or will running clean the first time explicitly satisfy the dependency for the other dependencies and prevent clean from running again!?
Any pointers will be appreciated.
Please Note
I am NOT asking about what the proper cleaning techniques are! I am specifically asking about the link that I posted... and how IT is handling the clean task.
Dependencies
Dependencies in a gulp file just say that it has to have run before it at least once. For example this code:
var gulp = require('gulp');
gulp.task('main', ['b', 'a'], function() {
return gulp;
});
gulp.task('a', ['b'], function() {
return gulp;
});
gulp.task('b', ['a'], function() {
return gulp;
});
Will run like this:
main
a
b
Not:
main
a
b
a
b
Repeating infinitely.
Dependencies execution order
However, it could just as easily be run in the order main, b, then a. This is because of synchronous tasks in gulp. The dependencies have to run before the task asynchronously, but they run together or synchronously, this answer explains the difference between synchronous and asynchronous.
To avoid this you can use this code in Gulp 4:
gulp.task('main', function() {
gulp.series('a', 'b');
});
This will always run in the order main, a, b
But below that, you need to use the run-sequence package. Here's an example:
var runSequence = require('run-sequence');
gulp.task('main', function() {
runSequence('a', 'b');
})

Using VS 2015/gulp for versioning js files

I'm using VS 2015, ASP.NET 5 (MVC 6) and Gulp to write a SPA with angularjs and supplementary modules. My target framework is dnx451. I've read several best practices which state that the response from Index should have a strict no cache policy set, and all other resources (e.g. js, css, img) should all be heavily cached. In doing so, the browser always downloads the lightweight page and caches the scripts. When publishing, I am trying to have a gulp task which concats/uglifys all my JS files and outputs a single app.min.{version}.js (also for the less -> css file). This gives the benefit of always downloading the latest file version, but keeping them in cache while it is the latest and greatest.
Is there a way to get the Version (from project.json) and the build (from the * portion of project.json) from my gulp task? I am looking for a way to have the file {version} portion of the name match the version/build of the website.
I have seen examples of using process.env in gulp for VS environment variables, but am having trouble putting the pieces together to achieve the desired Version.Build format.
I have tried:
var project = require('./project.json');
gulp.task('js-publish', function(){
project.version; //this give 1.0.0-* (makes sense since its a string)
});
and
gulp.task('js-publish', function(){
process.env.BUILD_VERSION; //which is undefined
});
You want to use the gulp-rename NPM package to rename the file. Add gulp-rename to your package.json file. Here is an example of how it can then be used in your gulpfile.js:
var rename = require("gulp-rename");
// rename via string
gulp.src("./src/main/text/hello.txt")
.pipe(rename("main/text/ciao/goodbye.md"))
.pipe(gulp.dest("./dist")); // ./dist/main/text/ciao/goodbye.md
// rename via function
gulp.src("./src/**/hello.txt")
.pipe(rename(function (path) {
path.dirname += "/ciao";
path.basename += "-goodbye";
path.extname = ".md"
}))
.pipe(gulp.dest("./dist")); // ./dist/main/text/ciao/hello-goodbye.md
// rename via hash
gulp.src("./src/main/text/hello.txt", { base: process.cwd() })
.pipe(rename({
dirname: "main/text/ciao",
basename: "aloha",
prefix: "bonjour-",
suffix: "-hola",
extname: ".md"
}))
.pipe(gulp.dest("./dist")); // ./dist/main/text/ciao/bonjour-aloha-hola.md

Gulp - How do I control processing order with gulp-concat

I'm trying to generate combined JavaScript and CSS resources into a single file using gulp-concat using something like this:
var concatjs = gulp
.src(['app/js/app.js','app/js/*Controller.js', 'app/js/*Service.js'])
.pipe(concat('app.js'))
.pipe(gulp.dest('build'));
I get a concatted file with this, but the order of the javascript files embedded in the combined output file is random - in this case the controllers are showing up before the initial app.js file, which causes problems when trying to load the Angular app that expects app.js before any of the related resources are loaded. Likewise for CSS resources that get combined end up in random order, and again the order is somewhat important - ie. bootstrap needs to load before the theme and any custom style sheets.
How can I set up the concatenation process so that the order remains intact?
Update
So it turns out the ordering above DOES actually work by explicitly specifying the file order in the array of file specs. So in this case the crucial thing is to list app/js/app.js first, then let the rest of the scripts where order doesn't matter in in any order.
The reason I failed to see this behavior (Duh!) is that Gulp Watch was running and the gulpfile.js update wasn't actually reflected in the output. Restarting gulp did update the script. Neophyte error...
Other Thoughts:
Still wondering though - is this the right place to specify build order? It seems you're now stuffing application logic (load order) into the build script, which doesn't feel right. Are there other approaches to address this?
For an angular application like the one in your example (and it's dependency management), I normally use this kind of syntax: gulp.src(['app\js\app.js', 'app\js\**\*.js']).
You can also use just gulp.src('app\js\**\*.js') if your app.js file is the first one in alphabetic order.
I see your point about moving the load file order into the build script: I had the same feeling till I started using gulp-inject for injecting the unminified files references in my index.html at development time and injecting the bundled, minified and versioned ones in the production index file. Using that glob ordering solution across all my development cycle made so sense to me that i don't think to it anymore.
Finally, a possible solution for this 'ordering smell' can be using browserify but to me it is just complicating the architecture for an angular application: in the end, as you said, you just need that one specific file is called before all the other ones.
For my js i use a particular structure/naming convention which helps. I split it up into directories by feature, where each 'feature' is then treated as a separate encapsulated module.
So for my projects i have,
app/js/
- app.js
- app.routes.js
- app.config.js
/core/
- core.js
- core.controllers.js
- core.services.js
/test/
- .spec.js test files for module here
/feature1/
- feature1.js
- feature1.controllers.js
/feature2/
- feature2.js
- feature2.controllers.js
...
So each directory has a file of the same name that simply has the initial module definition in it, which is all that app.js has in it for the whole app. So for feature1.js
angular.module('feature1', [])
and then subsequent files in the module retrieve the module and add things (controllers/services/factories etc) to it.
angular.module('feature1')
.controller(....)
Anyway, i'll get to the point...
As i have a predefined structure and know that a specific file has to go first for each module, i'm able to use the function below to sort everything into order before it gets processed by gulp.
This function depends on npm install file and npm install path
function getModules(src, app, ignore) {
var modules = [];
file.walkSync(src, function(dirPath, dirs, files) {
if(files.length < 1)
return;
var dir = path.basename(dirPath)
module;
if(ignore.indexOf(dir) === -1) {
module = dirPath === src ? app : dir;
files = files.sort(function(a, b) {
return path.basename(a, '.js') === module ? -1 : 1;
})
.filter(function(value) {
return value.indexOf('.') !== 0;
})
.map(function(value) {
return path.join(dirPath, value);
})
modules = modules.concat(files);
}
})
return modules;
}
It walks the directory structure passed to it, takes the files from each directory (or module) and sorts them into the correct order, ensuring that the module definition file is always first. It also ignores any directories that appear in the 'ignore' array and removes any hidden files that begin with '.'
Usage would be,
getModules(src, appName, ignoreDirs);
src is the dir you want to recurse from
appName is the name of your app.js file - so 'app'
ignoreDirs is an array of directory names you'd like to ignore
so
getModules('app/js', 'app', ['test']);
And it returns an array of all the files in your app in the correct order, which you could then use like:
gulp.task('scripts', function() {
var modules = getModules('app/js', 'app', ['test']);
return gulp.src(modules)
.pipe(concat('app.js'))
.pipe(gulp.dest('build'));
});

Define global values using AMD require.js & backbone.js

I am developing a frontend using the Backbone.js and require.js and everything is going well till i need to create a file named it config.js to store some defaule values to use it in the whole of the application
below is the code of the config.js file
// Filename: config.js
define([''], function(){
var baseUrl = "http://localhost:8888/client/",
apiServer = "http://api-server:8888";
return function(type){
return eval(type);
};
});
in one of my views I would define the config.js then i can access the value of both
var baseUrl = "http://localhost:8888/client/",
apiServer = "http://api-server:8888";
via this line of code below that i put it inside any *.js file on my application
var baseUrl = config('baseUrl');
console.log(baseUrl); //prints out this > http://localhost:8888/client/
the problem here is i am using eval to get the value of what kind of value i need to retrieves, I know it's not safe method to use but could anyone suggest safe solution
RequireJS lets you define objects just like you define more complicated modules. You can have a config module and then use it in whichever other files that require it.
Inside config.js you can do:
define({
baseUrl:"http://localhost:8888/client/",
apiServer:"http://api-server:8888"
});
Then require it in other modules:
//someotherfile.js , defining a module
define(["config"],function(config){
config.baseUrl;// will return the correct value here
//whatever
});
Side note: You can use actual global state (defining the variable on window) but I strongly urge you not to since this will make testing hard, and will make the dependency implicit and not explicit. Explicit dependencies should always be preferred. In the above code and unlike the global it's perfectly clear that the configuration is required by the modules using it.
Note, if you want values that are not valid identifiers you can use bracket syntax too config["baseUrl"] the two (that and config.baseUrl) are identical in JavaScript.
As an alternative solution (and uglier than Benjamin's) you can put both urls into an object:
define([''], function(){
var urls = {
baseUrl: "http://localhost:8888/client/",
apiServer: "http://api-server:8888"
};
return function(type){
return urls[type];
};
});
Still, simply exporting an object is much cleaner.

Resources