How to get relative source using gulp.src() - javascript

I have a file at /components/slider/index.html. I setup a gulp task that injects related css/js files from separate folders using gulp-inject.
gulp.task('default', function() {
return gulp.src('./components/**/*.html')
.pipe( inject(gulp.src(['./assets/css/bootstrap/*.css'], {read: false}), { relative: true }) )
.pipe( inject(gulp.src(['./assets/js/jquery/*.js'], {read: false}), {starttag: '<!-- inject:head:{{ext}} -->', relative: true} ) )
.pipe(gulp.dest('./dist'));
});
Now I need to get the source of a js file, located along side of the html source we are pipe-ing, in order to inject it relativley using gulp-inject.
Is there anyway to get gulp.src('./components/**/*.html') in a pipe and somehow get the sibling js file from there? Any suggestion?

It turns out you can not do that using gulp-inject, So what I did was to get a list of directory paths, and then do gulp-inject on each of them separately.
This way I had access to all the folders & files paths before I even begin injecting.
var fs = require('fs');
var dirPath = '/components/widgets/';
var result = []; //this is going to contain paths
fs.readdir(__dirname + dirPath, function (err, filesPath) {
if (err) throw err;
result = filesPath.map(function (filePath) {
return dirPath + filePath;
});
function do_inject(entry) {
// Injection Code using gulp-inject
}
result.forEach(function(entry) {
do_inject(entry);
});
});
Also I ended up using "addPrefix" and "addRootSlash" options for my gulp-inject to make it behave how I want. Just some additional info, it may help someone.

Related

How to sync a local folder with gulp, with update for deleted files and folders?

