Reputation: 3256
I'm trying to bundle up my own code (A) which in turn uses 2 third party components (B and C) where C also needs B. Everything as far as I know is written using CommonJS node style modules.
A on its own when bundled comes out at 60K.
B is included separately and assumed to be global, I've got this working just fine by doing a dirty bit of a replace in my build step that swaps out require("B") with global.B
C is whats causing me issues though, its meant to be "just 8K" in size yet when I try bundling it up with A my bundle jumps up to 600K+ as I assume its pulling in dependancies galore?
This is not acceptable but I don't know how to get it any smaller as I don't know what the heck its pulling in (or more importantly what I can exclude to make it still work). I could try a binary chop with the exculsions but I'd don't know if that is a safe way or even sensible way to do it.
How can I bundle C up and only have my bundle come out at 68.5K (total size of both chunks of code 60k + 8.5k) and of course still work?
I'm new to node and browserify but I've been hammering on this for over a week so fair to say I've given it a good stab before putting my hand up.
Additional info if it matters:
Upvotes: 6
Views: 8325
Reputation: 6245
You can see which files are taking up space in the bundle by running this command: browserify --list test/browser/browserify-test-uncompiled.js | xargs ls -la | sort
Upvotes: 0
Reputation: 439
I've put together a working example for how to split code into multiple bundles using Browserify: https://github.com/aldendaniels/browserify-bundle-splitting
With this approach you can load all your vendor code via Browserify (no global shimming needed), but still have your own code bundled separately.
Since the generated bundles are truly independent, you can easily have different settings for the generated bundles. For example, you might want to disable source maps for 3rd party code, but use source maps for your own code.
Upvotes: 1
Reputation: 382
Someone else already mentioned the external option which should be the actual solution. Now, do consider these pieces of advice as well. You might know most if not all of it already but some of it might help. This won't turn the 600k file into 1k but might be significant nonetheless.
Begin by checking out the advanced options in https://github.com/substack/node-browserify#usage and more specifically the --no-bundle-external option. If the external option does work with require('b') but still includes the external libraries, this is your best bet;
Also look at the options about the global variables as well. When I started out with browserify I had a single function compile into a huge library as it contained all the stubs for the NodeJS native modules. The aforementioned options were key in solving this issue. It was in a Grunt-task but if I recall correctly it wasn't with the grunt-browserify task, it still might be relevant.
Do set the build environment before running browserify:app if you haven't already done that. There are libraries which depend on these variables for their production compilation (I think React is one of them).
grunt.loadNpmTasks('grunt-env');
// initConfig task
env: {
dist: {
NODE_ENV : 'production',
},
dev: {
NODE_ENV: 'development',
}
}
grunt.registerTask("build_dist", ['env:dist', 'browserify:app']
Try running Uglify with specifically these options as well;
// initConfig task options
options: {
compress:{
dead_code : true, // discard unreachable code
drop_debugger : true, // discard “debugger” statements
global_defs : { // global definitions
"DEBUG": false, // matters for some libraries
},
}
}
You can optimize a lot more but this should get you started.
B is included separately and assumed to be global, I've got this working just fine by doing a dirty bit of a replace in my build step that swaps out require("B") with global.B.
If you're swapping to global.B after the compilation your package will have all of require('b')'s dependencies as well. This hack is (probably) better:
b-singleton.js content:
module.exports = window.B;
This is not acceptable but I don't know how to get it any smaller as I don't know what the heck its pulling in (or more importantly what I can exclude to make it still work)
Go look inside the source code of the generated library, you should be able to identify the different modules and their filepath.
Upvotes: 2
Reputation: 62813
If you create an external bundle containing all your app's dependencies (B + C) and declare those modules as external when bundling your app's own code (A), then things should work as you expect.
I don't know the grunt-browserify config incantations for doing this, but the following show how you'd use browserify directly in some example gulp tasks, so the bundle creation should be reusable:
var browserify = require('browserify')
var gulp = require('gulp')
var source = require('vinyl-source-stream')
gulp.task('js-deps', function() {
var b = browserify()
b.require('react')
b.require('react-router-component')
b.transform('envify')
return b.bundle()
.pipe(source('deps.js'))
.pipe(gulp.dest('./build'))
})
gulp.task('bundle-js', function() {
var b = browserify('./lib/app.js')
b.external('react')
b.external('react-router-component')
return b.bundle()
.pipe(source('app.js'))
.pipe(gulp.dest('./build'))
})
Upvotes: 5