Send parameters to jshint reporter in Gulp - node.js

I have Gulpfile with jshint configured to use jshint-stylish reporter. I need to pass option verbose to reporter in order to display warning codes. Is it possible to do it using Gulp?
Current my gulpfile.js looks like below:
var gulp = require('gulp');
var jshint = require('gulp-jshint');
var compass = require('gulp-compass');
var path = require('path');
require('shelljs/global');
var jsFiles = ['www/js/**/*.js', '!www/js/libraries/**/*.js', 'www/spec/**/*.js', '!www/spec/lib/**/*.js'];
var sassFiles = 'www/sass/*.scss';
gulp.task('lint', function () {
return gulp
.src(jsFiles)
.pipe(jshint())
.pipe(jshint.reporter('jshint-stylish'));
});
gulp.task('compass', function () {
gulp.src(sassFiles)
.pipe(compass({
project: path.join(__dirname, 'www'),
css: 'css',
sass: 'sass',
image: 'img',
font: 'fonts'
})).on('error', function() {});
});
var phonegapBuild = function (platform) {
if (!which('phonegap')) {
console.log('phonegap command not found')
return 1;
}
exec('phonegap local build ' + platform);
};
gulp.task('build:android', ['lint', 'compass'], function () {
phonegapBuild('android');
});
gulp.task('build:ios', ['lint', 'compass'], function () {
phonegapBuild('ios');
});
gulp.task('watch', function() {
gulp.watch(jsFiles, ['lint']);
gulp.watch(sassFiles, ['compass']);
});
gulp.task('default', ['lint', 'compass']);