I am working on a WordPress plugin and have all the files in my working directory and run gulp in that project folder. Now, I'd like to have a watch task that copies all the changes to my local WP installation for testing.
Therefore I am looking for a way to sync (only in one direction) the project folder with the plugin folder of WP.
I managed to get it to work with gulp-directory-sync
...
var dirSync = require("gulp-directory-sync");
var localDir = "../newDir/";
var buildDir = "./buildDir/";
...
function copy_to_local_folder() {
return pipeline(
gulp.src(buildDir+'**/*'),
dirSync( buildDir, localDir, { printSummary: true } )
);
}
function watch_local() {
gulp.watch(buildDir+'**/*', copy_to_local_folder);
exports.default = watch_local;
However, the plugin hasn't been updated in 4 years and according to this answer, it is not doing it the proper "gulp way" (e.g. not using gulp-src) and this task should be possible with other basic gulp functions.
Copying changed files is pretty easy, but also keeping track of deleted files is more complicated. I also would prefer to only update changed/deleted/new files and not clearing the folder every time before coping all files.
Starting with the updated code in the aforementioned answer, I tried to implement it and made changes to make it work.
...
var newer = require("gulp-newer");
var pipeline = require("readable-stream").pipeline;
var del = require("del");
var localDir = "../newDir/";
var buildDir = "./buildDir/";
function copy_to_local_folder() {
return pipeline(
gulp.src([buildDir+'**/*']),
newer(localDir),
gulp.dest(localDir),
);
}
function watch_local() {
var watcher = gulp.watch(buildDir + '**/*', copy_to_local_folder );
watcher.on('unlink', function(path) {
console.log(path);
var newPath = './'+path;
newPath = newPath.replace(buildDir, localDir);
console.log(newPath);
(async () => {
const deletedPaths = await del(newPath, {dryRun: true, force: true});
console.log('Deleted files and directories:\n', deletedPaths.join('\n'));
})();
});
}
exports.default = watch_local;
With this code, the folder gets updated when I change or delete files, but it does not trigger when I delete an entire folder. Which is probably because I use unlink and not unlinkDir. But even if I use the version of the function below, it doesn't get triggered by deleting a folder (with containing files).
watcher.on('unlinkDir', function(path) {
console.log('folder deleted');
console.log(path);
var newPath = './'+path;
newPath = newPath.replace(buildDir, localDir);
console.log(newPath);
});
What am I doing wrong?
Or is there in general a better way to achieve this?
PS: I'm using
node v11.15.0
gulp v4.0.2
on Linux
deleting files and folders in VS Code
Update:
When I run it with:
watcher.on('unlink', ... and delete a file:
it works
with the console.log output and the ( async () => ...
and Starting and Finished for copy_to_local_folder
watcher.on('unlinkDir', ... and delete a folder:
it works not
nothing happens in the console output
(not even Starting)
watcher.on('unlinkDir', ... and delete a file:
Starting and Finished for copy_to_local_folder
but not the console.log and ( async () => ...
watcher.on('add', ... and watcher.on('addDir', ...
work both
Seems to me that the watcher.on('unlinkDir', ... does never get triggered ... is unlinkDir not supported by gulp-watch?

Import / read variable from separate gulp file

I'm looking to split my gulpfile.js assets or src variables into separate files so that I can manage them better. For example:
....
var scripts = ['awful.js', 'lot.js', 'of.js', 'js.js', 'files.js']
....(somewhere down the line)
gulp.task('vendorjs', function() {
return gulp.src(scripts)
.pipe(concat('vendor.js'))
.pipe(rename({suffix: '.min'}))
.pipe(uglify())
.pipe(gulp.dest(paths.root + 'dist'))
.pipe(notify({ message: 'vendorjs task completed' }));
});
So what I'm basically interested if theres a way to actually move to a separate file the scripts variable and be able to access it from gulpfile.js.
I've been looking into something like:
require("fs").readFile('gulp/test.js', function(e, data) {
//(test.js would be the file that holds the scripts var)
});
Howerver while it does read the contents of the file, I still can't access it from the gulpfile.js. Any tips or ideas are much appreciated.
Node.js allows you to import other files using require(). It supports three types of files:
JSON files. See DavidDomain's answer for that.
Binary Node.js addons. Not useful for your use case.
JavaScript files. That's what you want.
For JavaScript files the value returned from require() is the one that is assigned to module.exports in the imported file.
So for your use case:
gulp/test.js
var arrayOfFiles = ["awful.js", "lots.js"];
arrayOfFiles.push("of.js");
arrayOfFiles.push("js.js");
arrayOfFiles.push("files.js");
for (var i = 0; i < 10; i++) {
arrayOfFiles.push("some_other_file" + i + ".js");
}
module.exports = {
scripts: arrayOfFiles
};
gulpfile.js
var test = require('gulp/test.js');
gulp.task('vendorjs', function() {
return gulp.src(test.scripts)
.pipe(concat('vendor.js'))
.pipe(rename({suffix: '.min'}))
.pipe(uglify())
.pipe(gulp.dest(paths.root + 'dist'))
.pipe(notify({ message: 'vendorjs task completed' }));
});
You could use a json file to store your assets or source file location in and load that into your gulp file.
For example:
// config.json
{
"scripts": ["awful.js", "lot.js", "of.js", "js.js", "files.js"]
}
And in your gulp file you would do
// gulpfile.js
var config = require('./config');
var scripts = config.scripts;
console.log(scripts);

Gulp pipe and caching issue when using "gulp-translate-html" and "gulp-inject"

I have a project where I have to generate translated static pages.
The choice was to use gulp because it helps a lot in minifying resources, watch for file changes and re-compile, and can also inject html templates in several pages.
I used:
- 'gulp-inject': for inserting templates into final files
- 'gulp-translate-html': for translating because I have '.json' dictionaries
So I have two issues:
'gulp-translate-html'
This uses the json as input for translating, using the following code:
gulp.task('translate', function() {
return gulp.src('./temp/en/template.html')
.pipe(translateHtml({
messages: require('./dictionary/en.json'),
templateSettings: {
interpolate: /{{([\s\S]+?)}}/g
}
}))
.pipe(gulp.dest('./en'));
});
I created a watch on the '.json' file, when modified, it should re-apply the translation. But somehow it uses the old file instead of the modified one.
Is there a workaround for this? Or other plugin that I could use for the json files?
'gulp-inject'
In the code-sample above, I translated only one file. But I need to do so for several languages that have different destinations, so I used a loop for the languages.(sorry for the code indentation)
var gulp = require('gulp'),
inject = require('gulp-inject'),
translateHtml = require('gulp-translate-html');
var languages = ['en', 'de'];
gulp.task('injectContent', function() {
/* the base file used as a reference*/
var target = gulp.src('./templates/base/baseTemplate.html');
/* get each language*/
languages.forEach(function(lang) {
target.pipe(inject(gulp.src('./templates/partials/injectTemplate.html'), {
relative: true,
starttag: '<!-- inject:template -->',
transform: function (filePath, file) {
return file.contents.toString('utf8');
}
}))
/* put the merged files into "temp" folder under its language folder*/
.pipe(gulp.dest('./temp/'+lang));
});
});
/* The translation has to be made after the injection above is finished*/
gulp.task('translate', ['injectContent'] function() {
/* get each language*/
languages.forEach(function(lang) {
gulp.src('./temp/'+ lang +'/baseTemplate.html')
.pipe(translateHtml({
messages: require('./dictionary/'+lang+'.json');,
templateSettings: {
interpolate: /{{([\s\S]+?)}}/g
}
}))
.pipe(gulp.dest('./'+lang)); /* put file in the "en" or "de" language folder*/
});
});
gulp.task('watch', function() {
gulp.watch(['./templates/**/*.html', './dictionary/*.json'], ['translate']);
});
gulp.task('default', ['translate', 'watch']);
Here I want the 'injectContent' task to be ran before the 'translation' task, but the latter runs too soon. This happens because there is not a specific return gulp callback in the 'injectContent', right?
How can I merge the results and not let the tasks intercalate?
Just found a solution for the caching issue from point 1:
Based on this answer: https://stackoverflow.com/a/16060619/944637 I deleted the cache and then the "require" function could reload the file from the filesystem and not from cache.
I added delete require.cache[require.resolve('./dictionary/en.json')]; at the beginning of the 'translate' task, before return.
EDIT: Just found the solution on Point 2 to merge the results using "merge-stream", in this answer here: https://stackoverflow.com/a/26786529
so my code turned out to be like this:
....
merge = require('merge-stream');
gulp.task('injectContent', function() {
var tasks = languages.map(function(lang){
return gulp.src('./templates/base/injectContent.html')
.pipe(plumber())
.pipe(debug())
.pipe(inject(gulp.src('./templates/partials/injectTemplate.html'), {
relative: true,
starttag: '<!-- inject:release -->',
transform: function (filePath, file) {
return file.contents.toString('utf8');
}
}))
.pipe(gulp.dest('./temp/'+lang));
});
return merge(tasks);
});
gulp.task('translate', ['injectContent'], function() {
for (var i in languages) {
var lang = languages[i];
delete require.cache[require.resolve('./dictionary/'+lang+'.json')];
gulp.src('./temp/'+lang+'/injectContent.html')
.pipe(plumber())
.pipe(debug())
.pipe(translateHtml({
messages: require('./dictionary/'+lang+'.json'),
templateSettings: {
interpolate: /{{([\s\S]+?)}}/g // this is for Angular-like variable syntax
}
}))
.pipe(gulp.dest('./'+lang));
}
});
....

Gulp task apply uglify if file in pipe is javascript

I want to check if the file in the pipe is .js or not (it could be .map, .html, ...). And if so, uglifying it before copying it in the correct path.
ʕ •́؈•̀) I've try something like this (which not working):
gulpfile.js
gulp.src(current + '/**/*', {base: current})
.pipe($.tap(function (file) {
if (path.extname(file.path) === '.js') {
return gulp.src(file.path)
.pipe($.uglify());
}
}))
.pipe(gulp.dest(destination + '/' + name));
But for now, the uglify seems to do nothing...
Is anyone have a clue on how to do this ? (╥﹏╥)
If you're open to using plugins there is one called gulp-filter that does what you're asking for. https://www.npmjs.com/package/gulp-filter
It would probably look something like this
var gulp = require('gulp');
var gulpFilter = require('gulp-filter');
gulp.task('default', function () {
// create filter instance inside task function
var jsfilter = gulpFilter('**/*.js', {restore: true});
return gulp.src(current + '/**/*', {base: current})
// filter a subset of the files
.pipe(jsFilter)
// run them through a plugin
.pipe($.uglify())
// bring back the previously filtered out files (optional)
.pipe(jsFilter.restore)
.pipe(gulp.dest(destination + '/' + name));
});
try using gulp-filter
something like
var filter = require('gulp-filter');
var jsFilter = filter('**/*.js');
gulp.src('*/*')
.pipe(jsFilter)
.pipe(uglify)

Modify file in place (same dest) using Gulp.js and a globbing pattern

I have a gulp task that is attempting to convert .scss files into .css files (using gulp-ruby-sass) and then place the resulting .css file into the same place it found the original file. The problem is, since I'm using a globbing pattern, I don't necessarily know where the original file is stored.
In the code below I'm trying to use gulp-tap to tap into the stream and figure out the file path of the current file the stream was read from:
gulp.task('convertSass', function() {
var fileLocation = "";
gulp.src("sass/**/*.scss")
.pipe(sass())
.pipe(tap(function(file,t){
fileLocation = path.dirname(file.path);
console.log(fileLocation);
}))
.pipe(gulp.dest(fileLocation));
});
Based on the output of the console.log(fileLocation), this code seems like it should work fine. However, the resulting CSS files seem to be placed one directory higher than I'm expecting. Where it should be project/sass/partials, the resulting file path is just project/partials.
If there's a much simplier way of doing this, I would definitely appreciate that solution even more. Thanks!
As you suspected, you are making this too complicated. The destination doesn't need to be dynamic as the globbed path is used for the dest as well. Simply pipe to the same base directory you're globbing the src from, in this case "sass":
gulp.src("sass/**/*.scss")
.pipe(sass())
.pipe(gulp.dest("sass"));
If your files do not have a common base and you need to pass an array of paths, this is no longer sufficient. In this case, you'd want to specify the base option.
var paths = [
"sass/**/*.scss",
"vendor/sass/**/*.scss"
];
gulp.src(paths, {base: "./"})
.pipe(sass())
.pipe(gulp.dest("./"));
This is simpler than numbers1311407 has led on. You don't need to specify the destination folder at all, simply use .. Also, be sure to set the base directory.
gulp.src("sass/**/*.scss", { base: "./" })
.pipe(sass())
.pipe(gulp.dest("."));
gulp.src("sass/**/*.scss")
.pipe(sass())
.pipe(gulp.dest(function(file) {
return file.base;
}));
Originally answer given here: https://stackoverflow.com/a/29817916/3834540.
I know this thread is old but it still shows up as the first result on google so I thought I might as well post the link here.
This was very helpful!
gulp.task("default", function(){
//sass
gulp.watch([srcPath + '.scss', '!'+ srcPath +'min.scss']).on("change", function(file) {
console.log("Compiling SASS File: " + file.path)
return gulp.src(file.path, { base: "./" })
.pipe(sass({style: 'compressed'}))
.pipe(rename({suffix: '.min'}))
.pipe(sourcemaps.init())
.pipe(autoprefixer({
browsers: ['last 2 versions'],
cascade: false
}))
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest("."));
});
//scripts
gulp.watch([srcPath + '.js','!'+ srcPath + 'min.js']).on("change", function(file) {
console.log("Compiling JS File: " + file.path)
gulp.src(file.path, { base: "./" })
.pipe(uglify())
.pipe(rename({suffix: '.min'}))
.pipe(gulp.dest("."));
});
})
if you want to save all files in their own path in the dist folder
const media = () => {
return gulp.src('./src/assets/media/**/*')
.pipe(gulp.dest(file => file.base.replace('src', 'dist'))
)
}
const watch = () => {
gulp.watch(
"./src/**/*",
media
);
};

Categories