Repository: netlify/zip-it-and-ship-it
Pull request #546 (2021-06-23 09:30:03)

feat: add more expressions to dynamic import parser
**- Summary**

Adds support for more expression types when parsing dynamic import expressions.

**- Test plan**

Adjusted existing tests. Also added a new test which asserts that we leave alone any imports whose expressions we can't convert at build time.

github-actions[bot]: ## ⏱ Benchmark results

*Comparing with 459ae63da849a1e0d4a271276e0333936c058e4a*

### largeDepsEsbuild: 12.3s
 ⬇️ **1.98% decrease** vs. 459ae63da849a1e0d4a271276e0333936c058e4a
```
^                                                          12.7s                                          
│   12s                    12.1s            12s             ┌──┐                            12s    12.3s  
│   ┌──┐           11.6s    ┌──┐   11.4s    ┌──┐   11.5s    |  |                            ┌──┐    ┌──┐  
│   |  |            ┌──┐    |  |    ┌──┐    |  |    ┌──┐    |  |                            |  |    |▒▒|  
│   |  |   10.3s    |  |    |  |    |  |    |  |    |  |    |  |    9.9s    9.9s    10s     |  |    |▒▒|  
│   |  |    ┌──┐    |  |    |  |    |  |    |  |    |  |    |  |    ┌──┐    ┌──┐    ┌──┐    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
└───┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴──>
    T-12    T-11    T-10    T-9     T-8     T-7     T-6     T-5     T-4     T-3     T-2     T-1      T    
```
<details>
<summary>Legend</summary>

- T-30 (459ae63da849a1e0d4a271276e0333936c058e4a): 12.6s
- T-29 (3b2bee45e41518ab4c5695de581c2e6202e533b6): 12.9s
- T-28 (3fb86ef73475a197318baf522e16966d35fc485b): 10.9s
- T-27 (f49afa12e3df4054cbc9191446b2d6f19c5deea4): 10.8s
- T-26 (baf9dfb9661d508bf052802101c5078a3ae7b6e5): 12.4s
- T-25 (4768f2fa3afe71f00b62e543291677ed130c92f8): 12.4s
- T-24 (6495b80b9e5886189c7f20a150d8c2ed6cf082b5): 10.5s
- T-23 (9e47927ca83777dd42b27f31d5feb3096d3e8ced): 10.7s
- T-22 (e2ae5ca6d1f640f13789b83e7211fc6a78116958): 10.9s
- T-21 (508721c3c2e3af2d672da86172686aa2e4e0776c): 12.5s
- T-20 (790010f035f121286c189ac88cf49e5a51de7a1b): 10.6s
- T-19 (0dfcc70a334d09523dcb127e1812d0dbbda7481b): 12s
- T-18 (c4c746323af0ffa3706c6136675aebbac2af1e3d): 10.3s
- T-17 (f1363d24abeeeb11abaed0c564ca5ae8874a70ae): 11.7s
- T-16 (a5cef00715188d477ba69f033c16de00cea768c0): 13s
- T-15 (febeffcae56016e74348c4380fd5572edcbe84d0): 12.5s
- T-14 (991d9c3ab2e4e4da188024e3e005601ce9f14896): 12.3s
- T-13 (dd7dd81e5bf63586018d0ef384c399b2c1ba21c4): 11.6s
- T-12 (d4bcaf0ab1ab6f984d4658da105936a21011fe66): 12s
- T-11 (92f64a67160ac9eb0301ae738e38d258117f2b06): 10.3s
- T-10 (06bc4f69b05c96899a1efbd953c560219291b568): 11.6s
- T-9 (6c0e5f1059d5e672ea5ee6509150e0896030e745): 12.1s
- T-8 (e4c22192f1f66aae395b00fe8eaf4c886781d723): 11.4s
- T-7 (3ba92859e8fbf0f20abc46912284575c24e18124): 12s
- T-6 (5cdd4d23e88300d026f0152222136a35849c3b7f): 11.5s
- T-5 (df7f3e92e9547649a4c7c0b25d6e317af292c089): 12.7s
- T-4 (08f2a5d49a78e4424bc7478aa3cc8c98d21c5ee7): 9.9s
- T-3 (1e5ba0b8519f8ab643496979d7304d68d749d31e): 9.9s
- T-2 (1507586389e536db74867e3e8d3a7145373adfd3): 10s
- T-1 (6f4ab2998291fc3dd9dfa2d48d38be4d5ab8a901): 12s
- **T (current commit): 12.3s**</details>
### largeDepsZisi: 1m 2.5s
 ⬇️ **3.32% decrease** vs. 459ae63da849a1e0d4a271276e0333936c058e4a
