Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Doesn't remove injections when stream is empty #59

Closed
gruppjo opened this issue Oct 6, 2014 · 13 comments
Closed

Doesn't remove injections when stream is empty #59

gruppjo opened this issue Oct 6, 2014 · 13 comments

Comments

@gruppjo
Copy link

gruppjo commented Oct 6, 2014

Hi,
I'm using gulp-inject to inject some files ./app/scripts/**/*.js into my index.html. When gulp finds files, the plugin works as expected and injects all files. But when I remove all files from the filesystem the files aren't removed in the index.html. I experimented a little bit and found out that when at least one file is in the stream the plugin correctly removes all others. When I remove the last file, the index.html remains untouched resulting in 404's.

I reduced the problem to this simple task to reproduce it:

gulp.task('inject', function () {
  var jsFiles = gulp.src(['./app/scripts/**/*.js']);

  return gulp.src('./app/index.html')
    .pipe($.inject(jsFiles, {relative: true}))
    .pipe(gulp.dest('./app'));
});

Am I doing something wrong or is this the intended behavior?

@kavaro
Copy link

kavaro commented Oct 9, 2014

+1 having the same issue

Found the following statement in function getNewContent (file: src/inject/inject.js):

if (!collection.length) {
    log('Nothing to inject into ' + magenta(target.relative) + '.');
    return oldContent;
  }

Could this be the issue ?

@joakimbeng
Copy link
Member

This is as intended, because the injection tags are dependent on what files to inject there's no good way to determine all tags in the target file(s) without any files to inject, and therefor it's hard to know what tags to empty.

Say for instance that you have this scenario:

gulp.task('styles', ['compile-styles'], function () {
  return gulp.src('index.html')
    .pipe(inject(gulp.src('build/**/*.css', {read: false}))
    .pipe(gulp.dest('.'));
});
gulp.task('scripts', ['lint-scripts'], function () {
  return gulp.src('index.html')
    .pipe(inject(gulp.src('**/*.js', {read: false}))
    .pipe(gulp.dest('.'));
});

If one of these streams are empty, e.g. there are no built css files then there's no way for gulp-inject in the styles task to know that it's only the <!-- inject:css --> that should be empty, because without files it does not have a file extension to compare with. And if it empties all <!-- inject:<ext> --> tags, then it will break the injection for the scripts task above.

@kavaro
Copy link

kavaro commented Oct 13, 2014

hmmm, makes sense

@joakimbeng
Copy link
Member

@gruppjo @kavaro can I close this then?

@kavaro
Copy link

kavaro commented Oct 24, 2014

yes

El 24/10/2014, a las 14:59, Joakim Carlstein [email protected] escribió:

@gruppjo https://github.com/gruppjo @kavaro https://github.com/kavaro can I close this then?


Reply to this email directly or view it on GitHub #59 (comment).

@gruppjo
Copy link
Author

gruppjo commented Nov 6, 2014

Sorry for getting back to this so late...
I'm not quite sure if I understand. In your scenario: Isn't that what the starttag option is for? Then it would be clear what injection block should be emptied.

In my case I need to inject several specific files when the project is built. Since these files result in a 404 during development I need to remove those when the build is finished.
Isn't this a quite common use-case? - Or am I just missing the obvious on how to do this?
If you're interested I'm happy to provide some more detailed information.

@joakimbeng
Copy link
Member

@gruppjo yes, but starttag and endtag are dynamic, i.e. they can contain {ext} which will be replaced by the file to inject's extension before trying to find the tags in the target file. And if there is no source file, then gulp-inject cannot know what to replace {ext} with...

Please provide more information, and particularly an example of what you're trying to accomplish. Because my question now is: why do you inject files if you're going to remove them anyway? (I have one injection task for development and one for production when the end result should be different)

@gruppjo
Copy link
Author

gruppjo commented Jan 7, 2015

The following scenario: I'm building mobile apps with cordova. Cordova provides a cordova.js file which needs to be injected per platform (ios, android, etc...). When developing the app in the browser, no cordova.js file should be injected. Thus I have two injection blocks in my index.html

<!-- build:js scripts/vendor.js -->
<!-- inject:cordova:js --> 
<!-- endinject -->
<!-- bower:js -->
<!-- endbower -->
<!-- endbuild -->

<!-- build:js scripts/app.js -->
<!-- inject:js -->
<!-- endinject -->
<!-- endbuild -->

First block injects cordova.js and allo bower components and builds them into vendor.js.
Second block injects all application js files.

When running gulp build --target=ios the injection task is designed to run

gulp.src('./app/index.html')
    .pipe($.inject(cordovaFile, {starttag: '<!-- inject:cordova:{{ext}} -->', relative: true}))
    .pipe(gulp.dest('./app'));

and inject the cordova.js.

When I run gulp watch the cordova.js should to be removed, since it's not available on the desktop. I figured this could established by just providing an empty stream. However this doesn't work. So after every build I get a 404for the cordova.js when running gulp watch. Additionally I need to be careful to not check in the cordova.js script line in the index.html in my git repository.

Does this help?

@johnpapa
Copy link

johnpapa commented Feb 1, 2015

I've also got a scenario where I want to inject a section of files only if a argument is passed to gulp. If that arg is missing , i want the inject block to be emptied. I'm working around it with a hack right now, but it would be nice to have an option to remove files if its an empty stream.

@kurdin
Copy link

kurdin commented Feb 16, 2015

Because my question now is: why do you inject files if you're going to remove them anyway? (I have one injection task for development and one for production when the end result should be different)

Because sometimes we need to use same HTML file, where we want to inject (dev) or remove (prod) JavaScript files depending on environment.

I've also got a scenario where I want to inject a section of files only if a argument is passed to gulp. If that arg is missing , i want the inject block to be emptied. I'm working around it with a hack right now, but it would be nice to have an option to remove files if its an empty stream.

+1, this would be very nice if we can remove/empty injected block with option like emptyTag : true

@kurdin
Copy link

kurdin commented Feb 16, 2015

in case if anybody need workaround, here is how I remove scripts with gulp-replace

var replace = require('gulp-replace');
...
gulp.task('remove-dev-js', function() {
  return gulp.src('./html/**/*.html')
    .pipe(replace(/<!-- (.*?):js -->([\S\s]*?)<!-- endinject -->/gmi, '<!-- $1:js -->\n<!-- endinject -->'))
    .pipe(gulp.dest('./html'));
});

@derekgreer
Copy link

I submit that a build-in solution is definitely needed. Perhaps an options can be added that allows for specifying a common prefix and a removeTags flag for removing the tags marked with a prefix prior to injection.

@derekgreer
Copy link

The desire to remove sections probably arises for many where style sheets or scripts need to be injected in a particular order for local/debug builds and as combined/minifed for release builds. For example:

<!-- bower:js -->
<!-- endinject -->

<!-- otherThirdParty:js -->
<!-- endinject -->

<!-- myStuff:js -->
<script src="~/dist/lib/how-it-be-in-prod-9cebad55e4.js"></script>
<!-- endinject -->

For such cases, another workaround to consider is to use a single injection tag for all script types and combine multiple streams into one stream which is passed to inject. This will also allow you to conditionally combine streams based upon environment variables, etc. The best library I've found for doing this is streamqueue.

Here's an example:

gulp.task("inject-dependencies", function() {
  var layoutStream = gulp.src("./index.html", { base: "./" });

  var firstStream = gulp.src("something/**/*", { read: false });
  var secondStream = gulp.src("something/**/*", { read: false });
  var thirdStream = gulp.src("something/**/*", { read: false });

  var stream = isRelease ? firstStream : queue({ objectMode: true }, secondStream, thirdStream);

  return layoutStream
    .pipe($.inject(stream, {
      name: "scripts",
      relative: false,
      addRootSlash: false
    }))
    .pipe(gulp.dest("./"));
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants