deepak1556 / gulp-browserify

Bundle modules with BrowserifyJS
MIT License
195 stars 45 forks source link

Trouble with external (multiple bundles) #55

Open vincentmac opened 10 years ago

vincentmac commented 10 years ago

I'm having trouble setting up multiple bundles. What I am trying to do is have one task to bundle my vendor libraries (vendor.js) and another task to bundle my application logic (main.js).

My vendor task is something like this:

var bower = 'app/bower_components';

// Vendor
gulp.task('vendor', function () {
  return gulp.src([
    bower + '/angular/angular.js',
    bower + '/angular-route/angular-route.js',
    bower + '/lodash/dist/lodash.js'
    ])
    .pipe($.browserify({
      debug: true,
      insertGlobals: true,
      transform: [
        'debowerify'
      ],
      shim: {
        angular: {
          path: bower + '/angular/angular.js',
          exports: 'angular'
        },
        'angular-route': {
          path: bower + '/angular-route/angular-route.js',
          exports: 'ngRoute',
          depends: {
            angular: 'angular'
          }
        },
        lodash: {
          path: bower + '/lodash/dist/lodash.js',
          exports: '_'
        }
      },
      alias: [
        bower + '/angular/angular.js:angular',
        bower + '/angular-route/angular-route.js:angular-route',
        bower + '/lodash/dist/lodash.js:lodash'
      ]
    }))
    .pipe($.concat('vendor.js'))
    // .pipe($.uglify())
    .pipe(gulp.dest('dist/scripts'))
    .pipe($.size());
});

My Scripts task (which should be able to require vendor libraries from the vendor.js bundle above) looks something like this:

// Scripts
gulp.task('scripts', function () {
  return gulp.src('app/scripts/main.js', {read: false})
    .pipe($.browserify({
      debug: true,
      transform: [
        'browserify-jade',
        'debowerify'
      ],
      external: ['angular', 'angular-route', 'lodash'],
      insertGlobals: true,
    })
    .on('prebundle', function(bundle) {
      bundle.external('angular');
      bundle.external('angular-route');
      bundle.external('lodash');
    }))
    // .pipe($.uglify())
    .pipe(gulp.dest('dist/scripts'))
    .pipe($.size())
    .pipe($.connect.reload());
});

When I run the scripts task any external library which should be requirable from vendor.js is still being included inside my main.js bundle. I've tried multiple variations on this (I'm a little unclear what exactly the {read: false} option does. I've also tried playing around with the bundle.external method including the aliased name (ie angular) and the path (app/bower_compontents/angular/angular.js or ./app/bower_compontents/angular/angular.js), but am still getting the vendor libraries bundled into main.js.

Can you please point me in the right direction? I'm able to do something very similar to this in grunt, but am unable to get this working correctly in gulp.

vincentmac commented 10 years ago

A little follow up on this.

If I set the browserify-shims in my package.json file, browserify will correctly exclude my vendor files from the bundle.

I've updated my package.json file to include settings for browserify, browser, and browserify-shim:

{
  "name": "ngify-test",
  "version": "0.0.0",
  "devDependencies": {
    "gulp": "3.5.2",
    "gulp-load-plugins": "~0.3.0",
    "gulp-browserify": "~0.4.4",
    "gulp-util": "~2.2.14",
    "gulp-autoprefixer": "~0.0.6",
    "gulp-csso": "~0.2.3",
    "gulp-jade": "~0.4.1",
    "gulp-jshint": "~1.4.0",
    "gulp-imagemin": "~0.1.5",
    "gulp-clean": "~0.2.4",
    "gulp-uglify": "~0.2.1",
    "gulp-concat": "~2.1.7",
    "gulp-cache": "~0.1.1",
    "gulp-sass": "~0.7.0",
    "gulp-size": "~0.1.3",
    "gulp-connect": "~0.3.1",
    "browserify": "~3.30.0",
    "debowerify": "~0.5.2",
    "browserify-jade": "~0.1.1",
    "mocha": "~1.17.1",
    "should": "~3.1.2",
    "jshint-stylish": "~0.1.5",
    "browserify-shim": "~3.2.2"
  },
  "engines": {
    "node": ">=0.10.0"
  },
  "browserify": {
    "transform": ["browserify-shim"]
  },
  "browser": {
    "angular": "./app/bower_components/angular/angular.js"
  },
  "browserify-shim": {
    "angular": "global:angular"
  }
}

Now in the scripts task of my gulpfile.js file, I have updated it to look like this:

// Scripts
gulp.task('scripts', function () {
  return gulp.src('app/scripts/main.js', {read: false})
    .pipe($.browserify({
      debug: true,
      transform: [
        'browserify-jade',
        'debowerify'
      ],
      external: ['angular', 'angular-route', 'lodash']
    }))
    // .pipe($.uglify())
    .pipe(gulp.dest('dist/scripts'))
    .pipe($.size())
    .pipe($.connect.reload());
});

This works, however, it feels like something is not working correctly. Am I configuring my gulpfile incorrectly? I don't think having to set the browserify shim in package.json is an ideal solution.

shuhei commented 10 years ago

@vincentmac Thanks for sharing!

I don't think having to set the browserify shim in package.json is an ideal solution.

I don't either especially with gulp but that's browserify-shim's design. It only loads config from package.json. It's reasonable because the first priority of browserify transforms is to work with CLI.

This works, however, it feels like something is not working correctly.

Why do you think it's not working correctly?

vincentmac commented 10 years ago

Yes, I understand that setting browserify-shim in package.json is the default behavior, however, in grunt-browserify you are able to set your shims directly in that task and they are passed to browserify-shim. Same applies for setting you external requires.

I'll post a sample of what I'm talking about from grunt when I get home. It's possible that I'm not explaining my issue clearly.

deepak1556 commented 10 years ago

@vincentmac thats because they are still on browserify-shim v2..0.10, with browserify-shim v3 the above method is the right way. Even grunt-browserify will be making some core changes in their v2.0 release https://github.com/jmreidy/grunt-browserify/issues/109

humidair1999 commented 10 years ago

I would absolutely kill for a working example of what @vincentmac was attempting to accomplish here; I've followed guidance in this thread, https://github.com/deepak1556/gulp-browserify/issues/53, and https://github.com/deepak1556/gulp-browserify/issues/48, and none of them are complete or clear enough; still not working.

I refuse to believe that you have to specify src for each file, gulp shim paths for each file, alias paths for each file, AND the relevant package.json properties... Not to mention utilizing the transform in both places. That seems incredibly redundant.

jhchill666 commented 10 years ago

Will provide one this weekend if still required?

humidair1999 commented 10 years ago

Personally, I've moved away from using build tools like grunt and gulp with browserify, as they were doing nothing but increasing complexity and making it difficult to achieve what I was hoping to do.

I do think an example would still be useful, though, especially for future users of gulp-browserify.

TimothyKrell commented 10 years ago

I would really like to see an example for this as well, if you have time @jamiehill

jhchill666 commented 10 years ago

Ok guys, I've finally had time to tidy up my code and push an example. It's not production quality ;) but works out of the box, and will hopefully get you on track

https://github.com/jamiehill/externalise-bower

I think the key here, is to keep-it-simple and minimise complexity. The `package.json' file is where your config should be. No point cluttering up gulp.

As you can see, the only transform I'm using is Deamdify, which effectively 'shims' anything that needs 'shimming'. I experimented alot with Debowerify, but it just didn't give me what I wanted off the shelf.

More-over, it does the opposit - it includes by default all bower component packages in your app/whatever.js. Simply removing it and letting the brilliant Deamdify do it's magic is enough to get going.

TimothyKrell commented 10 years ago

Sweet! This is exactly what I've been looking for. Thanks!

jhchill666 commented 10 years ago

It uses a packager under the hood, that I wrote, which basically just resolves bower package names, and endpoints. Otherwise is standard Browserify functionality.

Might be worth wrapping Browserify and releasing as a plugin if there was sufficient interest.

TimothyKrell commented 10 years ago

Were you thinking of making a gulp plugin? It seems like it would be nice if it weren't coupled to a specific version of browserify, so users didn't have to wait for the plugin to be updated to use a newer version.

After doing some more research, I am using browserify straight without gulp-browserify.

I had also been messing with Debowerify like you, but ran into conflicts with Browserify-Shim. Your packager looks really handy either way, but I think I would like using it more without it wrapping Browserify. Just a thought.

sogko commented 10 years ago

Hey guys,

I've forked @jamiehgill excellent example and replaced use of gulp-browerify with vanilla browserify + vinyl-source-stream (the recommended way these days)

https://github.com/sogko/externalise-bower

@jamiehill Your packager seems promising, and I would be interested in using it as a Bower util (to get package names/ids, resolves package names to ids, resolve ids to full path etc). But at the current state, there's too much coupling to gulp-browserify. I'm guessing it'd be more useful if its a standalone bower package util of some sorts.

In the forked example, I used your packager externally in gulpfile.js.

Hope this helps anyone else along the way trying to get gulp + browersify + bower + multiple bundles working.

_Update:_ I've replaced the use of the packager with bower-resolve instead. Still lacks a clean way to get all package ids in bower.json,

iongion commented 10 years ago

unbelievable how ugly and unclear this still is, this entire issue, brave people @sogko, @jamiehill

cherrydev commented 8 years ago

While this is no longer maintained, I've been having similar problems getting this working properly when using browserify directly and wanting to create a vendor bundle from modules being resolved from node_modules, I used this as an example of how to get this working. I stumbled across this issue while searching for a solution so maybe this'll help someone.