```
^ 1m 7.1s                                                 1m 6.3s                         1m 5.4s         
│   ┌──┐          1m 4.4s 1m 3.6s         1m 2.7s 1m 2.4s   ┌──┐                            ┌──┐  1m 2.5s 
│   |  |            ┌──┐    ┌──┐   59.3s    ┌──┐    ┌──┐    |  |                            |  |    ┌──┐  
│   |  |            |  |    |  |    ┌──┐    |  |    |  |    |  |                            |  |    |▒▒|  
│   |  |   54.7s    |  |    |  |    |  |    |  |    |  |    |  |   52.2s   52.8s   54.8s    |  |    |▒▒|  
│   |  |    ┌──┐    |  |    |  |    |  |    |  |    |  |    |  |    ┌──┐    ┌──┐    ┌──┐    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
└───┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴──>
    T-12    T-11    T-10    T-9     T-8     T-7     T-6     T-5     T-4     T-3     T-2     T-1      T    
```
<details>
<summary>Legend</summary>

- T-30 (459ae63da849a1e0d4a271276e0333936c058e4a): 1m 4.5s
- T-29 (3b2bee45e41518ab4c5695de581c2e6202e533b6): 1m 6.6s
- T-28 (3fb86ef73475a197318baf522e16966d35fc485b): 55.7s
- T-27 (f49afa12e3df4054cbc9191446b2d6f19c5deea4): 54.8s
- T-26 (baf9dfb9661d508bf052802101c5078a3ae7b6e5): 1m 4.8s
- T-25 (4768f2fa3afe71f00b62e543291677ed130c92f8): 1m 4.7s
- T-24 (6495b80b9e5886189c7f20a150d8c2ed6cf082b5): 54.5s
- T-23 (9e47927ca83777dd42b27f31d5feb3096d3e8ced): 54.6s
- T-22 (e2ae5ca6d1f640f13789b83e7211fc6a78116958): 55.4s
- T-21 (508721c3c2e3af2d672da86172686aa2e4e0776c): 1m 3.1s
- T-20 (790010f035f121286c189ac88cf49e5a51de7a1b): 54s
- T-19 (0dfcc70a334d09523dcb127e1812d0dbbda7481b): 1m 3.9s
- T-18 (c4c746323af0ffa3706c6136675aebbac2af1e3d): 54.3s
- T-17 (f1363d24abeeeb11abaed0c564ca5ae8874a70ae): 59.5s
- T-16 (a5cef00715188d477ba69f033c16de00cea768c0): 1m 9.5s
- T-15 (febeffcae56016e74348c4380fd5572edcbe84d0): 1m 3.7s
- T-14 (991d9c3ab2e4e4da188024e3e005601ce9f14896): 1m 2.9s
- T-13 (dd7dd81e5bf63586018d0ef384c399b2c1ba21c4): 59.5s
- T-12 (d4bcaf0ab1ab6f984d4658da105936a21011fe66): 1m 7.1s
- T-11 (92f64a67160ac9eb0301ae738e38d258117f2b06): 54.7s
- T-10 (06bc4f69b05c96899a1efbd953c560219291b568): 1m 4.4s
- T-9 (6c0e5f1059d5e672ea5ee6509150e0896030e745): 1m 3.6s
- T-8 (e4c22192f1f66aae395b00fe8eaf4c886781d723): 59.3s
- T-7 (3ba92859e8fbf0f20abc46912284575c24e18124): 1m 2.7s
- T-6 (5cdd4d23e88300d026f0152222136a35849c3b7f): 1m 2.4s
- T-5 (df7f3e92e9547649a4c7c0b25d6e317af292c089): 1m 6.3s
- T-4 (08f2a5d49a78e4424bc7478aa3cc8c98d21c5ee7): 52.2s
- T-3 (1e5ba0b8519f8ab643496979d7304d68d749d31e): 52.8s
- T-2 (1507586389e536db74867e3e8d3a7145373adfd3): 54.8s
- T-1 (6f4ab2998291fc3dd9dfa2d48d38be4d5ab8a901): 1m 5.4s
- **T (current commit): 1m 2.5s**</details>
<!--delta:benchmark@{}-->

