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

node.jsGulp

node.js Problem Overview


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?

node.js Solutions


Solution 1 - node.js

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/'))
})

Solution 2 - node.js

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());

Solution 3 - node.js

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'));
});

Solution 4 - node.js

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

Solution 5 - node.js

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/'))
});

Solution 6 - node.js

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.

Solution 7 - node.js

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'));

Solution 8 - node.js

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)

Solution 9 - node.js

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');

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDarylView Question on Stackoverflow
Solution 1 - node.jsChristoph NeumannView Answer on Stackoverflow
Solution 2 - node.jsfreganteView Answer on Stackoverflow
Solution 3 - node.jsmjhasbachView Answer on Stackoverflow
Solution 4 - node.jsGOTO 0View Answer on Stackoverflow
Solution 5 - node.jsDave James MillerView Answer on Stackoverflow
Solution 6 - node.jsMike CauserView Answer on Stackoverflow
Solution 7 - node.jsJonas BerlinView Answer on Stackoverflow
Solution 8 - node.jsWilliam BerntingView Answer on Stackoverflow
Solution 9 - node.jsVikramView Answer on Stackoverflow