proptypes
proptypes copied to clipboard
Removing dead code in prod builds
I've been looking a little into reducing the weight of my production libs.js and noticed that this proptypes lib was adding around ~4kb after minification, I know not much but hey every bit counts, especially when proptypes isn't used in prod builds.
Looking at preact-compat where these prop types get brought in I see you formulate a DEV var based on process.env.NODE_ENV here, that's then used to enable/disable PropType usage.
Unfortunately uglify.js with webpack DefinePlugin doesn't strip out the proptypes code based on this. Perhaps with tree shaking it might but that's not 100% working yet so I've not spent too much time there. Also I think you need to use the explicit conditional e.g. if (process.env.NODE_ENV === 'production') for uglify stripping to work (see below).
Looking at React code they stub out all the prop type validators and use these when process.env.NODE_ENV is production'. They actually have a babel processor which replaces __DEV__ with process.env.NODE_ENV !== 'production.
So first pass I tried formulating the DEV var like you did in preact compat and applying it. That didn't work though. For uglify to strip the code you seem to have to use the explicit check in the conditional, and on it's own.
if (process.env.NODE_ENV !== 'production'`) {
} else {
}
which webpack will replace with the following in prod builds
if (false) { ...
https://github.com/developit/proptypes/compare/master...mikestead:feature/prod-noop?expand=1#diff-1fdf421c05c1140f6d71444ea2b27638R117
So the above works and my libs shrink
libs.c1c2e08.js 131 kB 1, 2 [emitted] libs // before
libs.a0e99bd.js 127 kB 1, 2 [emitted] libs // after
My problem is how to polyfill process.env IN the proptypes index.js. I tried something like the following
if (typeof process === 'undefined') {
var process = {};
}
if (!process.env) {
process.env = {};
}
but that interferes with the uglify stripping too. I think it would need polyfilled outside of this module for it to work?
Not super high priority, just hoped there may be a quick win.
Hi @mikestead - would something like this work?
if (typeof process!=='undefined' && process.env.NODE_ENV!=='production') {
} else {
}
FWIW, I have found that you have to add a tiny bit extra in DefinePlugin to get things removed:
new DefinePlugin({
process: {},
'process.env': {},
'process.env.NODE_ENV': JSON.stringify('production')
})
Thanks for the input and tip, if I add process and process.env to the define plugin with no changes to PropTypes lib I do indeed see a little more code removed, and from react-router as well as preact/preact-compat.
libs.e47828f.js 129 kB 1, 2 [emitted] libs
I guess that's for code that also checks the parent chain of process.env.NODE_ENV in a conditional.
You are also correct the following does seem to work, and without touching the DefinePlugin.
if (typeof process!=='undefined' && process.env.NODE_ENV!=='production') {
But we're obv not checking for env here. If I add that check code isn't stripped... unless I go make those additions to the DefinePlugin :)
For backwards compatibility I tried switching it to
if (typeof process!=='undefined' && process.env.NODE_ENV==='production') {
and inverting the if else blocks, but then the code wasn't stripped. I guess Uglify may only like stripping from the if block?
If I swap back and then add process and process.env to DefinePlugin I can use an OR
if (typeof process==='undefined' || !process.env || process.env.NODE_ENV!=='production') { // dev
Let me know what you want to do, if anything and I'm happy to open a pull request.