ludohenin / gulp-inline-ng2-template

Gulp plugin to inline HTML and CSS into Angular 2 component decorators
MIT License
126 stars 26 forks source link

Not working correctly with Watchify #55

Open Yimiprod opened 8 years ago

Yimiprod commented 8 years ago

After modifying a build for ionic2 to include gulp-inline-ng2-template i stumble upon a strange bug case, the transform with ng2TemplateParser isn't applied if browserify/watchify/gulpWatch is used.

I'm not sure from where the problem come from so i post it to your knowledge.

var gulp = require('gulp'),
    gulpWatch = require('gulp-watch'),
    browserify = require('browserify'),
    watchify = require('watchify'),
    tsify = require('tsify'),
    pretty = require('prettysize'),
    merge = require('lodash.merge'),
    source = require('vinyl-source-stream'),
    buffer = require('vinyl-buffer'),
    sourcemaps = require('gulp-sourcemaps'),
    uglify = require('gulp-uglify'),
    stream = require('stream'),
    ng2TemplateParser = require('gulp-inline-ng2-template/parser')
    through = require('through2');

var defaultOptions = {
  watch: false,
  src: ['./app/app.ts', './typings/index.d.ts'],
  outputPath: 'www/build/js/',
  outputFile: 'app.bundle.js',
  minify: false,
  browserifyOptions: {
    cache: {},
    packageCache: {},
    debug: true,
    base: '/app',
    useRelativePaths: true,
    supportNonExistentFiles: false
  },
  watchifyOptions: {
    verbose: true
  },
  tsifyOptions: {},
  uglifyOptions: {},
  onError: function(err){
    console.error(err.toString());
    this.emit('end');
  },
  onLog: function(log){
    console.log((log = log.split(' '), log[0] = pretty(log[0]), log.join(' ')));
  }
}

module.exports = function(options) {
  options = merge(defaultOptions, options);

  var b = browserify(options.src, options.browserifyOptions)
    .plugin(tsify, options.tsifyOptions)
    .transform(function(file) {
      return through(function (buf, enc, next) {
        ng2TemplateParser({contents: buf, path: file}, options.browserifyOptions)((err, result) => {
          this.push(result);
          process.nextTick(next);
        });
      });
    });

  if (options.watch) {
    watchify(b, options.watchifyOptions);
    b.on('update', bundle);
    b.on('log', options.onLog);
    gulpWatch('app/**/*.html', bundle);
  }

  return bundle();

  function bundle() {
    return b.bundle()
      .on('error', options.onError)
      .pipe(source(options.outputFile))
      .pipe(buffer())
      .pipe(gulp.dest(options.outputPath));
  }
}
MiniGab commented 8 years ago

I have a working and dirty solution for ionic2.

Here is my code :

function templateInliner(file) {
    return through(function (buf, enc, next) {
        ng2TemplateParser({ contents: buf, path: file }, inlinerOptions)((err, result) => {
            this.push(result);
            process.nextTick(next);
        });
    }); 
}

var buildBrowserify = function (options) {
    options = merge(defaultOptions, options);
    var b = browserify(options.src, options.browserifyOptions)
      .plugin(tsify, options.tsifyOptions);

    if (options.watch) {
        b = watchify(b, options.watchifyOptions);
        b.on('update', bundle);
        b.on('log', options.onLog);
    }

    b = b.transform(templateInliner);

    return bundle();

    function bundle() {
        var debug = options.browserifyOptions.debug;
        return b
          .bundle()
          .on('error', options.onError)
          .pipe(source(options.outputFile))
          .pipe(buffer())
          .pipe(debug ? sourcemaps.init({ loadMaps: true }) : noop())
          .pipe(options.minify ? uglify(options.uglifyOptions) : noop())
          .pipe(debug ? sourcemaps.write('./', { includeContent: true, sourceRoot: '../../../' }) : noop())
          .pipe(gulp.dest(options.outputPath));
    }

    function noop() {
        return new stream.PassThrough({ objectMode: true });
    }
}

hope this helps

Yimiprod commented 8 years ago

It look a lot like my last version I posted on the forum ionic2 but thanks :D The only problem with this version is there no watching of the templates. But it work in this form.

ludohenin commented 8 years ago

Can we close ?

mogusbi commented 8 years ago

Surely this should still be open as the issue still persists (templates not being watched)?

Colorfulstan commented 7 years ago

Here is my solution to trigger rebuilds when indirect dependencies change:

// ng2inlinetransform.js
var ng2TemplateParser = require('gulp-inline-ng2-template/parser');
var through = require('through2');

module.exports = function (file) {
    return through(function (buf, enc, next) {
        var stream = this
        var fileProcessorFn = function (path, ext, file, callback) {
            try {
                // emitting the file for watchify to pick it up as dependency and triggering rebuild on change
                // https://github.com/substack/watchify/issues/215
                stream.emit('file', path)
                callback(null, file);
            }
            catch (err) {
                callback(err);
            }
        }

        // rest is done as documented
        // https://github.com/ludohenin/gulp-inline-ng2-template#browserify-transform-example
        var options = {
            target: 'es6',
            useRelativePaths: true,
            templateProcessor: fileProcessorFn,
            styleProcessor: fileProcessorFn
        };

        ng2TemplateParser({contents: buf, path: file}, options)((err, result) => {
            this.push(result);
            process.nextTick(next);
        });
    });
}
daKuleMune commented 7 years ago

This should not have been close before being at least explained in the README.md. The fact that I found this was dump luck. Colorfulstan answer is by far the most descriptive, as it can easily be applied to the style method as well.

ludohenin commented 7 years ago

Would you please make a PR for that ?

daKuleMune commented 7 years ago

Sure although if I fork this project, I have noticed that small scale this project is fine, but once you have a decent project size the builds can take 40+ seconds and 10 seconds to do a single file update. So I would like to see what I can do to optimize the build time. Doing manual copies of the file contents only added a second to the full build time, so there is something used here that is not scaling very well, but that is a different issue, so I will see about making a bug for that and implementing both in a fork.