Buffer shim included even if External is added

Do you want to request a feature or report a bug?
Bug

What is the current behavior?

When Buffer invocations are guarded in a typeof check, even when Buffer is added as an external web pack will inject the buffer shim.

If the current behavior is a bug, please provide the steps to reproduce.

$ cat index.js 
function isbuf(x) {
	if(typeof Buffer !== 'undefined') return Buffer.isBuffer(x); // <-- buffer use is guarded by a typeof check
	return false;
}
$ cat webpack.config.js 
module.exports = {
	"entry": "./index.js",
	"output": {
		"filename": "./out.js"
	},
	"externals": {
		"Buffer": { // <-- this should be telling web pack not to include the buffer shim
			"root": "Buffer"
		},
		"buffer": {
			"root": "Buffer"
		}
	}
}
$ webpack index.js 
Hash: df0a684f7a2699d0b0ac
Version: webpack 2.2.1
Time: 172ms
   Asset     Size  Chunks             Chunk Names
./out.js  58.1 kB       0  [emitted]  main
   [0] ./index.js 99 bytes {0} [built]
   [1] (webpack)/buildin/global.js 509 bytes {0} [built]
   [2] (webpack)/~/base64-js/index.js 3.48 kB {0} [built]
   [3] (webpack)/~/buffer/index.js 48.6 kB {0} [built] # <-- buffer is inexplicably included
   [4] (webpack)/~/ieee754/index.js 2.05 kB {0} [built]
   [5] (webpack)/~/isarray/index.js 132 bytes {0} [built]
   [6] multi ./index.js ./index.js 40 bytes {0} [built]
$ grep SlowBuffer out.js | head -n 1
exports.SlowBuffer = SlowBuffer # <-- proof that the buffer shim was really added to the bundle

What is the expected behavior?

If Buffer is declared as an external, webpack should not be adding the Buffer shim.

If this is a feature request, what is motivation or use case for changing the behavior?

Please mention other relevant information such as the browser version, Node.js version, webpack version and Operating System.

web pack 2.2.1 node 7.5.0

Author: Fantashit

3 thoughts on “Buffer shim included even if External is added

  1. If you want to disable Buffer handling: node: { Buffer: false }.

    The correct syntax for externals: externals: { buffer: "root Buffer" }

  2. @RickBRoss (and the 8 upvoters of his question ;))
    Some JS libraries try to be environment-independent and automatically work both in the browser and in nodejs, by doing feature detection at runtime.

    if (isNodeJs()) {
       /* use some nodejs built-in */
      Buffer.alloc(...)
    } else {
       /* we're in a browser: import some library and do it in a different way */
    }
    

    To be user-friendly, webpack automatically shims some node built-ins (for example it bundles a Buffer polyfill for the browser) when encountering such code. The problem is that this may lead to shipping a large unused polyfill if the code path is never taken. (But if this was not implemented, some npm deps that were only written for nodejs would fail at runtime when running in the browser. Which behavior is better is debatable.)

    Anyway, if you know that you don’t need those shims (i.e. you target browser env only, and the nodejs-specific code paths are never executed), you can exclude them via config. The tricky thing is that most likely, this kind of code will not be in your codebase, but in your dependencies. Unless you do codebase analysis with webpack visualizer or similar tool, normally you won’t even know that this is happening.

    IMO if you have a browser-targeting project, it probably makes sense to disable all node builtins polyfilling, and only reenable when you discover you need it. That way you won’t be surprised with large bundle size increase when adding an innocuously-looking dependency one day.

    More docs: https://webpack.js.org/configuration/node/

Comments are closed.