Skip to content

Unset env variables are not properly embedded #8961

Closed
@cauthmann

Description

@cauthmann

Describe the bug

Variables like REACT_APP_FOO are hard-baked into the code if they were present in the environment during build-time. Referencing a variable that did not exist during build time results in rather useless code that cannot be minified:

process.env.REACT_APP_FOO

->

Object({
    NODE_ENV: "production",
    PUBLIC_URL: "",
    WDS_SOCKET_HOST: void 0,
    WDS_SOCKET_PATH: void 0,
    WDS_SOCKET_PORT: void 0
}).REACT_APP_FOO

This will neither cause an error, not is it minified into a constant expression.

Full example further below.

Did you try recovering your dependencies?

Problem is reproducible on a fresh install.
> npm --version: 6.14.4

Which terms did you search for in User Guide?

This behaviour is not documented on
https://create-react-app.dev/docs/adding-custom-environment-variables/

Environment

Environment Info:

  current version of create-react-app: 3.4.1

  [Tested on multiple systems, everything else is irrelevant]

Steps to reproduce

> npx create-react-app test
> cd test
> $EDITOR src/index.js

index.js:

if (process.env.REACT_APP_FOO) {
	console.log('Foo is enabled');
}
else {
	console.log('Foo is disabled');
}
> npm run build
> cat build/static/js/main*.js

main*.js (prettified):

(this.webpackJsonptest = this.webpackJsonptest || []).push([
    [0],
    [function(o, s, e) {
        o.exports = e(1)
    }, function(o, s) {
        Object({
            NODE_ENV: "production",
            PUBLIC_URL: "",
            WDS_SOCKET_HOST: void 0,
            WDS_SOCKET_PATH: void 0,
            WDS_SOCKET_PORT: void 0
        }).REACT_APP_FOO ? console.log("Foo is enabled") : console.log("Foo is disabled")
    }],
    [
        [0, 1]
    ]
]);

Expected behavior

  • Preferred: the build emits a warning or an error when referencing a missing variable. It's most likely either a typo in the variable name, or a broken build configuration.
  • Alternatively, the variable is replaced with undefined or void 0 or '' or some other sensible default value.
  • Alternatively, this behaviour is at least documented with a warning on the corresponding page.

The workaround is to define a default value for every used variable in .env and commit the file, but that doesn't protect against mistyped identifiers in the code.

Actual behavior

See above for actual output. The output contains both '"Foo is enabled"' and "Foo is disabled", even though one of them is dead code.

Reproducible demo

See above.

I am not sure how best to resolve the issue.

Replacing with undefined or '' isn't easy:

  • It's not a bug in terser - the code could evaluate to something other than undefined if someone sets Object.prototype.REACT_APP_FOO, so terser is not allowed to minify here. Playing around with terser's repl, I was unable to find a different construct for process.env that would allow minification here.
  • webpack's DefinePlugin does not allow regexps for replacements; substituting REACT_APP_.* is not possible.

Emitting an error isn't easy:

  • scanning the build output for remaining process.env.REACT_APP_ won't work, and scanning for the whole code snippet above seems really fragile.

This could be solved by moving the replacement logic from DefinePlugin into a custom babel plugin (similar to this one). Considering that cra only supports replacing with strings, and not with arbitrary javascript code, that might work. Is babel guaranteed to be run on every source file, including typescript?

If all else fails, I think it deserves at least a warning in the documentation.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions