如何在 Gulp 中从字符串创建文件?

在我的 Gulpfile 中,有一个字符串中的版本号。我想把版本号写到一个文件中。在 Gulp 中有没有一种很好的方法来实现这一点,或者我应该查看更通用的 NodeJS API?

63929 次浏览

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.

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

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

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

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

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

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)