Well, this, plus the fact that the output of the stylish reporter is hardly readable on Windows due to the darkness of the blue text, so I have to keep going in an manually changing the colour after installing it, has made me do something about it. So you should hopefully have more luck with this reporter I've just written:
https://github.com/spiralx/jshint-summary
You basically use it like this;
var summary = require('jshint-summary');
// ...
.pipe(jshint.reporter(summary({
verbose: true,
reasonCol: 'cyan,bold',
codeCol: 'green'
})
and the summary function will initialise the function passed to JSHint with those settings - see the page on Github for a bit more documentation.
It's got some very basic tests, and the library's gulpfile.js uses it to show its own JSHint output :)

How about using similar technique, as you already did with phonegap?
var jshint = function (parameter) {
// todo: define paths with js files, or pass them as parameter too
exec('jshint ' + paths + ' ' + parameter);
};

Based on https://github.com/wearefractal/gulp-jshint/blob/master/index.js#L99 it appears that gulp-jshint doesn't facilitate passing more than the name to the reporter if you load it with a string. It seems a simple thing to extend though. I'll race you to a pull request. :D
Alternatively, try something like this:
var stylish = require('jshint-stylish');
// ...
.pipe(jshint.reporter(stylish(opt)));
I'm pretty sure I have the syntax wrong, but this may get you unstuck.

It's annoying, and makes any decent reporter somewhat tricky to use within the existing framework. I've come up with this hack for the Stylish reporter, it's just currently in my gulpfile.js:
function wrapStylishReporter(reporterOptions) {
var reporter = require(stylish).reporter,
reporterOptions = reporterOptions || {};
var wrapped = function(results, data, config) {
var opts = [config, reporterOptions].reduce(function(dest, src) {
if (src) {
for (var k in src) {
dest[k] = src[k];
}
}
return dest;
}, {});
reporter(results, data, opts);
};
return jshint.reporter(wrapped);
}
And then for the task definition itself:
gulp.task('lint', function() {
return gulp.src('+(bin|lib)/**/*.js')
.pipe(jshint())
.pipe(wrapStylishReporter({ verbose: true }))
.pipe(jshint.reporter('fail'));
});
Ideally reporters would either be a function that takes an options parameter and returns the reporter function, or a fairly basic class so you could have options as well as state.

Related

NodeJS/Express share function between multiple routes files [duplicate]

Let's say I have a file called app.js. Pretty simple:
var express = require('express');
var app = express.createServer();
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.get('/', function(req, res){
res.render('index', {locals: {
title: 'NowJS + Express Example'
}});
});
app.listen(8080);
What if I have a functions inside "tools.js". How would I import them to use in apps.js?
Or...am I supposed to turn "tools" into a module, and then require it? << seems hard, I rather do the basic import of the tools.js file.
You can require any js file, you just need to declare what you want to expose.
// tools.js
// ========
module.exports = {
foo: function () {
// whatever
},
bar: function () {
// whatever
}
};
var zemba = function () {
}
And in your app file:
// app.js
// ======
var tools = require('./tools');
console.log(typeof tools.foo); // => 'function'
console.log(typeof tools.bar); // => 'function'
console.log(typeof tools.zemba); // => undefined
If, despite all the other answers, you still want to traditionally include a file in a node.js source file, you can use this:
var fs = require('fs');
// file is included here:
eval(fs.readFileSync('tools.js')+'');
The empty string concatenation +'' is necessary to get the file content as a string and not an object (you can also use .toString() if you prefer).
The eval() can't be used inside a function and must be called inside the global scope otherwise no functions or variables will be accessible (i.e. you can't create a include() utility function or something like that).
Please note that in most cases this is bad practice and you should instead write a module. However, there are rare situations, where pollution of your local context/namespace is what you really want.
Update 2015-08-06
Please also note this won't work with "use strict"; (when you are in "strict mode") because functions and variables defined in the "imported" file can't be accessed by the code that does the import. Strict mode enforces some rules defined by newer versions of the language standard. This may be another reason to avoid the solution described here.
You need no new functions nor new modules.
You simply need to execute the module you're calling if you don't want to use namespace.
in tools.js
module.exports = function() {
this.sum = function(a,b) { return a+b };
this.multiply = function(a,b) { return a*b };
//etc
}
in app.js
or in any other .js like myController.js :
instead of
var tools = require('tools.js') which force us to use a namespace and call tools like tools.sum(1,2);
we can simply call
require('tools.js')();
and then
sum(1,2);
in my case I have a file with controllers ctrls.js
module.exports = function() {
this.Categories = require('categories.js');
}
and I can use Categories in every context as public class after require('ctrls.js')()
Create two js files
// File cal.js
module.exports = {
sum: function(a,b) {
return a+b
},
multiply: function(a,b) {
return a*b
}
};
Main js file
// File app.js
var tools = require("./cal.js");
var value = tools.sum(10,20);
console.log("Value: "+value);
Console Output
Value: 30
create two files e.g app.js and tools.js
app.js
const tools= require("./tools.js")
var x = tools.add(4,2) ;
var y = tools.subtract(4,2);
console.log(x);
console.log(y);
tools.js
const add = function(x, y){
return x+y;
}
const subtract = function(x, y){
return x-y;
}
module.exports ={
add,subtract
}
output
6
2
Here is a plain and simple explanation:
Server.js content:
// Include the public functions from 'helpers.js'
var helpers = require('./helpers');
// Let's assume this is the data which comes from the database or somewhere else
var databaseName = 'Walter';
var databaseSurname = 'Heisenberg';
// Use the function from 'helpers.js' in the main file, which is server.js
var fullname = helpers.concatenateNames(databaseName, databaseSurname);
Helpers.js content:
// 'module.exports' is a node.JS specific feature, it does not work with regular JavaScript
module.exports =
{
// This is the function which will be called in the main file, which is server.js
// The parameters 'name' and 'surname' will be provided inside the function
// when the function is called in the main file.
// Example: concatenameNames('John,'Doe');
concatenateNames: function (name, surname)
{
var wholeName = name + " " + surname;
return wholeName;
},
sampleFunctionTwo: function ()
{
}
};
// Private variables and functions which will not be accessible outside this file
var privateFunction = function ()
{
};
I was also looking for a NodeJS 'include' function and I checked the solution proposed by Udo G - see message https://stackoverflow.com/a/8744519/2979590. His code doesn't work with my included JS files.
Finally I solved the problem like that:
var fs = require("fs");
function read(f) {
return fs.readFileSync(f).toString();
}
function include(f) {
eval.apply(global, [read(f)]);
}
include('somefile_with_some_declarations.js');
Sure, that helps.
Create two JavaScript files. E.g. import_functions.js and main.js
1.) import_functions.js
// Declaration --------------------------------------
module.exports =
{
add,
subtract
// ...
}
// Implementation ----------------------------------
function add(x, y)
{
return x + y;
}
function subtract(x, y)
{
return x - y;
}
// ...
2.) main.js
// include ---------------------------------------
const sf= require("./import_functions.js")
// use -------------------------------------------
var x = sf.add(4,2);
console.log(x);
var y = sf.subtract(4,2);
console.log(y);
output
6
2
The vm module in Node.js provides the ability to execute JavaScript code within the current context (including global object). See http://nodejs.org/docs/latest/api/vm.html#vm_vm_runinthiscontext_code_filename
Note that, as of today, there's a bug in the vm module that prevenst runInThisContext from doing the right when invoked from a new context. This only matters if your main program executes code within a new context and then that code calls runInThisContext. See https://github.com/joyent/node/issues/898
Sadly, the with(global) approach that Fernando suggested doesn't work for named functions like "function foo() {}"
In short, here's an include() function that works for me:
function include(path) {
var code = fs.readFileSync(path, 'utf-8');
vm.runInThisContext(code, path);
}
say we wants to call function ping() and add(30,20) which is in lib.js file
from main.js
main.js
lib = require("./lib.js")
output = lib.ping();
console.log(output);
//Passing Parameters
console.log("Sum of A and B = " + lib.add(20,30))
lib.js
this.ping=function ()
{
return "Ping Success"
}
//Functions with parameters
this.add=function(a,b)
{
return a+b
}
Udo G. said:
The eval() can't be used inside a function and must be called inside
the global scope otherwise no functions or variables will be
accessible (i.e. you can't create a include() utility function or
something like that).
He's right, but there's a way to affect the global scope from a function. Improving his example:
function include(file_) {
with (global) {
eval(fs.readFileSync(file_) + '');
};
};
include('somefile_with_some_declarations.js');
// the declarations are now accessible here.
Hope, that helps.
app.js
let { func_name } = require('path_to_tools.js');
func_name(); //function calling
tools.js
let func_name = function() {
...
//function body
...
};
module.exports = { func_name };
It worked with me like the following....
Lib1.js
//Any other private code here
// Code you want to export
exports.function1 = function(params) {.......};
exports.function2 = function(params) {.......};
// Again any private code
now in the Main.js file you need to include Lib1.js
var mylib = requires('lib1.js');
mylib.function1(params);
mylib.function2(params);
Please remember to put the Lib1.js in node_modules folder.
Another way to do this in my opinion, is to execute everything in the lib file when you call require() function using (function(/* things here */){})(); doing this will make all these functions global scope, exactly like the eval() solution
src/lib.js
(function () {
funcOne = function() {
console.log('mlt funcOne here');
}
funcThree = function(firstName) {
console.log(firstName, 'calls funcThree here');
}
name = "Mulatinho";
myobject = {
title: 'Node.JS is cool',
funcFour: function() {
return console.log('internal funcFour() called here');
}
}
})();
And then in your main code you can call your functions by name like:
main.js
require('./src/lib')
funcOne();
funcThree('Alex');
console.log(name);
console.log(myobject);
console.log(myobject.funcFour());
Will make this output
bash-3.2$ node -v
v7.2.1
bash-3.2$ node main.js
mlt funcOne here
Alex calls funcThree here
Mulatinho
{ title: 'Node.JS is cool', funcFour: [Function: funcFour] }
internal funcFour() called here
undefined
Pay atention to the undefined when you call my object.funcFour(), it will be the same if you load with eval(). Hope it helps :)
You can put your functions in global variables, but it's better practice to just turn your tools script into a module. It's really not too hard – just attach your public API to the exports object. Take a look at Understanding Node.js' exports module for some more detail.
I just want to add, in case you need just certain functions imported from your tools.js, then you can use a destructuring assignment which is supported in node.js since version 6.4 - see node.green.
Example:
(both files are in the same folder)
tools.js
module.exports = {
sum: function(a,b) {
return a + b;
},
isEven: function(a) {
return a % 2 == 0;
}
};
main.js
const { isEven } = require('./tools.js');
console.log(isEven(10));
output: true
This also avoids that you assign those functions as properties of another object as its the case in the following (common) assignment:
const tools = require('./tools.js');
where you need to call tools.isEven(10).
NOTE:
Don't forget to prefix your file name with the correct path - even if both files are in the same folder, you need to prefix with ./
From Node.js docs:
Without a leading '/', './', or '../' to indicate a file, the module
must either be a core module or is loaded from a node_modules folder.
Include file and run it in given (non-global) context
fileToInclude.js
define({
"data": "XYZ"
});
main.js
var fs = require("fs");
var vm = require("vm");
function include(path, context) {
var code = fs.readFileSync(path, 'utf-8');
vm.runInContext(code, vm.createContext(context));
}
// Include file
var customContext = {
"define": function (data) {
console.log(data);
}
};
include('./fileToInclude.js', customContext);
Using the ESM module system:
a.js:
export default function foo() {};
export function bar() {};
b.js:
import foo, {bar} from './a.js';
This is the best way i have created so far.
var fs = require('fs'),
includedFiles_ = {};
global.include = function (fileName) {
var sys = require('sys');
sys.puts('Loading file: ' + fileName);
var ev = require(fileName);
for (var prop in ev) {
global[prop] = ev[prop];
}
includedFiles_[fileName] = true;
};
global.includeOnce = function (fileName) {
if (!includedFiles_[fileName]) {
include(fileName);
}
};
global.includeFolderOnce = function (folder) {
var file, fileName,
sys = require('sys'),
files = fs.readdirSync(folder);
var getFileName = function(str) {
var splited = str.split('.');
splited.pop();
return splited.join('.');
},
getExtension = function(str) {
var splited = str.split('.');
return splited[splited.length - 1];
};
for (var i = 0; i < files.length; i++) {
file = files[i];
if (getExtension(file) === 'js') {
fileName = getFileName(file);
try {
includeOnce(folder + '/' + file);
} catch (err) {
// if (ext.vars) {
// console.log(ext.vars.dump(err));
// } else {
sys.puts(err);
// }
}
}
}
};
includeFolderOnce('./extensions');
includeOnce('./bin/Lara.js');
var lara = new Lara();
You still need to inform what you want to export
includeOnce('./bin/WebServer.js');
function Lara() {
this.webServer = new WebServer();
this.webServer.start();
}
Lara.prototype.webServer = null;
module.exports.Lara = Lara;
You can simple just require('./filename').
Eg.
// file: index.js
var express = require('express');
var app = express();
var child = require('./child');
app.use('/child', child);
app.get('/', function (req, res) {
res.send('parent');
});
app.listen(process.env.PORT, function () {
console.log('Example app listening on port '+process.env.PORT+'!');
});
// file: child.js
var express = require('express'),
child = express.Router();
console.log('child');
child.get('/child', function(req, res){
res.send('Child2');
});
child.get('/', function(req, res){
res.send('Child');
});
module.exports = child;
Please note that:
you can't listen PORT on the child file, only parent express module has PORT listener
Child is using 'Router', not parent Express moudle.
Node works based on commonjs modules and more recently, esm modules. Basically, you should create modules in separated .js files and make use of imports/exports (module.exports and require).
Javascript on the browser works differently, based on scope. There is the global scope, and through clojures (functions inside other functions) you have private scopes.
So,in node, export functions and objects that you will consume in other modules.
The cleanest way IMO is the following, In tools.js:
function A(){
.
.
.
}
function B(){
.
.
.
}
module.exports = {
A,
B
}
Then, in app.js, just require the tools.js as following: const tools = require("tools");
I was as well searching for an option to include code without writing modules, resp. use the same tested standalone sources from a different project for a Node.js service - and jmparattes answer did it for me.
The benefit is, you don't pollute the namespace, I don't have trouble with "use strict"; and it works well.
Here a full sample:
Script to load - /lib/foo.js
"use strict";
(function(){
var Foo = function(e){
this.foo = e;
}
Foo.prototype.x = 1;
return Foo;
}())
SampleModule - index.js
"use strict";
const fs = require('fs');
const path = require('path');
var SampleModule = module.exports = {
instAFoo: function(){
var Foo = eval.apply(
this, [fs.readFileSync(path.join(__dirname, '/lib/foo.js')).toString()]
);
var instance = new Foo('bar');
console.log(instance.foo); // 'bar'
console.log(instance.x); // '1'
}
}
Hope this was helpfull somehow.
Like you are having a file abc.txt and many more?
Create 2 files: fileread.js and fetchingfile.js, then in fileread.js write this code:
function fileread(filename) {
var contents= fs.readFileSync(filename);
return contents;
}
var fs = require("fs"); // file system
//var data = fileread("abc.txt");
module.exports.fileread = fileread;
//data.say();
//console.log(data.toString());
}
In fetchingfile.js write this code:
function myerror(){
console.log("Hey need some help");
console.log("type file=abc.txt");
}
var ags = require("minimist")(process.argv.slice(2), { string: "file" });
if(ags.help || !ags.file) {
myerror();
process.exit(1);
}
var hello = require("./fileread.js");
var data = hello.fileread(ags.file); // importing module here
console.log(data.toString());
Now, in a terminal:
$ node fetchingfile.js --file=abc.txt
You are passing the file name as an argument, moreover include all files in readfile.js instead of passing it.
Thanks
Another method when using node.js and express.js framework
var f1 = function(){
console.log("f1");
}
var f2 = function(){
console.log("f2");
}
module.exports = {
f1 : f1,
f2 : f2
}
store this in a js file named s and in the folder statics
Now to use the function
var s = require('../statics/s');
s.f1();
s.f2();
To turn "tools" into a module, I don't see hard at all. Despite all the other answers I would still recommend use of module.exports:
//util.js
module.exports = {
myFunction: function () {
// your logic in here
let message = "I am message from myFunction";
return message;
}
}
Now we need to assign this exports to global scope (in your app|index|server.js )
var util = require('./util');
Now you can refer and call function as:
//util.myFunction();
console.log(util.myFunction()); // prints in console :I am message from myFunction
To interactively test the module ./test.js in a Unix environment, something like this could be used:
>> node -e "eval(''+require('fs').readFileSync('./test.js'))" -i
...
Use:
var mymodule = require("./tools.js")
app.js:
module.exports.<your function> = function () {
<what should the function do>
}

