webpack/webpack-cli

Variables passed to `--env` with an empty value are incorrectly parsed

benjaminblack opened this issue · 5 comments

Describe the bug

When passing env vars to webpack cli using --env, if the value of the variable passed is empty, then the resulting variable name and value is parsed incorrectly. As an example, webpack --env TEST="" results in the following env:

{
  WEBPACK_BUNDLE: true,
  WEBPACK_BUILD: true,
  'TEST=': true
}

What is the current behavior?

Empty variables passed to --env like --env VAR="" or --env VAR=$NOT_DEFINED result in the env object containing property names like VAR= with the value true.

To Reproduce

Minimal webpack.config.js demonstrating behavior:

import { fileURLToPath } from "node:url";

export default (env) => {
  console.log(env);

  return {
    mode: "production",
    entry: "./main.js",
    output: {
      path: fileURLToPath(new URL(".", import.meta.url)),
      filename: "main.bundle.js",
    },
  };
};

Steps to reproduce the behavior:

$ npx webpack --env TEST1="" --env TEST2=$NON_EXISTENT_ENVVAR --env TEST3=

Expected behavior

Empty variables could be represented as one of null, undefined, or "", but certainly should not be true, and the property name should not include the =.

Screenshots

N/A

Please paste the results of npx webpack-cli info here, and mention other relevant information

$ npx webpack --env TEST1="" --env TEST2=$NON_EXISTENT_ENVVAR --env TEST3=
{
  WEBPACK_BUNDLE: true,
  WEBPACK_BUILD: true,
  'TEST1=': true,
  'TEST2=': true,
  'TEST3=': true
}
asset main.bundle.js 50 bytes [compared for emit] [minimized] (name: main)
./main.js 28 bytes [built] [code generated]
webpack 5.73.0 compiled successfully in 82 ms

Additional context

None

PR welcome

Note

The catch here is that you have to escape the empty string on the terminal like this: npx webpack --env TEST1=\"\"

@benjaminblack @alexander-akait this is a duplicate of #2642 and was fixed in #2643.

We also have test cases for this:

it("Supports empty string", async () => {
const { exitCode, stderr, stdout } = await run(__dirname, ["--env", `foo=''`]);
expect(exitCode).toBe(0);
expect(stderr).toBeFalsy();
expect(stdout).toBeTruthy();
// Should generate the appropriate files
expect(existsSync(resolve(__dirname, "./dist/empty-string.js"))).toBeTruthy();
});
it('Supports empty string with multiple "="', async () => {
const { exitCode, stderr, stdout } = await run(__dirname, ["--env", `foo=bar=''`]);
expect(exitCode).toBe(0);
expect(stderr).toBeFalsy();
expect(stdout).toBeTruthy();
// Should generate the appropriate files
expect(existsSync(resolve(__dirname, "./dist/new-empty-string.js"))).toBeTruthy();
});
it('Supports env variable with "=" at the end', async () => {
const { exitCode, stderr, stdout } = await run(__dirname, ["--env", `foo=`]);
expect(exitCode).toBe(0);
expect(stderr).toBeFalsy();
expect(stdout).toBeTruthy();
// Should generate the appropriate files
expect(existsSync(resolve(__dirname, "./dist/equal-at-the-end.js"))).toBeTruthy();
});

But yes I feel if it ends with = we should set it to undefined instead of setting foo=: true. I'll raise a patch for this.

I'm not invoking Webpack through the terminal, I'm doing it through package.json.

With this script:

 "webpack": "webpack --env TEST=\"\""

The result is a property of TEST= with a value of true.

With this:

  "webpack": "webpack --env TEST=\\\"\\\""

The result is a property of TEST, but the value is '""' -- which is not an empty string, which would be falsy, but a string containing "", which is truthy.

No matter which variation I try, I can't get a property of TEST with a value that is falsy, which is what I'd expect.

The result is a property of TEST, but the value is '""' -- which is not an empty string, which would be falsy, but a string containing "", which is truthy.

Expected, because you have "" string, it is truthy

But webpack --env TEST="" should be falsy, it is bug on our side