In the code below (described as gulp-task), the fileShouldBePreprocessedBySass() function is called after executing console.log('intercepted!'); . Naturally, with such an unexpected sequence, in the fileShouldBePreprocessedBySass(targetFileAbsolutePath) parameter targetFileAbsolutePath not yet been initialized, therefore it has the value undefined .

 let currentSourceFileAbsolutePath; return gulp.src(entryPointsSourceFilesPathsOrGlobs) // "gulpPlugins.intercept" - это "gulp-intercept" .pipe(gulpPlugins.intercept( sourceVynilFile => { console.log('intercepted!'); currentSourceFileAbsolutePath = sourceVynilFile.path; console.log(currentSourceFileAbsolutePath); // Пока всё нормально return sourceVynilFile; })) // "gulpPlugins.if" - это "gulp-if" .pipe(gulpPlugins.if( // currentSourceFileAbsolutePath имеет значение undefined !!! fileShouldBePreprocessedBySass(currentSourceFileAbsolutePath), gulpPlugins.sass() )); // ... fileShouldBePreprocessedBySass(targetFileAbsolutePath) { console.warn('---'); console.warn(targetFileAbsolutePath); // undefined! const targetFilenameExtension = Path.extname(targetFileAbsolutePath); let targetFilenameExtensionIsSupportedBySassPreprocessor = false; for (const filenameExtension of SUPPORTED_FILENAME_EXTENSIONS__SASS_PREPROCESSOR) { if (filenameExtension === targetFilenameExtension) { targetFilenameExtensionIsSupportedBySassPreprocessor = true; break; } } return targetFilenameExtensionIsSupportedBySassPreprocessor; } 

The source code, generally speaking, is on TypeScript with the strictest settings, but I rewrote it in JavaScript for this question so that more people can understand the code. I mentioned TypeScript because the compiler somehow realized that the parameter in the pipe(gulpPlugins.if(/*...*/)) was not yet initialized, and therefore worked with an error.

I was very surprised by this because I have another similar gulp-task, where everything works fine:

 let currentSourceFileAbsolutePath: string; return gulp.src(entryPointsSourceFilesPathsOrGlobs) .pipe(gulpPlugins.intercept(sourceVynilFile => { currentSourceFileAbsolutePath = sourceVynilFile.path; return sourceFile; })) .pipe(gulpPlugins.pug()) .pipe(gulpPlugins.intercept(compiledHtmlFile => { // currentSourceFileAbsolutePath проинициализирован, всё нормально. if (shouldValidateCompiledHtmlRespectiveToSourceFile(currentSourceFileAbsolutePath)) { HtmlValidator.validateHtml(compiledHtmlFile); } return compiledHtmlFile; })) .pipe(gulp.dest(() => ( // currentSourceFileAbsolutePath проинициализирован, всё нормально. getOutputDirectoryForPreprocessedMarkupEntryPointFileByRespectiveSourceFile(currentSourceFileAbsolutePath) ))); 

What did I miss? Was there some kind of asynchronous call?


And why, in fact, such a complex code? What is the problem?

The logic in a real project is naturally much more complicated (in view of the bulk TZ), and if you don’t go into details, you just need to know the absolute path to the source file inside each pipe() . As soon as the file passes, for example, pipe(gulpPlugins.pug()) , the extension will change from .pug to .html , and this will NOT be the original file.

Different decisions are much easier to make if you know the path to the source file, so a specific configuration is associated with it, which needs to be found and, on its basis, to do something with the file. If the path to the file has changed, then it will be much more difficult to find a suitable configuration, and restoring the path to the source file from a modified one (for example, restoring path/to/file/test.pug by path/to/file/test.html ) will make the code very heavy. , because:

  • Depending on the specific task, the path recovery algorithm will differ
  • As you go through .pipe , the path to the file may change several times.
  • The code is constantly modified, and as it is modified, the algorithms for restoring the original path will have to be changed.

Therefore, the misfortune for which there is such a code for gulp-task that is present in the question is to know the path to the source file in each pipe() . If there is any easier way to do this - I will be glad to see it in your wonderful answers.

    1 answer 1

    Your use of the gulp-if plugin is synchronous — it runs once during the initialization of the thread handlers.

    The fileShouldBePreprocessedBySass() function is called once BEFORE reading data from the stream, gets the un-initialized currentSourceFileAbsolutePath argument for its parameter, and returns the result == false . The gulp-if plugin sees that its first argument is of type boolean — returns, according to the value of the first argument, an object from its true / false-arguments. The object obtained in this way will be used when reading data from the stream for ALL files.

    In order to change the situation and make the gulp-if plugin work when reading data from the stream for each file - you need to specify the argument for pipe() like this:

     ... // "gulpPlugins.if" - это "gulp-if" .pipe(gulpPlugins.if( fileShouldBePreprocessedBySass, gulpPlugins.sass() )); ... 

    Then the gulp-if plugin will return the ternaryStream object, initializing it with its arguments, and the fileShouldBePreprocessedBySass function will be called while reading data from the stream for EACH file and the argument for it is from the previous pipe() .

    And the currentSourceFileAbsolutePath variable will be correctly initialized by the previous handlers at the time of the fileShouldBePreprocessedBySass() function calls.

    • Thank you for your reply! And for your time you spent reading the question. - Sideways Gleb