Restarting gulp after changes to gulpfile.js

I am attempting to re-run my gulp build when gulpfile.js changes, but I am having issues with the method all of my research has lead me to.
I have one watcher for all my less and javascript files and a configuration object that has the list of files to watch, how they are output, etc. This is a stripped-down example of what it looks like:
var $ = require('gulp-load-plugins')();
var config = {
root: rootPath,
output: {
app: 'app',
vendor: 'vendor'
}, // ...
};
gulp.task('default', ['build', 'watch']);
gulp.task('build', ['clean', 'less:app', 'less:theme', 'css:vendor', 'js:app', 'js:vendor', 'rev', 'css:copyfonts']);
gulp.task('watch', function () {
var allFiles = config.styles.appSrc
.concat(config.styles.vendorSrc)
.concat(config.scripts.appSrc)
.concat(config.scripts.vendorSrc);
$.watch(allFiles, function () {
gulp.start('default');
});
});
gulp.task('watch:gulp', function () {
var p;
gulp.watch('gulpfile.js', spawnUpdatedGulp);
spawnUpdatedGulp();
function spawnUpdatedGulp() {
if (p) {
p.kill();
}
p = spawn('gulp', ['default', '--color'], { stdio: 'inherit' });
}
});
// .. other build tasks ..
The above code shows how I tried the accepted answer to this:
How can Gulp be restarted upon each Gulpfile change?
However, it has a major issue. When I run watch:gulp, it runs the build just fine, and everything is great. The config.output.app variable is how the app specific css and js files are named, so my test case has been:
run gulp:watch, check that the css output is named according to config.output.app
change config.output.app, and perform step #1 again
save any random javascript file that it is watching, and see if it builds correctly
Step 3 is riddled with permission errors because of multiple watchers on the files, and this only gets worse the more I repeat steps 1 and 2. Visual Studio will even freeze.
I have not found a way to clean up the old watchers. I tried to manually kill them like this:
var appFileWatcher;
gulp.task('watch', function () {
var allFiles = config.styles.appSrc
.concat(config.styles.vendorSrc)
.concat(config.scripts.appSrc)
.concat(config.scripts.vendorSrc);
appFileWatcher = $.watch(allFiles, function () {
gulp.start('default');
});
});
gulp.task('watch:gulp', function () {
var p;
var gulpWatcher = $.watch('gulpfile.js', spawnUpdatedGulp);
spawnUpdatedGulp();
function spawnUpdatedGulp() {
if (p) {
p.kill();
}
if (appFileWatcher) {
appFileWatcher.unwatch();
}
gulpWatcher.unwatch();
p = spawn('gulp', ['default', '--color'], { stdio: 'inherit' });
}
});
This also does not work. I still get multiple watchers trying to perform the build when I perform my same test case.
How do I kill those watchers that stay around after the new gulp process is spawned?

