Repository: parcel-bundler/parcel (js)

Issue:
Electron: "require" is transpiled to "undefined"
<!---
Thanks for filing an issue 😄 ! Before you submit, please read the following:

Search open/closed issues before submitting since someone might have asked the same thing before!
-->

# 🐛 bug report

I've been using Parcel 2.0.0.beta-2 in my Electron app and it's been great. Saw the announcement today and upgraded, but something seems to have changed: my `require` calls are being replaced with `undefined` in my Electron dev build.

I think it's being tree-shaken? Works fine in the browser. I haven't had time to investigate yet, but I'm flagging it in case it's something obvious that I need to change between beta 2 and 3. 

![image](https://user-images.githubusercontent.com/42827/119065934-81909780-b993-11eb-969d-490f3a2c2241.png)

<img width="605" alt="Screen Shot 2021-05-20 at 5 35 53 PM" src="https://user-images.githubusercontent.com/42827/119065392-46419900-b992-11eb-991d-752a5a86cd8e.png">

I'm still trying alternatives, just wanted to see whether there's something obvious I've missed. I've tried replacing `window.require` with `require`, basically everything obvious. The code as written originally works fine in the console: 

![image](https://user-images.githubusercontent.com/42827/119065971-90774a00-b993-11eb-8549-e202b74d8e11.png)

## 🎛 Configuration (.babelrc, package.json, cli command)

Parcel: Just upgraded from 2.0.0.beta-2
.babelrc: Still present

```json
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "esmodules": true
        }
      }
    ],
    "@babel/preset-react"
  ],
  "plugins": [
    [
      "import",
      {
        "libraryName": "@react-icons",
        "camel2DashComponentName": false,
        "transformToDefaultImport": false,
        "customName": "../../..//react-icons.js"
      },
      "@react-icons"
    ],
    [
      "babel-plugin-root-import",
      {
        "rootPathSuffix": "./src/main",
        "rootPathPrefix": "~/"
      }
    ],
    "@babel/plugin-proposal-optional-chaining",
    [
      "auto-import",
      {
        "declarations": [
          {
            "default": "React",
            "path": "react",
            "members": ["useState", "useEffect", "useContext", "useRef"]
          },
          {
            "default": "PropTypes",
            "path": "prop-types"
          },
          {
            "default": "classnames",
            "path": "classnames"
          }
        ]
      }
    ],
    [
      "@babel/plugin-proposal-class-properties",
      {
        "loose": true
      }
    ],
    "react-hot-loader/babel",
    [
      "@babel/plugin-transform-runtime",
      {
        "regenerator": true
      }
    ]
  ]
}
```

## 🤔 Expected Behavior

Should be able to import Electron modules from the front-end code!

## 🌍 Your Environment

<!--- Include as many relevant details about the environment you experienced the bug in -->

| Software         | Version(s) |
| ---------------- | ---------- |
| Parcel           | 2.0.0.beta-3
| Node             | 15
| npm/Yarn         | 
| Operating System | macOS

<!-- Love parcel? Please consider supporting our collective:
👉  https://opencollective.com/parcel/donate -->


Pull request:
Don't replace require in member expressions
Closes #6323

Patch:
diff --git a/Cargo.lock b/Cargo.lock
index bb4fa2ba2..ca047c56c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -536,9 +536,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
 
 [[package]]
 name = "ordered-float"
-version = "2.2.0"
+version = "2.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b50b8919aecb97e5ee9aceef27e24f39c46b11831130f4a6b7b091ec5de0de12"
+checksum = "76d99537dd7019c4dabfcf3898a43ee685412f76e6bee1ecc48785d730c1a275"
 dependencies = [
  "num-traits",
 ]
@@ -663,9 +663,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.26"
+version = "1.0.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
+checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
 dependencies = [
  "unicode-xid",
 ]
@@ -999,9 +999,9 @@ dependencies = [
 
 [[package]]
 name = "swc_common"
-version = "0.10.19"
+version = "0.10.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2061abb9f67dcef7abd6c874c72be6c90e8eca8b799fd769fd696c14af526929"
+checksum = "d02578ed17d73cb0233cf27aa6c59220a1910f5f335196dced75c9b2be2900fb"
 dependencies = [
  "ast_node",
  "atty",
@@ -1039,9 +1039,9 @@ dependencies = [
 
 [[package]]
 name = "swc_ecma_codegen"
-version = "0.55.1"
+version = "0.55.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae3084419db115abde69a07de264df672990f18990101d6c87728cc2818a493d"
+checksum = "1ee2a49373c24a7a2b5b5a4b311c89b480bec43faf68e278672d6e6d02fddfc6"
 dependencies = [
  "bitflags",
  "num-bigint",
@@ -1088,9 +1088,9 @@ dependencies = [
 
 [[package]]
 name = "swc_ecma_preset_env"
-version = "0.20.1"
+version = "0.20.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "533633147bb37f1031e395d5c362316779d61d8257fb5a941ed3c4b8622216fe"
+checksum = "397ffd052931f737aa38dbd7d8c879d2cafd19cc5f9d4b46d366a62a15fe06d0"
 dependencies = [
  "dashmap",
  "fxhash",
@@ -1134,9 +1134,9 @@ dependencies = [
 
 [[package]]
 name = "swc_ecma_transforms_base"
-version = "0.15.3"
+version = "0.15.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2e9496dd9efacb7b376caf03e94512ef07b3f8a316ae486b8650efbc9e69ead"
+checksum = "cf55207e36eaa746e474bbf57ae2ee7455626f6711d0e7c14065bfc13bc59ed5"
 dependencies = [
  "fxhash",
  "once_cell",
@@ -1153,9 +1153,9 @@ dependencies = [
 
 [[package]]
 name = "swc_ecma_transforms_compat"
-version = "0.17.3"
+version = "0.17.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c3b80fca1d79baa86acb7c4d9f40f892330c32ffb925f6aeaf3fb94e5aeca0b"
+checksum = "1994d8b1c1c0bee81844d22549b9d6c3164adfa6d7fa1a89781081238c12be11"
 dependencies = [
  "arrayvec",
  "fxhash",
@@ -1208,9 +1208,9 @@ dependencies = [
 
 [[package]]
 name = "swc_ecma_transforms_optimization"
-version = "0.20.0"
+version = "0.20.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f5ee19ef905f78b09838c781e3e57f7934cd56d9218422dc99c65098caf344c"
+checksum = "217679ab1534a43a31c2890e94266abd627ebf898955bf25e57ccca1fe5c4879"
 dependencies = [
  "dashmap",
  "fxhash",
@@ -1272,9 +1272,9 @@ dependencies = [
 
 [[package]]
 name = "swc_ecma_transforms_typescript"
-version = "0.19.1"
+version = "0.19.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1249d66b01ef36d21fddfef8c76b2ce2d7a5dcb5e8b0aae6b928059fc694910"
+checksum = "83332a6f75268a1240694e5b1ae21c91da170b1609b830cf2bb544575d255567"
 dependencies = [
  "fxhash",
  "serde",
diff --git a/packages/transformers/js/package.json b/packages/transformers/js/package.json
index eb248b1c0..27f65afd3 100644
--- a/packages/transformers/js/package.json
+++ b/packages/transformers/js/package.json
@@ -37,6 +37,7 @@
     "detect-libc": "^1.0.3",
     "micromatch": "^4.0.2",
     "nullthrows": "^1.1.1",
+    "regenerator-runtime": "^0.13.7",
     "semver": "^5.4.1"
   },
   "devDependencies": {
diff --git a/packages/transformers/js/src/dependency_collector.rs b/packages/transformers/js/src/dependency_collector.rs
index b59531ee0..efbba67e4 100644
--- a/packages/transformers/js/src/dependency_collector.rs
+++ b/packages/transformers/js/src/dependency_collector.rs
@@ -383,7 +383,7 @@ impl<'a> Fold for DependencyCollector<'a> {
   }
 
   fn fold_unary_expr(&mut self, node: ast::UnaryExpr) -> ast::UnaryExpr {
-    // Don't traverse `typeof require` further to `require` with undefined
+    // Don't traverse `typeof require` further to not replace `require` with undefined
     if let ast::UnaryExpr {
       op: ast::UnaryOp::TypeOf,
       arg,
@@ -467,6 +467,17 @@ impl<'a> Fold for DependencyCollector<'a> {
     return node.fold_children_with(self);
   }
 
+  fn fold_member_expr(&mut self, mut node: ast::MemberExpr) -> ast::MemberExpr {
+    node.obj = node.obj.fold_children_with(self);
+
+    // To ensure that fold_expr doesn't replace `require` in non-computed member expressions
+    if node.computed {
+      node.prop = node.prop.fold_children_with(self);
+    }
+
+    node
+  }
+
   fn fold_expr(&mut self, node: ast::Expr) -> ast::Expr {
     if let Some((specifier, span)) = match_import_meta_url(&node, self.decls) {
       self.add_dependency(specifier.clone(), span, DependencyKind::URL, None, false);
diff --git a/packages/transformers/js/src/env_replacer.rs b/packages/transformers/js/src/env_replacer.rs
index 083886c73..3c9e6134c 100644
--- a/packages/transformers/js/src/env_replacer.rs
+++ b/packages/transformers/js/src/env_replacer.rs
@@ -39,69 +39,75 @@ impl<'a> Fold for EnvReplacer<'a> {
       }
     }
 
-    match node {
-      Member(ref member) => {
-        if self.is_browser && match_member_expr(member, vec!["process", "browser"], self.decls) {
-          return Lit(Lit::Bool(Bool {
-            value: true,
-            span: DUMMY_SP,
-          }));
-        }
+    if let Member(ref member) = node {
+      if self.is_browser && match_member_expr(member, vec!["process", "browser"], self.decls) {
+        return Lit(Lit::Bool(Bool {
+          value: true,
+          span: DUMMY_SP,
+        }));
+      }
 
-        if !self.replace_env {
-          return node;
-        }
+      if !self.replace_env {
+        return node;
+      }
 
-        match member {
-          MemberExpr {
-            obj: Expr(ref expr),
-            ref prop,
-            computed: false,
-            ..
-          } => {
-            match &**expr {
-              Member(member) => {
-                if match_member_expr(member, vec!["process", "env"], self.decls) {
-                  match &**prop {
-                    Lit(Lit::Str(Str { value: ref sym, .. })) | Ident(Ident { ref sym, .. }) => {
-                      if let Some(val) = self.env.get(sym) {
-                        self.used_env.insert(sym.clone());
-                        return Lit(Lit::Str(ast::Str {
-                          span: DUMMY_SP,
-                          value: val.into(),
-                          has_escape: false,
-                          kind: ast::StrKind::Synthesized,
-                        }));
-                      } else {
-                        match sym as &str {
-                          // don't replace process.env.hasOwnProperty with undefined
-                          "hasOwnProperty"
-                          | "isPrototypeOf"
-                          | "propertyIsEnumerable"
-                          | "toLocaleString"
-                          | "toSource"
-                          | "toString"
-                          | "valueOf" => {}
-                          _ => {
-                            self.used_env.insert(sym.clone());
-                            return Ident(Ident::new(js_word!("undefined"), DUMMY_SP));
-                          }
-                        }
-                      }
-                    }
-                    _ => {}
-                  }
+      if let MemberExpr {
+        obj: Expr(ref expr),
+        ref prop,
+        computed,
+        ..
+      } = member
+      {
+        if let Member(member) = &**expr {
+          if match_member_expr(member, vec!["process", "env"], self.decls) {
+            if let Lit(Lit::Str(Str { value: ref sym, .. })) = &**prop {
+              if let Some(replacement) = self.replace(sym) {
+                return replacement;
+              }
+            } else if let Ident(Ident { ref sym, .. }) = &**prop {
+              if !computed {
+                if let Some(replacement) = self.replace(sym) {
+                  return replacement;
                 }
               }
-              _ => {}
             }
           }
-          _ => {}
         }
       }
-      _ => {}
     }
 
-    return swc_ecmascript::visit::fold_expr(self, node);
+    swc_ecmascript::visit::fold_expr(self, node)
+  }
+}
+
+impl<'a> EnvReplacer<'a> {
+  fn replace(&mut self, sym: &JsWord) -> Option<ast::Expr> {
+    use ast::{Expr::*, Ident, Lit};
+
+    if let Some(val) = self.env.get(sym) {
+      self.used_env.insert(sym.clone());
+      return Some(Lit(Lit::Str(ast::Str {
+        span: DUMMY_SP,
+        value: val.into(),
+        has_escape: false,
+        kind: ast::StrKind::Synthesized,
+      })));
+    } else {
+      match sym as &str {
+        // don't replace process.env.hasOwnProperty with undefined
+        "hasOwnProperty"
+        | "isPrototypeOf"
+        | "propertyIsEnumerable"
+        | "toLocaleString"
+        | "toSource"
+        | "toString"
+        | "valueOf" => {}
+        _ => {
+          self.used_env.insert(sym.clone());
+          return Some(Ident(Ident::new(js_word!("undefined"), DUMMY_SP)));
+        }
+      };
+    }
+    None
   }
 }
diff --git a/packages/transformers/js/src/hoist.rs b/packages/transformers/js/src/hoist.rs
index 9073ff661..1cfc4924b 100644
--- a/packages/transformers/js/src/hoist.rs
+++ b/packages/transformers/js/src/hoist.rs
@@ -103,6 +103,18 @@ impl<'a> Hoist<'a> {
   }
 }
 
+macro_rules! hoist_visit_fn {
+  ($name:ident, $type:ident) => {
+    fn $name(&mut self, node: $type) -> $type {
+      let in_function_scope = self.in_function_scope;
+      self.in_function_scope = true;
+      let res = node.fold_children_with(self);
+      self.in_function_scope = in_function_scope;
+      res
+    }
+  };
+}
+
 impl<'a> Fold for Hoist<'a> {
   fn fold_module(&mut self, node: Module) -> Module {
     let mut node = node;
@@ -485,21 +497,10 @@ impl<'a> Fold for Hoist<'a> {
     node
   }
 
-  fn fold_function(&mut self, node: Function) -> Function {
-    let in_function_scope = self.in_function_scope;
-    self.in_function_scope = true;
-    let res = node.fold_children_with(self);
-    self.in_function_scope = in_function_scope;
-    res
-  }
-
-  fn fold_class(&mut self, node: Class) -> Class {
-    let in_function_scope = self.in_function_scope;
-    self.in_function_scope = true;
-    let res = node.fold_children_with(self);
-    self.in_function_scope = in_function_scope;
-    res
-  }
+  hoist_visit_fn!(fold_function, Function);
+  hoist_visit_fn!(fold_class, Class);
+  hoist_visit_fn!(fold_getter_prop, GetterProp);
+  hoist_visit_fn!(fold_setter_prop, SetterProp);
 
   fn fold_expr(&mut self, node: Expr) -> Expr {
     match node {
@@ -1063,15 +1064,17 @@ impl<'a> Hoist<'a> {
   }
 }
 
-macro_rules! visit_fn {
-  ($self: ident, $node: ident) => {
-    let in_module_this = $self.in_module_this;
-    let in_function = $self.in_function;
-    $self.in_module_this = false;
-    $self.in_function = true;
-    $node.visit_children_with($self);
-    $self.in_module_this = in_module_this;
-    $self.in_function = in_function;
+macro_rules! collect_visit_fn {
+  ($name:ident, $type:ident) => {
+    fn $name(&mut self, node: &$type, _parent: &dyn Node) {
+      let in_module_this = self.in_module_this;
+      let in_function = self.in_function;
+      self.in_module_this = false;
+      self.in_function = true;
+      node.visit_children_with(self);
+      self.in_module_this = in_module_this;
+      self.in_function = in_function;
+    }
   };
 }
 
@@ -1151,13 +1154,10 @@ impl Visit for Collect {
     self.in_module_this = false;
   }
 
-  fn visit_function(&mut self, node: &Function, _parent: &dyn Node) {
-    visit_fn!(self, node);
-  }
-
-  fn visit_class(&mut self, node: &Class, _parent: &dyn Node) {
-    visit_fn!(self, node);
-  }
+  collect_visit_fn!(visit_function, Function);
+  collect_visit_fn!(visit_class, Class);
+  collect_visit_fn!(visit_getter_prop, GetterProp);
+  collect_visit_fn!(visit_setter_prop, SetterProp);
 
   fn visit_arrow_expr(&mut self, node: &ArrowExpr, _parent: &dyn Node) {
     let in_function = self.in_function;
@@ -1438,6 +1438,8 @@ impl Visit for Collect {
         }
         _ => node.visit_children_with(self),
       }
+    } else {
+      node.visit_children_with(self);
     }
   }
 
@@ -2186,6 +2188,24 @@ mod tests {
     "#,
     );
     assert_eq!(collect.should_wrap, true);
+
+    let (collect, _code, _hoist) = parse(
+      r#"
+    const foo = {
+      get a() {
+        return 1;
+      },
+      set b(v) {
+        return;
+      },
+      run() {
+        return 3;
+      },
+    };
+    console.log(foo.a);
+    "#,
+    );
+    assert_eq!(collect.should_wrap, false);
   }
 
   #[test]
diff --git a/packages/transformers/js/src/modules.rs b/packages/transformers/js/src/modules.rs
index f182c67c7..e03b7145d 100644
--- a/packages/transformers/js/src/modules.rs
+++ b/packages/transformers/js/src/modules.rs
@@ -225,6 +225,18 @@ impl ESMFold {
   }
 }
 
+macro_rules! modules_visit_fn {
+  ($name:ident, $type:ident) => {
+    fn $name(&mut self, node: $type) -> $type {
+      let in_function_scope = self.in_function_scope;
+      self.in_function_scope = true;
+      let res = node.fold_children_with(self);
+      self.in_function_scope = in_function_scope;
+      res
+    }
+  };
+}
+
 impl Fold for ESMFold {
   fn fold_module(&mut self, node: Module) -> Module {
     let mut is_esm = false;
@@ -542,21 +554,10 @@ impl Fold for ESMFold {
     node.fold_children_with(self)
   }
 
-  fn fold_function(&mut self, node: Function) -> Function {
-    let in_function_scope = self.in_function_scope;
-    self.in_function_scope = true;
-    let res = node.fold_children_with(self);
-    self.in_function_scope = in_function_scope;
-    res
-  }
-
-  fn fold_class(&mut self, node: Class) -> Class {
-    let in_function_scope = self.in_function_scope;
-    self.in_function_scope = true;
-    let res = node.fold_children_with(self);
-    self.in_function_scope = in_function_scope;
-    res
-  }
+  modules_visit_fn!(fold_function, Function);
+  modules_visit_fn!(fold_class, Class);
+  modules_visit_fn!(fold_getter_prop, GetterProp);
+  modules_visit_fn!(fold_setter_prop, SetterProp);
 
   fn fold_expr(&mut self, node: Expr) -> Expr {
     match &node {
diff --git a/yarn.lock b/yarn.lock
index 563ef7b7a..686522de1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2146,6 +2146,69 @@
   dependencies:
     "@octokit/openapi-types" "^6.2.0"
 
+"@parcel/babel-ast-utils@2.0.0-beta.2":
+  version "2.0.0-beta.2"
+  resolved "https://registry.yarnpkg.com/@parcel/babel-ast-utils/-/babel-ast-utils-2.0.0-beta.2.tgz#834fea0d71c2524d9ec46a3df1a4100513402fd6"
+  integrity sha512-2ujEqleotjlX+QBODAEAJ4V/fHSA7oYjyUsHsBstoyMQyunBuj0xqQlLFzE9buGrdZoNGDuSHoDaVo7cP2f7nQ==
+  dependencies:
+    "@babel/parser" "^7.0.0"
+    "@parcel/source-map" "2.0.0-alpha.4.21"
+    "@parcel/utils" "2.0.0-beta.2"
+    astring "^1.6.2"
+
+"@parcel/babylon-walk@2.0.0-beta.2":
+  version "2.0.0-beta.2"
+  resolved "https://registry.yarnpkg.com/@parcel/babylon-walk/-/babylon-walk-2.0.0-beta.2.tgz#c22da82161d1f548d6736b07d9aa754451ec00b1"
+  integrity sha512-bfMq8kDpzqkMT/yRYAnjVsrkuPhEDLRxiCNR4yoSje4Mcj2sMwiGyjFkSQAgGzav7O8iBa0NsL+txiF1QnmcUg==
+  dependencies:
+    "@babel/types" "^7.12.13"
+    lodash.clone "^4.5.0"
+
+"@parcel/codeframe@2.0.0-beta.2":
+  version "2.0.0-beta.2"
+  resolved "https://registry.yarnpkg.com/@parcel/codeframe/-/codeframe-2.0.0-beta.2.tgz#5a72779cd3c75be54a26db91d113e477db93c79a"
+  integrity sha512-l7/meH8amRVsDFmNJqX/cUH8O9FqPwZHcKCLi0yu1KzemKLODQCfMPJqm3JRwaAUK4oC8fULVGpN7m4wKlSQnQ==
+  dependencies:
+    chalk "^4.1.0"
+    emphasize "^4.2.0"
+    slice-ansi "^4.0.0"
+    string-width "^4.2.0"
+
+"@parcel/diagnostic@2.0.0-beta.2":
+  version "2.0.0-beta.2"
+  resolved "https://registry.yarnpkg.com/@parcel/diagnostic/-/diagnostic-2.0.0-beta.2.tgz#ecdb2d03c057d4c104aa19b8a6ee431a201d6ca3"
+  integrity sha512-6cRnWSRjzy5OPJyXl6DWAWoVfQg90chttwKd3lWDM4lpDDRq9hbpp4ADaOVAnF5rDd/B+mwwjAzxcgwJQD8u/w==
+  dependencies:
+    json-source-map "^0.6.1"
+    nullthrows "^1.1.1"
+
+"@parcel/events@2.0.0-beta.2":
+  version "2.0.0-beta.2"
+  resolved "https://registry.yarnpkg.com/@parcel/events/-/events-2.0.0-beta.2.tgz#31e73129787422fa19b70d5b1a976169d18a05b7"
+  integrity sha512-kbiFb/Qd8TavhmL84FTg3dN29Zi5Bi8bWqMgzA8hq7E8W5ezXpmw1Tu5wkjsNzHuOTj2YcAtxlTh3l29UEmh2g==
+
+"@parcel/logger@2.0.0-beta.2":
+  version "2.0.0-beta.2"
+  resolved "https://registry.yarnpkg.com/@parcel/logger/-/logger-2.0.0-beta.2.tgz#f721802b0549cc9a4a6509cc73cef7263a3f231b"
+  integrity sha512-YuTUGN47eMctdtTx0hhqKUCRCtuqqV+n6MRrm5sTlg/XpZP8ySUnq4+8VqMqslB761GgXmaDKtNIebe0lc+Erw==
+  dependencies:
+    "@parcel/diagnostic" "2.0.0-beta.2"
+    "@parcel/events" "2.0.0-beta.2"
+
+"@parcel/markdown-ansi@2.0.0-beta.2":
+  version "2.0.0-beta.2"
+  resolved "https://registry.yarnpkg.com/@parcel/markdown-ansi/-/markdown-ansi-2.0.0-beta.2.tgz#5270b64313c6bbcdd8b401ecd9e02dda9e71b465"
+  integrity sha512-5fYNvwp2PpQaBxMM3qsVjVz5W8Rrc/eZdCaWudlxhucmUxy3BLedQ1ci6bSzjG1Fl/PDgzcIbZdrqD2+Z+QppA==
+  dependencies:
+    chalk "^4.1.0"
+
+"@parcel/plugin@2.0.0-beta.2":
+  version "2.0.0-beta.2"
+  resolved "https://registry.yarnpkg.com/@parcel/plugin/-/plugin-2.0.0-beta.2.tgz#78de0725c9dfb010ccbf92fe39b1aafa960675e5"
+  integrity sha512-I89k7uc+yeSe6LrREajkvR6HnfcZzMDoz/TjnfG0W+iQYdKKaAuggf9zlQ6aOr8moGM1orcVSx5X+77u/tX0gg==
+  dependencies:
+    "@parcel/types" "2.0.0-beta.2"
+
 "@parcel/scope-hoisting@2.0.0-beta.2":
   version "2.0.0-beta.2"
   resolved "https://registry.yarnpkg.com/@parcel/scope-hoisting/-/scope-hoisting-2.0.0-beta.2.tgz#7c1d3846d0bb9d6b4d7420026c45735aa1425b5f"
@@ -2179,6 +2242,36 @@
     detect-libc "^1.0.3"
     globby "^11.0.3"
 
+"@parcel/types@2.0.0-beta.2":
+  version "2.0.0-beta.2"
+  resolved "https://registry.yarnpkg.com/@parcel/types/-/types-2.0.0-beta.2.tgz#39530f885a546ccc8759ba8b970440bb7aadc146"
+  integrity sha512-ri2BPGAFDntQbA5p3m/4QgnEqWYToUMkAtLelXSPbwnTM0KARavTAwSRqz1xwTdXa8gQyv4SSV7xURwaPaZ3GA==
+
+"@parcel/utils@2.0.0-beta.2":
+  version "2.0.0-beta.2"
+  resolved "https://registry.yarnpkg.com/@parcel/utils/-/utils-2.0.0-beta.2.tgz#705fb51f3a6e0e09b8fde86a8998f954ac7fb4d9"
+  integrity sha512-v8vFGdUY/IuuL7dvmdNxhv4TowgqYDxupToxEvMix1GePRx7QTV1ugy/uWgMXhNIytFo4qyo1fWD7VcXLMS1TQ==
+  dependencies:
+    "@iarna/toml" "^2.2.0"
+    "@parcel/codeframe" "2.0.0-beta.2"
+    "@parcel/diagnostic" "2.0.0-beta.2"
+    "@parcel/logger" "2.0.0-beta.2"
+    "@parcel/markdown-ansi" "2.0.0-beta.2"
+    "@parcel/source-map" "2.0.0-alpha.4.21"
+    ansi-html "^0.0.7"
+    chalk "^4.1.0"
+    clone "^2.1.1"
+    fast-glob "3.1.1"
+    fastest-levenshtein "^1.0.8"
+    is-glob "^4.0.0"
+    is-url "^1.2.2"
+    json5 "^1.0.1"
+    lru-cache "^6.0.0"
+    micromatch "^4.0.2"
+    node-forge "^0.10.0"
+    nullthrows "^1.1.1"
+    open "^7.0.3"
+
 "@parcel/watcher@2.0.0-alpha.10":
   version "2.0.0-alpha.10"
   resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.0.0-alpha.10.tgz#99266189f5193512dbdf6b0faca20400c519a16e"
@@ -11240,10 +11333,10 @@ regenerate@^1.2.1, regenerate@^1.4.0:
   resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
   integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
 
-regenerator-runtime@^0.13.4:
-  version "0.13.4"
-  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.4.tgz#e96bf612a3362d12bb69f7e8f74ffeab25c7ac91"
-  integrity sha512-plpwicqEzfEyTQohIKktWigcLzmNStMGwbOUbykx51/29Z3JOGYldaaNGK7ngNXV+UcoqvIMmloZ48Sr74sd+g==
+regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7:
+  version "0.13.7"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
+  integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
 
 regenerator-transform@^0.14.2:
   version "0.14.2"


Test patch:
diff --git a/packages/core/integration-tests/test/integration/env-computed-string/index.js b/packages/core/integration-tests/test/integration/env-computed-string/index.js
new file mode 100644
index 000000000..cc24ee682
--- /dev/null
+++ b/packages/core/integration-tests/test/integration/env-computed-string/index.js
@@ -0,0 +1,1 @@
+module.exports = process.env["ABC"];
diff --git a/packages/core/integration-tests/test/integration/js-require-free/index.js b/packages/core/integration-tests/test/integration/js-require-free/index.js
new file mode 100644
index 000000000..aeb7abb47
--- /dev/null
+++ b/packages/core/integration-tests/test/integration/js-require-free/index.js
@@ -0,0 +1,12 @@
+const x = {
+	require: ["a", "b"],
+};
+
+output(
+	x.require[
+		(() => {
+			let x = typeof require !== "undefined" && require;
+			return 0;
+		})()
+	]
+);
diff --git a/packages/core/integration-tests/test/javascript.js b/packages/core/integration-tests/test/javascript.js
index 12c04cea6..63164227a 100644
--- a/packages/core/integration-tests/test/javascript.js
+++ b/packages/core/integration-tests/test/javascript.js
@@ -1780,6 +1780,21 @@ describe('javascript', function() {
     assert.strictEqual(output, 'abc');
   });
 
+  it('should inline computed accesses with string literals to process.env', async function() {
+    let b = await bundle(
+      path.join(__dirname, '/integration/env-computed-string/index.js'),
+      {
+        env: {ABC: 'XYZ'},
+      },
+    );
+
+    let contents = await outputFS.readFile(b.getBundles()[0].filePath, 'utf8');
+    assert(!contents.includes('process.env'));
+
+    let output = await run(b);
+    assert.strictEqual(output, 'XYZ');
+  });
+
   it('should insert environment variables from a file', async function() {
     let b = await bundle(
       path.join(__dirname, '/integration/env-file/index.js'),
@@ -3485,6 +3500,35 @@ describe('javascript', function() {
     assert.deepEqual(res.default, 'x: 123');
   });
 
+  it('should only replace free references to require', async () => {
+    let b = await bundle(
+      path.join(__dirname, 'integration/js-require-free/index.js'),
+    );
+    let output;
+    await run(b, {
+      output(v) {
+        output = v;
+      },
+    });
+    assert.strictEqual(output, 'a');
+  });
+
+  it('should only replace free references to require with scope hoisting', async () => {
+    let b = await bundle(
+      path.join(__dirname, 'integration/js-require-free/index.js'),
+      {
+        mode: 'production',
+      },
+    );
+    let output;
+    await run(b, {
+      output(v) {
+        output = v;
+      },
+    });
+    assert.strictEqual(output, 'a');
+  });
+
   it('should support runtime module deduplication', async function() {
     let b = await bundle(
       path.join(__dirname, 'integration/js-runtime-dedup/index.js'),