Patch:
diff --git a/src/runtimes/node/dynamic_imports/parser.js b/src/runtimes/node/dynamic_imports/parser.js
index fc44875..d710bcb 100644
--- a/src/runtimes/node/dynamic_imports/parser.js
+++ b/src/runtimes/node/dynamic_imports/parser.js
@@ -26,21 +26,50 @@ const getAbsoluteGlob = ({ basePath, globNodes, resolveDir }) => {
   return absoluteGlob
 }
 
+// Returns GLOB_WILDCARD for AST nodes that are accepted as part of a dynamic
+// expression and convertable to a wildcard character. This determines whether
+// we convert an expression or leave it alone. For example:
+//
+// - `./files/${someVariable}`: Convert `someVariable` to `*`
+// - `./files/${[some, array]}`: Don't convert expression
+//
+// The following AST nodes are converted to a wildcard:
+//
+// - CallExpression: `someFunction()`
+// - ConditionalExpression: `someCond ? someValue : otherValue`
+// - Identifier: `someVariable`
+// - MemberExpression: `someArray[index]` or `someObject.property`
+const getWildcardFromASTNode = (node) => {
+  switch (node.type) {
+    case 'CallExpression':
+    case 'ConditionalExpression':
+    case 'Identifier':
+    case 'MemberExpression':
+      return GLOB_WILDCARD
+
+    default:
+      throw new Error('Expression member not supported')
+  }
+}
+
 // Tries to parse an expression, returning an object with:
 // - `includedPathsGlob`: A glob with the files to be included in the bundle
 // - `type`: The expression type (e.g. "require", "import")