Browserify + browserify-ngannotate + Tsify not working

I'm using gulp with browserify and tsify. This has been working quite well. Then I decided to add ng-annotate using browserify-ngannotate.
I've added the ng-annotate browserify transform but it seems that if tsify is added as a plugin the ng-annotate transform is never called.
If I remove the tsify plugin then ng-annote gets called. I've played around and switched around the plugin/transform registration. Am I missing something here, or should I go and log an issue at browserify/tsify?
var browserify = require('browserify');
var browserSyncConfig = require('../config').browserSync;
var browserSync = require('browser-sync').get(browserSyncConfig.instance);
var watchify = require('watchify');
var tsify = require('tsify');
var ngAnnotate = require('browserify-ngannotate');
var mergeStream = require('merge-stream');
var bundleLogger = require('../util/bundleLogger');
var gulp = require('gulp');
var handleErrors = require('../util/handleErrors');
var source = require('vinyl-source-stream');
var config = require('../config').browserify;
var _ = require('lodash');
var browserifyTask = function (devMode) {
var browserifyThis = function (bundleConfig) {
if (devMode) {
// Add watchify args and debug (sourcemaps) option
_.extend(bundleConfig, watchify.args, {debug: true});
// A watchify require/external bug that prevents proper recompiling,
// so (for now) we'll ignore these options during development. Running
// `gulp browserify` directly will properly require and externalize.
bundleConfig = _.omit(bundleConfig, ['external', 'require']);
}
var b = browserify(bundleConfig);
if (bundleConfig.tsify) {
b = b.plugin(tsify, {
noImplicitAny: false,
target: 'ES5',
noExternalResolve: false,
module: 'commonjs',
removeComments: false
});
}
if (bundleConfig.ngAnnotate) {
b = b.transform(ngAnnotate);
}
var bundle = function () {
// Log when bundling starts
bundleLogger.start(bundleConfig.outputName);
return b
.bundle()
// Report compile errors
.on('error', handleErrors)
// Use vinyl-source-stream to make the
// stream gulp compatible. Specify the
// desired output filename here.
.pipe(source(bundleConfig.outputName))
// Specify the output destination
.pipe(gulp.dest(bundleConfig.dest))
.pipe(browserSync.stream());
};
if (devMode) {
// Wrap with watchify and rebundle on changes
b = watchify(b, {
poll: true
});
// Rebundle on update
b.on('update', bundle);
bundleLogger.watch(bundleConfig.outputName);
} else {
// Sort out shared dependencies.
// b.require exposes modules externally
if (bundleConfig.require) b.require(bundleConfig.require);
// b.external excludes modules from the bundle, and expects
// they'll be available externally
if (bundleConfig.external) b.external(bundleConfig.external);
}
return bundle();
};
// Start bundling with Browserify for each bundleConfig specified
return mergeStream.apply(gulp, _.map(config.bundleConfigs, browserifyThis));
};
gulp.task('browserify', function () {
return browserifyTask()
});
// Exporting the task so we can call it directly in our watch task, with the 'devMode' option
module.exports = browserifyTask;
You can solve it by specify extensions in ng-annotate options.
bundler.transform(ngAnnotate, { ext: ['.ts', '.js'] });
I realized I had this problem too, when I added uglifyify to the bundle transforms to produce minified builds.
An important aspect of my solution is that the missing, explicit $inject statements, that ng-annotate should have inserted, doesn't matter until the code is actually minified. Luckily, UglifyJS2, which does the actual minification in uglifyify, got support for handling ng-annotate's ngInject comments in version 2.4.9 (in January, 2014).
So, the solution that worked for me was to install uglifyify:
npm install --save-dev uglifyify
and add the following uglifyify transform to the Browserify bundle:
b.transform({
global: true,
mangle: false,
comments: true,
compress: {
angular: true
}
}, 'uglifyify');
This will make UglifyJS2 insert the appropriate $inject statements into your code before it is minified.
So, to summarize, I did not have a solution for only using ng-annotate, but my solution will add the necessary $inject statements before the code is minified, which is what matters in most cases.

