Parcel: Cannot conditionally require modules based on process.env.NODE_ENV

Created on 26 Feb 2018  Â·  8Comments  Â·  Source: parcel-bundler/parcel

đŸ€” Expected Behavior

With the following code:

if (process.env.NODE_ENV === 'production') {
  console.log('Running in production');
} else {
  console.log('Running in development');
}

When running parcel build [input], the code console.log('Running in development') is not included in the bundle, and the code console.log('Running in production') is included. This is the expected behavior.

But with the following code:

if (process.env.NODE_ENV === 'production') {
  require('./production.js')
} else {
  require('./development.js')
}

When running parcel build [input], both the content of ./production.js and ./development.js is included in the bundle.

It seems that excluding the unused code is done during minification, which work for static code, but doesn't work with require as the bundler handled the require before minification.

😯 Current Behavior

The code within if (process.env.NODE_ENV === 'production') {...} else {...} should be included in the bundle based on the process.env.NODE_ENV variable.

🔩 Context

That would allow to use development tools like react-hot-loader that require different modules in production or development. See /src/index.js.

🌍 Your Environment

| Software | Version(s) |
| ---------------- | ---------- |
| Parcel | 1.6.2 |
| Node | 9.5.0 |
| npm/Yarn | yarn 1.3.2 |
| Operating System | OSX |

Bug

Most helpful comment

@davidnagli I was asking in general as it's useful to require some libs only in dev.

In the case of react-hot-loader they example in their repo present the same issue: the dev module is included in the production bundle. So I guess "Parcel already supports react-hot-loader out of the box" is a definition somewhat up to interpretation, or at least comes with some caveats. Yes it does work as expected in dev and the modules are hot reloaded preserving the state. But the dev modules are included in the production module.

Are there other use cases, besides react-hot-loader, where we would want to programmatically evaluate conditionals surrounding require calls? Because implementing it would be very expensive performance-wise, and wouldn’t even be needed 99% of the time since most people don’t use require in this way.

In the react ecosystem it seems there is a lot of libraries that have a dev and a prod mode that relies on process.env.NODE_ENV.
It's the case for react itself or for prop-types and pretty much any react related library.

I don't know about other client side rendering libraries (Angular, Vue etc...) but I wouldn't be surprised if it was the case.

In my opinion we should keep things the way they are, and simply walk through imports/requires, and then rely on tree shaking to try to remove them like @DeMoorJasper suggested.
If tree shaking doesn’t solve this in the future, we can try looking into traversing the AST and trying to extract the nearest conditional statement, or maybe supporting ternary operator expressions within the require (that would be pretty cool actually).

If treeshaking does the jobs that's great! Being able to remove the development code of React in production is pretty important. Not doing so would make it really difficult to use Parcel for a React app.
I'm not sure how webpack handles that, but when using create-react-app the dev code is not included in the prod package.

All 8 comments

Does the issue also occur when you set the require to a variable, so that the imported stuff actually goes somewhere?

For example, if you change your code to:

if (process.env.NODE_ENV === 'production') {
  var app = require(‘./production.js’)
} else {
  var app = require(‘./development.js’)
}

I also wonder if you get different results using the ES6 import statement

Same problem when I assign the require to a variable.
With ES6 import I don't think I can do a conditional import as the import statement must be at the file top level?

This is an expected result as parcel just walks through all the requires, this might get removed if treeshaking lands as that would recognise it’s unused and remove it

Sent with GitHawk

@DeMoorJasper Oh ya true

@pvdlg Were you asking this specifically for react-hot-loader, or in general? Because Parcel already supports react-hot-loader out of the box. See: React Hot Loader Docs #parcel

Are there other use cases, besides react-hot-loader, where we would want to programmatically evaluate conditionals surrounding require calls? Because implementing it would be _very_ expensive performance-wise, and wouldn’t even be needed 99% of the time since most people don’t use require in this way.

In my opinion we should keep things the way they are, and simply walk through imports/requires, and then rely on tree shaking to try to remove them like @DeMoorJasper suggested.

If tree shaking doesn’t solve this in the future, we can try looking into traversing the AST and trying to extract the nearest conditional statement, or maybe supporting ternary operator expressions within the require (that would be pretty cool actually).

@davidnagli I was asking in general as it's useful to require some libs only in dev.

In the case of react-hot-loader they example in their repo present the same issue: the dev module is included in the production bundle. So I guess "Parcel already supports react-hot-loader out of the box" is a definition somewhat up to interpretation, or at least comes with some caveats. Yes it does work as expected in dev and the modules are hot reloaded preserving the state. But the dev modules are included in the production module.

Are there other use cases, besides react-hot-loader, where we would want to programmatically evaluate conditionals surrounding require calls? Because implementing it would be very expensive performance-wise, and wouldn’t even be needed 99% of the time since most people don’t use require in this way.

In the react ecosystem it seems there is a lot of libraries that have a dev and a prod mode that relies on process.env.NODE_ENV.
It's the case for react itself or for prop-types and pretty much any react related library.

I don't know about other client side rendering libraries (Angular, Vue etc...) but I wouldn't be surprised if it was the case.

In my opinion we should keep things the way they are, and simply walk through imports/requires, and then rely on tree shaking to try to remove them like @DeMoorJasper suggested.
If tree shaking doesn’t solve this in the future, we can try looking into traversing the AST and trying to extract the nearest conditional statement, or maybe supporting ternary operator expressions within the require (that would be pretty cool actually).

If treeshaking does the jobs that's great! Being able to remove the development code of React in production is pretty important. Not doing so would make it really difficult to use Parcel for a React app.
I'm not sure how webpack handles that, but when using create-react-app the dev code is not included in the prod package.

Same problem here.

// in parcel
if (!process.env.BUILD_DEPLOY) {
  require('./mock')
}

but the content of './mock' was also inlined into the bundle.js though it was not required.

After some thinking it might actually be a good idea to do this before any minifying or treeshaking as it would improve performance, as all the unused code doesn’t need any processing if it never gets imported in the first place. It shouldn’t be hard to implement, I might look into it if i find the time

Sent with GitHawk

Fixed by #1166.

Was this page helpful?
0 / 5 - 0 ratings