-const parseExpression = ({ basePath, expression, resolveDir }) => {
-  const { body } = acorn.parse(expression, { ecmaVersion: ECMA_VERSION })
-  const { callee = {} } = body[0].expression
+const parseExpression = ({ basePath, expression: rawExpression, resolveDir }) => {
+  const { body } = acorn.parse(rawExpression, { ecmaVersion: ECMA_VERSION })
+  const [topLevelExpression] = body
+  const { expression } = topLevelExpression
 
-  if (callee.name === 'require') {
-    const includedPathsGlob = parseRequire({ basePath, expression: body[0].expression, resolveDir })
+  if (expression.type === 'CallExpression' && expression.callee.name === 'require') {
+    try {
+      const includedPathsGlob = parseRequire({ basePath, expression, resolveDir })
 
-    if (includedPathsGlob) {
       return {
         includedPathsGlob,
-        type: callee.name,
+        type: expression.callee.name,
       }
+    } catch (_) {
+      // no-op
     }
   }
 }
@@ -84,15 +113,11 @@ const parseBinaryExpression = (expression) => {
       case 'BinaryExpression':
         return parseBinaryExpression(operand)
 
-      case 'CallExpression':
-      case 'Identifier':
-        return GLOB_WILDCARD
-
       case 'Literal':
         return operand.value
 
       default:
-        throw new Error('Expression member not supported')
+        return getWildcardFromASTNode(operand)
     }
   })
 
@@ -107,21 +132,17 @@ const parseBinaryExpression = (expression) => {
 const parseTemplateLiteral = (expression) => {
   const { expressions, quasis } = expression
   const parts = [...expressions, ...quasis].sort((partA, partB) => partA.start - partB.start)
-  const globNodes = parts.map(({ type, value }) => {
-    switch (type) {
+  const globNodes = parts.map((part) => {
+    switch (part.type) {
       case 'TemplateElement':
-        return value.cooked
-
-      case 'CallExpression':
-      case 'Identifier':
-        return GLOB_WILDCARD
+        return part.value.cooked
 
       default:
-        return null
+        return getWildcardFromASTNode(part)
     }
   })
 
-  return globNodes.every(Boolean) ? globNodes : null
+  return globNodes.filter(Boolean)
 }
 
 // For our purposes, we consider a glob to be valid if all the nodes are


Test patch:
diff --git a/tests/fixtures/node-module-dynamic-import-template-literal/function.js b/tests/fixtures/node-module-dynamic-import-template-literal/function.js
new file mode 100644
index 0000000..41fa369
--- /dev/null
+++ b/tests/fixtures/node-module-dynamic-import-template-literal/function.js
@@ -0,0 +1,1 @@
+module.exports = require('@org/test')
diff --git a/tests/fixtures/node-module-dynamic-import-template-literal/node_modules/@org/test/files/one.js b/tests/fixtures/node-module-dynamic-import-template-literal/node_modules/@org/test/files/one.js
new file mode 100644
index 0000000..ef06e80
--- /dev/null
+++ b/tests/fixtures/node-module-dynamic-import-template-literal/node_modules/@org/test/files/one.js
@@ -0,0 +1,1 @@
+module.exports = true
\ No newline at end of file
diff --git a/tests/fixtures/node-module-dynamic-import-template-literal/node_modules/@org/test/index.js b/tests/fixtures/node-module-dynamic-import-template-literal/node_modules/@org/test/index.js
new file mode 100644
index 0000000..846f148
--- /dev/null
+++ b/tests/fixtures/node-module-dynamic-import-template-literal/node_modules/@org/test/index.js
@@ -0,0 +1,13 @@
+module.exports = (number) => {
+  const parent = {
+    child: number
+  }
+  const arr = [number]
+  const require1 = require(`./files/${number}.js`)
+  const require2 = require(`./files/${number}`)
+  const require3 = require(`./files/${parent.child}`)
+  const require4 = require(`./files/${arr[0]}`)
+  const require5 = require(`./files/${number.length > 0 ? number : 'uh-oh'}`)
+
+  return [require1, require2, require3, require4, require5]
+}
diff --git a/tests/fixtures/node-module-dynamic-import-template-literal/node_modules/@org/test/package.json b/tests/fixtures/node-module-dynamic-import-template-literal/node_modules/@org/test/package.json
new file mode 100644
index 0000000..0383048
--- /dev/null
+++ b/tests/fixtures/node-module-dynamic-import-template-literal/node_modules/@org/test/package.json
@@ -0,0 +1,4 @@
+{
+  "name": "@org/test",
+  "version": "1.0.0"
+}
diff --git a/tests/fixtures/node-module-dynamic-import-template-literal/package.json b/tests/fixtures/node-module-dynamic-import-template-literal/package.json
new file mode 100644
index 0000000..93ab46c
--- /dev/null
+++ b/tests/fixtures/node-module-dynamic-import-template-literal/package.json
@@ -0,0 +1,7 @@
+{
+  "name": "node-module-dynamic-import-template-literal",
+  "version": "1.0.0",
+  "dependencies": {
+    "@org/test": "1.0.0"
+  }
+}
diff --git a/tests/fixtures/node-module-dynamic-import-unresolvable/function.js b/tests/fixtures/node-module-dynamic-import-unresolvable/function.js
new file mode 100644
index 0000000..41fa369
--- /dev/null
+++ b/tests/fixtures/node-module-dynamic-import-unresolvable/function.js
@@ -0,0 +1,1 @@
+module.exports = require('@org/test')
diff --git a/tests/fixtures/node-module-dynamic-import-unresolvable/node_modules/@org/test/files/one.js b/tests/fixtures/node-module-dynamic-import-unresolvable/node_modules/@org/test/files/one.js
new file mode 100644
index 0000000..ef06e80
--- /dev/null
+++ b/tests/fixtures/node-module-dynamic-import-unresolvable/node_modules/@org/test/files/one.js
@@ -0,0 +1,1 @@
+module.exports = true
\ No newline at end of file
diff --git a/tests/fixtures/node-module-dynamic-import-unresolvable/node_modules/@org/test/index.js b/tests/fixtures/node-module-dynamic-import-unresolvable/node_modules/@org/test/index.js
new file mode 100644
index 0000000..ea3b5fc
--- /dev/null
+++ b/tests/fixtures/node-module-dynamic-import-unresolvable/node_modules/@org/test/index.js
@@ -0,0 +1,7 @@
+module.exports = (number) => {
+  const require1 = require(number)
+  const require2 = require(`${number}.json`)
+  const require3 = require(foo(number))
+
+  return [require1, require2, require3]
+}
diff --git a/tests/fixtures/node-module-dynamic-import-unresolvable/node_modules/@org/test/package.json b/tests/fixtures/node-module-dynamic-import-unresolvable/node_modules/@org/test/package.json
new file mode 100644
index 0000000..0383048
--- /dev/null
+++ b/tests/fixtures/node-module-dynamic-import-unresolvable/node_modules/@org/test/package.json
@@ -0,0 +1,4 @@
+{
+  "name": "@org/test",
+  "version": "1.0.0"
+}
diff --git a/tests/fixtures/node-module-dynamic-import-unresolvable/package.json b/tests/fixtures/node-module-dynamic-import-unresolvable/package.json
new file mode 100644
index 0000000..93ab46c
--- /dev/null
+++ b/tests/fixtures/node-module-dynamic-import-unresolvable/package.json
@@ -0,0 +1,7 @@
+{
+  "name": "node-module-dynamic-import-template-literal",
+  "version": "1.0.0",
+  "dependencies": {
+    "@org/test": "1.0.0"
+  }
+}
diff --git a/tests/fixtures/node-module-dynamic-import/node_modules/@org/test/index.js b/tests/fixtures/node-module-dynamic-import/node_modules/@org/test/index.js
index 62c9432..08b5108 100644
--- a/tests/fixtures/node-module-dynamic-import/node_modules/@org/test/index.js
+++ b/tests/fixtures/node-module-dynamic-import/node_modules/@org/test/index.js
@@ -2,7 +2,7 @@ const test2 = require('test-two')
 
 module.exports = (number) => {
   try {
-    test2()
+    test2(number)
   } catch (_) {}
 
   const file = require(`./files/${number}.json`)
diff --git a/tests/fixtures/node-module-dynamic-import/node_modules/test-two/index.js b/tests/fixtures/node-module-dynamic-import/node_modules/test-two/index.js
index 4e07ac5..6722dc9 100644
--- a/tests/fixtures/node-module-dynamic-import/node_modules/test-two/index.js
+++ b/tests/fixtures/node-module-dynamic-import/node_modules/test-two/index.js
@@ -1,5 +1,4 @@
-module.exports = () => {
-  const number = 'one'
+module.exports = (number) => {
   const file = require.resolve(`./files/${number}.json`)
 
   return require(file)
diff --git a/tests/main.js b/tests/main.js
index 0f61250..5e9e77c 100644
--- a/tests/main.js
+++ b/tests/main.js
@@ -1237,19 +1237,34 @@ test('Returns an empty list of modules with dynamic imports if the modules are m
 })
 
 test('Adds a runtime shim and includes the files needed for dynamic imports using a template literal', async (t) => {
-  const fixtureName = 'node-module-dynamic-import'
+  const fixtureName = 'node-module-dynamic-import-template-literal'
   const { files, tmpDir } = await zipNode(t, fixtureName, {
     opts: { basePath: join(FIXTURES_DIR, fixtureName), config: { '*': { nodeBundler: ESBUILD } } },
   })
 
   // eslint-disable-next-line import/no-dynamic-require, node/global-require
   const func = require(`${tmpDir}/function.js`)
+  const values = func('one')
+  const expectedLength = 5
 
-  t.true(func('one'))
+  // eslint-disable-next-line unicorn/new-for-builtins
+  t.deepEqual(values, Array(expectedLength).fill(true))
   t.throws(() => func('two'))
-  t.is(files[0].nodeModulesWithDynamicImports.length, 2)
+  t.is(files[0].nodeModulesWithDynamicImports.length, 1)
   t.true(files[0].nodeModulesWithDynamicImports.includes('@org/test'))
-  t.true(files[0].nodeModulesWithDynamicImports.includes('test-two'))
+})
+
+test('Leaves dynamic imports untouched when the files required to resolve the expression cannot be packaged at build time', async (t) => {
+  const fixtureName = 'node-module-dynamic-import-unresolvable'
+  const { tmpDir } = await zipNode(t, fixtureName, {
+    opts: { basePath: join(FIXTURES_DIR, fixtureName), config: { '*': { nodeBundler: ESBUILD } } },
+  })
+  const functionSource = await pReadFile(`${tmpDir}/src/function.js`, 'utf8')
+
+  t.true(functionSource.includes('const require1 = require(number)'))
+  // eslint-disable-next-line no-template-curly-in-string
+  t.true(functionSource.includes('const require2 = require(`${number}.json`);'))
+  t.true(functionSource.includes('const require3 = require(foo(number));'))
 })
 
 test('Adds a runtime shim and includes the files needed for dynamic imports using an expression built with the `+` operator', async (t) => {