I have a rather specific problem: I am trying to build a complex stack using Sails.js with machinepack-sailsgulpify.
In order to inject assets into my templates I use gulp-inject
plugin, as the machinepack suggests. The problem is that for anything other than html
and ejs
the injector doesn't work. It simply doesn't change anything. No errors, nothing.
My task looks like this:
gulp.task('sails-linker-gulp:devViews', function() {
return gulp.src('views/**/*.?(html|ejs|jade|pug|haml|slim|dust)') // Read templates
.pipe(
plugins.inject(
gulp.src(require('../pipeline').jsFilesToInject, {read: false}), // Link the javaScript
{
starttag: generateScriptStartTag,
endtag: generateScriptEndTag,
ignorePath: '.tmp/public',
transform: (filepath, file, i, length) => {
return `script(src="${filepath}")`;
}
}
)
)
.pipe(
plugins.inject(
gulp.src(require('../pipeline').cssFilesToInject, {read: false}), // Link the styles
{
starttag: generateStyleStartTag,
endtag: generateStyleEndTag,
ignorePath: '.tmp/public'
}
)
)
.pipe(
plugins.inject(
gulp.src( ['.tmp/public/jst.js'], {read: false}), // Link the JST Templates
{
starttag: generateTemplateStartTag,
endtag: generateTemplateEndTag,
ignorePath: '.tmp/public'
}
)
)
.pipe(gulp.dest('views/'))// Write modified files...
Don't worry about the generateScriptStartTag
and such functions, they are just there for control and I am 1000% sure they work correctly, tested a lot. They generate the tags kind of like this:
//- SCRIPTS
//- SCRIPTS END
depending on the template language.
Adding custom transform function did not work. If I use ejs
or html
or really anything that resembles html syntax it works fine.
Now, about Sails: I can NOT add a gulp task to compile the template before injecting because Sails renders templates on request in development, it doesn't actually pre-compile them into any directory. And honestly: why should I? The injection is just adding lines to my .jade/.pug files in views
, the files are there already, so I don't see why there's a problem there. Can someone advise?
UPDATE:
Rather frustrating inspection of the code revealed that the 'matches' property when running the inject
function of has length 0 and when inspecting the content
of the stream in node inspector, I did not see the comments, they were stripped away, despite the fact that they are clearly there in the file.
UPDATE #2: It appears that I was wrong about ejs. ONLY HTML files are getting processed. Also it works OK when it doesn't detect the injection comments. However if it does the end event simply never emits for that file and nothing gets injected. This is true for ALL templating engines, only static HTML files have injection working fine.
UPDATE #3:
After another 5 hours of debugging I found the problem, however my understanding of streams isn't good enough to get me any closer to the solution. The problem is that in inject
function of the plugin there's a loop that doesn't quit properly, and while it perfectly injects the required tags into the stream, it then runs that loop again on the same stream (with injected tags), and throws an error.
Why that error never showed up in any console I don't know but there you go. Can someone please help? I am completely lost with this... Is it a bug in the plugin?
I had to figure this out on my own.
It is a bug in gulp-inject
. The regex that this plugin generates to test against the injection tags does not match the whole line, it's simply matches the first occurrence. This means that if I have my tags set like so:
//SCRIPTS
//SCRIPTS END
The regex will match the starttag
: //SCRIPTS
twice:
And the end tag will only be matched once. This was causing the second faulty loop with the error for missing end tag.
A workaround is to avoid repeating start of tags.
//SCRIPTS
//END SCRIPTS
That's not a solution, however. A solution would be to alter the regex so that it only allows whitespace and newline characters in order to match the tag, when using an indent-based template language.
Something like this would work: /\/\/-\s*SCRIPTS(?=\s*\n|$)/ig
Can't believe nobody has stumbled upon this until now, seems like it would be a more common problem...