Gulp, livereload, jade

Need help.
I use gulp-conect and it livereload method. But if I build a few template in time, get a lot of page refresh. Is any solution, I want to build few templates with single page refresh?
So, I reproduce the problem you have and came accross this working solution.
First, lets check gulp plugins you need:
gulp-jade
gulp-livereload
optional: gulp-load-plugins
In case you need some of them go to:
http://gulpjs.com/plugins/
Search for them and install them.
Strategy: I created a gulp task called live that will check your *.jade files, and as you are working on a certain file & saving it, gulp will compile it into html and refresh the browser.
In order to accomplish that, we define a function called compileAndRefresh that will take the file returned by the watcher. It will compile that file into html and the refesh the browser (test with livereload plugin for chrome).
Notes:
I always use gulp-load-plugin to load plugins, so thats whay I use plugins.jad and plugins.livereload.
This will only compile files that are saved and while you have the task live exucting on the command line. Will not compile other files that are not in use. In order to accomplish that, you need to define a task that compiles all files, not only the ones that have been changed.
Assume .jade files in /jade and html output to /html
So, here is the gulpfile.js:
var gulp = require('gulp'),
gulpLoadPlugins = require('gulp-load-plugins'),
plugins = gulpLoadPlugins();
gulp.task('webserver', function() {
gulp.src('./html')
.pipe(plugins.webserver({
livereload: true
}));
gulp.watch('./jade/*.jade', function(event) {
compileAndRefresh(event.path);
});
});
function compileAndRefresh(file) {
gulp.src(file)
.pipe(plugins.jade({
}))
.pipe(gulp.dest('./html'))
}
Post edit notes:
Removed liveReload call from compileAndRefresh (webserver will do that).
Use gulp-server plugin insted of gulp-connect, as they suggest on their repository: "New plugin based on connect 3 using the gulp.src() API. Written in plain javascript. https://github.com/schickling/gulp-webserver"
Something you can do is to watch only files that changes, and then apply a function only to those files that have been changed, something like this:
gulp.task('live', function() {
gulp.watch('templates/folder', function(event) {
refresh_templates(event.path);
});
});
function refresh_templates(file) {
return
gulp.src(file)
.pipe(plugins.embedlr())
.pipe(plugins.livereload());
}
PS: this is not a working example, and I dont know if you are using embedlr, but the point, is that you can watch, and use a callback to call another function with the files that are changing, and the manipulate only those files. Also, I supposed that your goal is to refresh the templates for your browser, but you manipulate as you like, save them on dest or do whatever you want.
Key point here is to show how to manipulate file that changes: callback of watch + custom function.
var jadeTask = function(path) {
path = path || loc.jade + '/*.jade';
if (/source/.test(path)) {
path = loc.jade + '/**/*.jade';
}
return gulp.src(path)
.pipe(changed(loc.markup, {extension: '.html'}))
.pipe(jade({
locals : json_array,
pretty : true
}))
.pipe(gulp.dest(loc.markup))
.pipe(connect.reload());
}
First install required plugins
gulp
express
gulp-jade
connect-livereload
tiny-lr
connect
then write the code
var gulp = require('gulp');
var express = require('express');
var path = require('path');
var connect = require("connect");
var jade = require('gulp-jade');
var app = express();
gulp.task('express', function() {
app.use(require('connect-livereload')({port: 8002}));
app.use(express.static(path.join(__dirname, '/dist')));
app.listen(8000);
});
var tinylr;
gulp.task('livereload', function() {
tinylr = require('tiny-lr')();
tinylr.listen(8002);
});
function notifyLiveReload(event) {
var fileName = require('path').relative(__dirname, event.path);
tinylr.changed({
body: {
files: [fileName]
}
});
}
gulp.task('jade', function(){
gulp.src('src/*.jade')
.pipe(jade())
.pipe(gulp.dest('dist'))
});
gulp.task('watch', function() {
gulp.watch('dist/*.html', notifyLiveReload);
gulp.watch('src/*.jade', ['jade']);
});
gulp.task('default', ['livereload', 'express', 'watch', 'jade'], function() {
});
find the example here at GitHub

How do you create a file from a string in Gulp?

In my gulpfile I have a version number in a string. I'd like to write the version number to a file. Is there a nice way to do this in Gulp, or should I be looking at more general NodeJS APIs?
If you'd like to do this in a gulp-like way, you can create a stream of "fake" vinyl files and call pipe per usual. Here's a function for creating the stream. "stream" is a core module, so you don't need to install anything:
const Vinyl = require('vinyl')
function string_src(filename, string) {
var src = require('stream').Readable({ objectMode: true })
src._read = function () {
this.push(new Vinyl({
cwd: "",
base: "",
path: filename,
contents: Buffer.from(string, 'utf-8')
}))
this.push(null)
}
return src
}
You can use it like this:
gulp.task('version', function () {
var pkg = require('package.json')
return string_src("version", pkg.version)
.pipe(gulp.dest('build/'))
})
It's pretty much a one-liner in node:
require('fs').writeFileSync('dist/version.txt', '1.2.3');
Or from package.json:
var pkg = require('./package.json');
var fs = require('fs');
fs.writeFileSync('dist/version.txt', 'Version: ' + pkg.version);
I'm using it to specify a build date in an easily-accessible file, so I use this code before the usual return gulp.src(...) in the build task:
require('fs').writeFileSync('dist/build-date.txt', new Date());
This can also be done with vinyl-source-stream. See this document in the gulp repository.
var gulp = require('gulp'),
source = require('vinyl-source-stream');
gulp.task('some-task', function() {
var stream = source('file.txt');
stream.end('some data');
stream.pipe(gulp.dest('output'));
});
According to the maintainer of Gulp, the preferred way to write a string to a file is using fs.writeFile with the task callback.
var fs = require('fs');
var gulp = require('gulp');
gulp.task('taskname', function(cb){
fs.writeFile('filename.txt', 'contents', cb);
});
Source: https://github.com/gulpjs/gulp/issues/332#issuecomment-36970935
You can also use gulp-file:
var gulp = require('gulp');
var file = require('gulp-file');
gulp.task('version', function () {
var pkg = require('package.json')
return gulp.src('src/**')
.pipe(file('version', pkg.version))
.pipe(gulp.dest('build/'))
});
or without using gulp.src():
gulp.task('version', function () {
var pkg = require('package.json')
return file('version', pkg.version, {src: true})
.pipe(gulp.dest('build/'))
});
The gulp-header package can be used to prefix files with header banners.
eg. This will inject a banner into the header of your javascript files.
var header = require('gulp-header');
var pkg = require('./package.json');
var banner = ['/**',
' * <%= pkg.name %> - <%= pkg.description %>',
' * #version v<%= pkg.version %>',
' * #link <%= pkg.homepage %>',
' * #license <%= pkg.license %>',
' */',
''].join('\n');
gulp.src('./foo/*.js')
.pipe(header(banner, { pkg: pkg } ))
.pipe(gulp.dest('./dist/')
Gulp is a streaming build system leveraging pipes.
If you simply want to write a new file with an arbitrary string, you can use built in node fs object.
Using the string-to-stream and vinyl-source-stream modules:
var str = require('string-to-stream');
var source = require('vinyl-source-stream');
var gulp = require('gulp');
str('1.4.27').pipe(source('version.txt')).pipe(gulp.dest('dist'));
Here's an answer that works in 2019.
Plugin:
var Vinyl = require('vinyl');
var through = require('through2');
var path = require('path');
// https://github.com/gulpjs/gulp/tree/master/docs/writing-a-plugin#modifying-file-content
function stringSrc(filename, string) {
/**
* #this {Transform}
*/
var transform = function(file, encoding, callback) {
if (path.basename(file.relative) === 'package.json') {
file.contents = Buffer.from(
JSON.stringify({
name: 'modified-package',
version: '1.0.0',
}),
);
}
// if you want to create multiple files, use this.push and provide empty callback() call instead
// this.push(file);
// callback();
callback(null, file);
};
return through.obj(transform);
}
And in your gulp pipeline:
gulp.src([
...
])
.pipe(stringSrc('version.json', '123'))
.pipe(gulp.dest(destinationPath))
From source: https://github.com/gulpjs/gulp/tree/master/docs/writing-a-plugin#modifying-file-content
The function parameter that you pass to through.obj() is a _transform
function which will operate on the input file. You may also provide an
optional _flush function if you need to emit a bit more data at the
end of the stream.
From within your transform function call this.push(file) 0 or more
times to pass along transformed/cloned files. You don't need to call
this.push(file) if you provide all output to the callback() function.
Call the callback function only when the current file (stream/buffer)
is completely consumed. If an error is encountered, pass it as the
first argument to the callback, otherwise set it to null. If you have
passed all output data to this.push() you can omit the second argument
to the callback.
Generally, a gulp plugin would update file.contents and then choose to
either:
call callback(null, file) or make one call to this.push(file)
This can also be achieved using gulp-tap
This can be especially helpful if you have identified multiple files that require this header. Here is relevant code (Also from gulp-tap documentation)
var gulp = require('gulp'),
tap = require('gulp-tap');
gulp.src("src/**")
.pipe(tap(function(file){
file.contents = Buffer.concat([
new Buffer('Some Version Header', 'utf8'),
file.contents
]);
}))
.pipe(gulp.dest('dist');

Resources