Repository: netlify/zip-it-and-ship-it
Pull request #562 (2021-06-28 16:41:34)

feat: remove `experimentalHandlerV2` config property
**- Summary**

Removes the feature flag and enables the behaviour, which has been fully rolled out in the Netlify platform, by default.

**- Test plan**

Adjusted tests.

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

*Comparing with 1782d559b8179fd6e8785425f0d053470339df01*

### largeDepsEsbuild: 12.4s
 ⬆️ **19.37% increase** vs. 1782d559b8179fd6e8785425f0d053470339df01
```
^                                   13s                                                                   
│                                   ┌──┐   12.5s   12.3s                                   12.1s   12.4s  
│           12s            11.7s    |  |    ┌──┐    ┌──┐   11.6s    12s            11.6s    ┌──┐    ┌──┐  
│ ──────────┌──┐────────────┌──┐────┼──┼────┼──┼────┼──┼────┌──┐────┌──┐────────────┌──┐────┼──┼────|▒▒|──
│  10.6s    |  |   10.3s    |  |    |  |    |  |    |  |    |  |    |  |   10.3s    |  |    |  |    |▒▒|  
│   ┌──┐    |  |    ┌──┐    |  |    |  |    |  |    |  |    |  |    |  |    ┌──┐    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
└───┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴──>
    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 (1782d559b8179fd6e8785425f0d053470339df01): 9.9s
- T-29 (db05daa3366142f4dbb844397c25ace1af966123): 12.1s
- T-28 (f69dc7bb918004a5c4b06c826c2f7189be8e129e): 14.1s
- T-27 (11e3486bc4f2ecf0f7ea6dd72b40432cd5e48306): 12s
- T-26 (c7b62ca7080b6a1bbe77483fde32e9bcde326855): 10.1s
- T-25 (d7bbd41934ed22e31e1c56d64c1c98f8b1cac86f): 11.4s
- T-24 (c733b46dd3470999d2c2e51d5cfc1e38c087839a): 12.2s
- T-23 (f29156ef5395795ad40e9df9556908b58aec6ae9): 13.1s
- T-22 (459ae63da849a1e0d4a271276e0333936c058e4a): 12.6s
- T-21 (3b2bee45e41518ab4c5695de581c2e6202e533b6): 12.9s
- T-20 (3fb86ef73475a197318baf522e16966d35fc485b): 10.9s
- T-19 (f49afa12e3df4054cbc9191446b2d6f19c5deea4): 10.8s
- T-18 (baf9dfb9661d508bf052802101c5078a3ae7b6e5): 12.4s
- T-17 (4768f2fa3afe71f00b62e543291677ed130c92f8): 12.4s
- T-16 (6495b80b9e5886189c7f20a150d8c2ed6cf082b5): 10.5s
- T-15 (9e47927ca83777dd42b27f31d5feb3096d3e8ced): 10.7s
- T-14 (e2ae5ca6d1f640f13789b83e7211fc6a78116958): 10.9s
- T-13 (508721c3c2e3af2d672da86172686aa2e4e0776c): 12.5s
- T-12 (790010f035f121286c189ac88cf49e5a51de7a1b): 10.6s
- T-11 (0dfcc70a334d09523dcb127e1812d0dbbda7481b): 12s
- T-10 (c4c746323af0ffa3706c6136675aebbac2af1e3d): 10.3s
- T-9 (f1363d24abeeeb11abaed0c564ca5ae8874a70ae): 11.7s
- T-8 (a5cef00715188d477ba69f033c16de00cea768c0): 13s
- T-7 (febeffcae56016e74348c4380fd5572edcbe84d0): 12.5s
- T-6 (991d9c3ab2e4e4da188024e3e005601ce9f14896): 12.3s
- T-5 (dd7dd81e5bf63586018d0ef384c399b2c1ba21c4): 11.6s
- T-4 (d4bcaf0ab1ab6f984d4658da105936a21011fe66): 12s
- T-3 (92f64a67160ac9eb0301ae738e38d258117f2b06): 10.3s
- T-2 (06bc4f69b05c96899a1efbd953c560219291b568): 11.6s
- T-1 (6c0e5f1059d5e672ea5ee6509150e0896030e745): 12.1s
- **T (current commit): 12.4s**</details>
### largeDepsZisi: 1m 1.9s
 ⬆️ **13.24% increase** vs. 1782d559b8179fd6e8785425f0d053470339df01
```
^                                 1m 9.5s                                                                 
│                                   ┌──┐                          1m 7.1s         1m 4.4s                 
│         1m 3.9s                   |  |  1m 3.7s 1m 2.9s           ┌──┐            ┌──┐  1m 3.6s 1m 1.9s 
│ ──────────┌──┐───────────59.5s────┼──┼────┌──┐────┌──┐───59.5s────┼──┼────────────┼──┼────┌──┐────┌──┐──
│   54s     |  |   54.3s    ┌──┐    |  |    |  |    |  |    ┌──┐    |  |   54.7s    |  |    |  |    |▒▒|  
│   ┌──┐    |  |    ┌──┐    |  |    |  |    |  |    |  |    |  |    |  |    ┌──┐    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
│   |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |  |    |▒▒|  
└───┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴────┴──┴──>
    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 (1782d559b8179fd6e8785425f0d053470339df01): 53.7s
- T-29 (db05daa3366142f4dbb844397c25ace1af966123): 1m 5.6s
- T-28 (f69dc7bb918004a5c4b06c826c2f7189be8e129e): 1m 16.4s
- T-27 (11e3486bc4f2ecf0f7ea6dd72b40432cd5e48306): 1m 2.9s
- T-26 (c7b62ca7080b6a1bbe77483fde32e9bcde326855): 53.4s
- T-25 (d7bbd41934ed22e31e1c56d64c1c98f8b1cac86f): 59.9s
- T-24 (c733b46dd3470999d2c2e51d5cfc1e38c087839a): 1m 3.5s
- T-23 (f29156ef5395795ad40e9df9556908b58aec6ae9): 1m 11.6s
- T-22 (459ae63da849a1e0d4a271276e0333936c058e4a): 1m 4.5s
- T-21 (3b2bee45e41518ab4c5695de581c2e6202e533b6): 1m 6.6s
- T-20 (3fb86ef73475a197318baf522e16966d35fc485b): 55.7s
- T-19 (f49afa12e3df4054cbc9191446b2d6f19c5deea4): 54.8s
- T-18 (baf9dfb9661d508bf052802101c5078a3ae7b6e5): 1m 4.8s
- T-17 (4768f2fa3afe71f00b62e543291677ed130c92f8): 1m 4.7s
- T-16 (6495b80b9e5886189c7f20a150d8c2ed6cf082b5): 54.5s
- T-15 (9e47927ca83777dd42b27f31d5feb3096d3e8ced): 54.6s
- T-14 (e2ae5ca6d1f640f13789b83e7211fc6a78116958): 55.4s
- T-13 (508721c3c2e3af2d672da86172686aa2e4e0776c): 1m 3.1s
- T-12 (790010f035f121286c189ac88cf49e5a51de7a1b): 54s
- T-11 (0dfcc70a334d09523dcb127e1812d0dbbda7481b): 1m 3.9s
- T-10 (c4c746323af0ffa3706c6136675aebbac2af1e3d): 54.3s
- T-9 (f1363d24abeeeb11abaed0c564ca5ae8874a70ae): 59.5s
- T-8 (a5cef00715188d477ba69f033c16de00cea768c0): 1m 9.5s
- T-7 (febeffcae56016e74348c4380fd5572edcbe84d0): 1m 3.7s
- T-6 (991d9c3ab2e4e4da188024e3e005601ce9f14896): 1m 2.9s
- T-5 (dd7dd81e5bf63586018d0ef384c399b2c1ba21c4): 59.5s
- T-4 (d4bcaf0ab1ab6f984d4658da105936a21011fe66): 1m 7.1s
- T-3 (92f64a67160ac9eb0301ae738e38d258117f2b06): 54.7s
- T-2 (06bc4f69b05c96899a1efbd953c560219291b568): 1m 4.4s
- T-1 (6c0e5f1059d5e672ea5ee6509150e0896030e745): 1m 3.6s
- **T (current commit): 1m 1.9s**</details>
<!--delta:benchmark@{}-->

Patch:
diff --git a/src/runtimes/node/zip_esbuild.js b/src/runtimes/node/zip_esbuild.js
index 263d739..9639f58 100644
--- a/src/runtimes/node/zip_esbuild.js
+++ b/src/runtimes/node/zip_esbuild.js
@@ -95,7 +95,6 @@ const zipEsbuild = async ({
       archiveFormat,
       basePath: functionBasePath,
       destFolder,
-      experimentalHandlerV2: config.experimentalHandlerV2,
       extension,
       filename,
       mainFile: normalizedMainFile,
diff --git a/src/runtimes/node/zip_zisi.js b/src/runtimes/node/zip_zisi.js
index 5af0bd4..b38fc29 100644
--- a/src/runtimes/node/zip_zisi.js
+++ b/src/runtimes/node/zip_zisi.js
@@ -36,7 +36,6 @@ const zipZisi = async ({
     basePath: getBasePath(dirnames),
     destFolder,
     extension,
-    experimentalHandlerV2: config.experimentalHandlerV2,
     filename,
     mainFile,
     pluginsModulesPath,
diff --git a/src/zip_node.js b/src/zip_node.js
index e5023f6..337ace4 100644
--- a/src/zip_node.js
+++ b/src/zip_node.js
@@ -74,7 +74,6 @@ const createZipArchive = async function ({
   basePath,
   destFolder,
   extension,
-  experimentalHandlerV2,
   filename,
   mainFile,
   pluginsModulesPath,
@@ -85,16 +84,9 @@ const createZipArchive = async function ({
   const entryFilename = `${basename(filename, extension)}.js`
   const entryFilePath = resolve(basePath, entryFilename)
 
-  // Traditionally, everything other than the entry file was placed inside a
-  // `src` sub-directory. We want to change this behavior, but we're doing so
-  // gradually. For now, we keep injecting that sub-directory unless there is
-  // a `experimentalHandlerV2` configuration property set to `true`, in which
-  // case we place all files at the root.
-  const needsUserNamespace = experimentalHandlerV2 !== true
-
   // We don't need an entry file if it would end up with the same path as the
   // function's main file.
-  const needsEntryFile = needsUserNamespace || entryFilePath !== mainFile
+  const needsEntryFile = entryFilePath !== mainFile
 
   // There is a naming conflict with the entry file if one of the supporting
   // files (i.e. not the main file) has the path that the entry file needs to
@@ -103,7 +95,7 @@ const createZipArchive = async function ({
 
   // If there is a naming conflict, we move all user files (everything other
   // than the entry file) to its own sub-directory.
-  const userNamespace = needsUserNamespace || hasEntryFileConflict ? DEFAULT_USER_SUBDIRECTORY : ''
+  const userNamespace = hasEntryFileConflict ? DEFAULT_USER_SUBDIRECTORY : ''
 
   if (needsEntryFile) {
     const entryFile = getEntryFile({ commonPrefix: basePath, filename, mainFile, userNamespace })


Test patch:
diff --git a/tests/main.js b/tests/main.js
index 289a235..02c5465 100644
--- a/tests/main.js
+++ b/tests/main.js
@@ -84,14 +84,14 @@ testBundlers(
     const { files, tmpDir } = await zipNode(t, fixtureDir, {
       opts: { config: { '*': { nodeBundler: bundler } } },
     })
-    const requires = await getRequires({ filePath: resolve(tmpDir, 'src/function.js') })
+    const requires = await getRequires({ filePath: resolve(tmpDir, 'function.js') })
     const normalizedRequires = new Set(requires.map(unixify))
     const modulePath = resolve(FIXTURES_DIR, `${fixtureDir}/node_modules/test`)
 
     t.is(files.length, 1)
     t.is(files[0].runtime, 'js')
-    t.true(await pathExists(`${tmpDir}/src/node_modules/test/native.node`))
-    t.true(await pathExists(`${tmpDir}/src/node_modules/test/side-file.js`))
+    t.true(await pathExists(`${tmpDir}/node_modules/test/native.node`))
+    t.true(await pathExists(`${tmpDir}/node_modules/test/side-file.js`))
     t.true(normalizedRequires.has('test'))
 
     // We can only detect native modules when using esbuild.
@@ -115,14 +115,14 @@ testBundlers(
     const { files, tmpDir } = await zipNode(t, fixtureDir, {
       opts: { config: { '*': { nodeBundler: bundler } } },
     })
-    const requires = await getRequires({ filePath: resolve(tmpDir, 'src/function.js') })
+    const requires = await getRequires({ filePath: resolve(tmpDir, 'function.js') })
     const normalizedRequires = new Set(requires.map(unixify))
     const modulePath = resolve(FIXTURES_DIR, `${fixtureDir}/node_modules/test`)
 
     t.is(files.length, 1)
     t.is(files[0].runtime, 'js')
-    t.true(await pathExists(`${tmpDir}/src/node_modules/test/native.node`))
-    t.true(await pathExists(`${tmpDir}/src/node_modules/test/side-file.js`))
+    t.true(await pathExists(`${tmpDir}/node_modules/test/native.node`))
+    t.true(await pathExists(`${tmpDir}/node_modules/test/side-file.js`))
     t.true(normalizedRequires.has('test'))
 
     // We can only detect native modules when using esbuild.
@@ -151,7 +151,7 @@ testBundlers('Can require dynamically generated node modules', [ESBUILD, ESBUILD
 testBundlers('Ignore some excluded node modules', [ESBUILD, ESBUILD_ZISI, DEFAULT], async (bundler, t) => {
   const { tmpDir } = await zipNode(t, 'node-module-excluded', { opts: { config: { '*': { nodeBundler: bundler } } } })
 
-  t.false(await pathExists(`${tmpDir}/src/node_modules/aws-sdk`))
+  t.false(await pathExists(`${tmpDir}/node_modules/aws-sdk`))
 
   try {
     // eslint-disable-next-line import/no-dynamic-require, node/global-require
@@ -169,7 +169,7 @@ testBundlers('Ignore TypeScript types', [ESBUILD, ESBUILD_ZISI, DEFAULT], async
   const { tmpDir } = await zipNode(t, 'node-module-typescript-types', {
     opts: { config: { '*': { nodeBundler: bundler } } },
   })
-  t.false(await pathExists(`${tmpDir}/src/node_modules/@types/node`))
+  t.false(await pathExists(`${tmpDir}/node_modules/@types/node`))
 })
 
 testBundlers('Throws on runtime errors', [ESBUILD, ESBUILD_ZISI, DEFAULT], async (bundler, t) => {
@@ -405,7 +405,7 @@ testBundlers(
     const { tmpDir } = await zipNode(t, 'ignore-dir-node-modules', {
       opts: { config: { '*': { nodeBundler: bundler } } },
     })
-    t.false(await pathExists(`${tmpDir}/src/node_modules`))
+    t.false(await pathExists(`${tmpDir}/node_modules`))
   },
 )
 
@@ -416,7 +416,7 @@ testBundlers(
     const { tmpDir } = await zipNode(t, 'ignore-deep-dir-node-modules', {
       opts: { config: { '*': { nodeBundler: bundler } } },
     })
-    t.false(await pathExists(`${tmpDir}/src/deep/node_modules`))
+    t.false(await pathExists(`${tmpDir}/deep/node_modules`))
   },
 )
 
@@ -471,7 +471,7 @@ testBundlers('Ignore directories without a main file', [ESBUILD, ESBUILD_ZISI, D
 
 testBundlers('Remove useless files', [ESBUILD, ESBUILD_ZISI, DEFAULT], async (bundler, t) => {
   const { tmpDir } = await zipNode(t, 'useless', { opts: { config: { '*': { nodeBundler: bundler } } } })
-  t.false(await pathExists(`${tmpDir}/src/Desktop.ini`))
+  t.false(await pathExists(`${tmpDir}/Desktop.ini`))
 })
 
 testBundlers('Works on empty directories', [ESBUILD, ESBUILD_ZISI, DEFAULT], async (bundler, t) => {
@@ -583,8 +583,8 @@ testBundlers('Zips node modules', [DEFAULT], async (bundler, t) => {
 testBundlers('Include most files from node modules', [DEFAULT], async (bundler, t) => {
   const { tmpDir } = await zipNode(t, 'node-module-included', { opts: { config: { '*': { nodeBundler: bundler } } } })
   const [mapExists, htmlExists] = await Promise.all([
-    pathExists(`${tmpDir}/src/node_modules/test/test.map`),
-    pathExists(`${tmpDir}/src/node_modules/test/test.html`),
+    pathExists(`${tmpDir}/node_modules/test/test.map`),
+    pathExists(`${tmpDir}/node_modules/test/test.html`),
   ])
   t.false(mapExists)
   t.true(htmlExists)
@@ -599,10 +599,10 @@ testBundlers('Includes specific Next.js dependencies when using next-on-netlify'
     opts: { config: { '*': { nodeBundler: bundler } } },
   })
   const [constantsExists, semverExists, otherExists, indexExists] = await Promise.all([
-    pathExists(`${tmpDir}/src/node_modules/next/dist/next-server/lib/constants.js`),
-    pathExists(`${tmpDir}/src/node_modules/next/dist/compiled/semver.js`),
-    pathExists(`${tmpDir}/src/node_modules/next/dist/other.js`),
-    pathExists(`${tmpDir}/src/node_modules/next/index.js`),
+    pathExists(`${tmpDir}/node_modules/next/dist/next-server/lib/constants.js`),
+    pathExists(`${tmpDir}/node_modules/next/dist/compiled/semver.js`),
+    pathExists(`${tmpDir}/node_modules/next/dist/other.js`),
+    pathExists(`${tmpDir}/node_modules/next/index.js`),
   ])
   t.true(constantsExists)
   t.true(semverExists)
@@ -613,10 +613,10 @@ testBundlers('Includes specific Next.js dependencies when using next-on-netlify'
 testBundlers('Includes all Next.js dependencies when not using next-on-netlify', [DEFAULT], async (bundler, t) => {
   const { tmpDir } = await zipNode(t, 'node-module-next', { opts: { config: { '*': { nodeBundler: bundler } } } })
   const [constantsExists, semverExists, otherExists, indexExists] = await Promise.all([
-    pathExists(`${tmpDir}/src/node_modules/next/dist/next-server/lib/constants.js`),
-    pathExists(`${tmpDir}/src/node_modules/next/dist/compiled/semver.js`),
-    pathExists(`${tmpDir}/src/node_modules/next/dist/other.js`),
-    pathExists(`${tmpDir}/src/node_modules/next/index.js`),
+    pathExists(`${tmpDir}/node_modules/next/dist/next-server/lib/constants.js`),
+    pathExists(`${tmpDir}/node_modules/next/dist/compiled/semver.js`),
+    pathExists(`${tmpDir}/node_modules/next/dist/other.js`),
+    pathExists(`${tmpDir}/node_modules/next/index.js`),
   ])
   t.true(constantsExists)
   t.true(semverExists)
@@ -631,7 +631,7 @@ testBundlers('Inlines node modules in the bundle', [ESBUILD, ESBUILD_ZISI], asyn
   const requires = await getRequires({ filePath: resolve(tmpDir, 'function.js') })
 
   t.false(requires.includes('test'))
-  t.false(await pathExists(`${tmpDir}/src/node_modules/test`))
+  t.false(await pathExists(`${tmpDir}/node_modules/test`))
 })
 
 testBundlers(
@@ -650,7 +650,7 @@ testBundlers(
     const requires = await getRequires({ filePath: resolve(tmpDir, 'function.js') })
 
     t.true(requires.includes('test'))
-    t.true(await pathExists(`${tmpDir}/src/node_modules/test`))
+    t.true(await pathExists(`${tmpDir}/node_modules/test`))
   },
 )
 
@@ -670,7 +670,7 @@ testBundlers(
     const requires = await getRequires({ filePath: resolve(tmpDir, 'function.js') })
 
     t.true(requires.includes('test'))
-    t.false(await pathExists(`${tmpDir}/src/node_modules/test`))
+    t.false(await pathExists(`${tmpDir}/node_modules/test`))
   },
 )
 
@@ -688,8 +688,8 @@ testBundlers(
       opts: { config },
     })
     const [mapExists, htmlExists] = await Promise.all([
-      pathExists(`${tmpDir}/src/node_modules/test/test.map`),
-      pathExists(`${tmpDir}/src/node_modules/test/test.html`),
+      pathExists(`${tmpDir}/node_modules/test/test.map`),
+      pathExists(`${tmpDir}/node_modules/test/test.html`),
     ])
     t.false(mapExists)
     t.true(htmlExists)
@@ -710,7 +710,7 @@ testBundlers(
       opts: { config },
     })
 
-    t.false(await pathExists(`${tmpDir}/src/node_modules/i-do-not-exist`))
+    t.false(await pathExists(`${tmpDir}/node_modules/i-do-not-exist`))
   },
 )
 
@@ -918,9 +918,9 @@ testBundlers(
 
     const { files, tmpDir } = await zipNode(t, 'config-apply-1', { length: 3, opts: { config } })
     const requires = await Promise.all([
-      getRequires({ filePath: resolve(tmpDir, 'src/another_function.js') }),
-      getRequires({ filePath: resolve(tmpDir, 'src/function_two.js') }),
-      getRequires({ filePath: resolve(tmpDir, 'src/function_one.js') }),
+      getRequires({ filePath: resolve(tmpDir, 'another_function.js') }),
+      getRequires({ filePath: resolve(tmpDir, 'function_two.js') }),
+      getRequires({ filePath: resolve(tmpDir, 'function_one.js') }),
     ])
 
     t.deepEqual(requires[0], ['test-1'])
@@ -957,9 +957,9 @@ testBundlers(
 
     const { files, tmpDir } = await zipNode(t, 'config-apply-1', { length: 3, opts: { config } })
     const requires = await Promise.all([
-      getRequires({ filePath: resolve(tmpDir, 'src/another_function.js') }),
-      getRequires({ filePath: resolve(tmpDir, 'src/function_two.js') }),
-      getRequires({ filePath: resolve(tmpDir, 'src/function_one.js') }),
+      getRequires({ filePath: resolve(tmpDir, 'another_function.js') }),
+      getRequires({ filePath: resolve(tmpDir, 'function_two.js') }),
+      getRequires({ filePath: resolve(tmpDir, 'function_one.js') }),
     ])
 
     t.deepEqual(requires[0], externalNodeModules)
@@ -1020,9 +1020,9 @@ testBundlers(
     t.true(body2.includes("I must've called a thousand times"))
     t.true(body3.includes('Uh-oh'))
 
-    t.true(await pathExists(`${tmpDir}/src/content/post1.md`))
-    t.true(await pathExists(`${tmpDir}/src/content/post2.md`))
-    t.false(await pathExists(`${tmpDir}/src/content/post3.md`))
+    t.true(await pathExists(`${tmpDir}/content/post1.md`))
+    t.true(await pathExists(`${tmpDir}/content/post2.md`))
+    t.false(await pathExists(`${tmpDir}/content/post3.md`))
   },
 )
 
@@ -1079,7 +1079,7 @@ testBundlers(
 )
 
 testBundlers(
-  'Places all user-defined files at the root of the target directory if the `experimentalHandlerV2` configuration property is defined',
+  'Places all user-defined files at the root of the target directory',
   [ESBUILD, ESBUILD_ZISI, DEFAULT],
   async (bundler, t) => {
     const fixtureName = 'base_path'
@@ -1088,7 +1088,6 @@ testBundlers(
         basePath: join(FIXTURES_DIR, fixtureName),
         config: {
           '*': {
-            experimentalHandlerV2: true,
             includedFiles: ['content/*'],
             nodeBundler: bundler,
           },
@@ -1112,7 +1111,7 @@ testBundlers(
 )
 
 testBundlers(
-  'Places all user-defined files in a `src/` sub-directory if there is a naming conflict with the entry file, even if the `experimentalHandlerV2` configuration property is defined',
+  'Places all user-defined files in a `src/` sub-directory if there is a naming conflict with the entry file',
   [ESBUILD, ESBUILD_ZISI, DEFAULT],
   async (bundler, t) => {
     const fixtureName = 'base_path'
@@ -1121,7 +1120,6 @@ testBundlers(
         basePath: join(FIXTURES_DIR, fixtureName),
         config: {
           '*': {
-            experimentalHandlerV2: true,
             includedFiles: ['content/*', 'func2.js'],
             nodeBundler: bundler,
           },
@@ -1145,36 +1143,6 @@ testBundlers(
   },
 )
 
-testBundlers(
-  'Places all user-defined files in a `src/` sub-directory if the `experimentalHandlerV2` configuration property is not defined',
-  [ESBUILD, ESBUILD_ZISI, DEFAULT],
-  async (bundler, t) => {
-    const fixtureName = 'base_path'
-    const { tmpDir } = await zipNode(t, `${fixtureName}/netlify/functions2`, {
-      opts: {
-        basePath: join(FIXTURES_DIR, fixtureName),
-        config: {
-          '*': {
-            includedFiles: ['content/*'],
-            nodeBundler: bundler,
-          },
-        },
-      },
-    })
-
-    // eslint-disable-next-line import/no-dynamic-require, node/global-require
-    const function2Entry = require(`${tmpDir}/func2.js`)
-
-    t.true(unixify(function2Entry[0]).includes('/src/'))
-    t.false(await pathExists(`${tmpDir}/content/post1.md`))
-    t.false(await pathExists(`${tmpDir}/content/post2.md`))
-    t.false(await pathExists(`${tmpDir}/content/post3.md`))
-    t.true(await pathExists(`${tmpDir}/src/content/post1.md`))
-    t.true(await pathExists(`${tmpDir}/src/content/post2.md`))
-    t.true(await pathExists(`${tmpDir}/src/content/post3.md`))
-  },
-)
-
 test('When generating a directory for a function with `archiveFormat: "none"`, it empties the directory before copying any files', async (t) => {
   const { path: tmpDir } = await getTmpDir({ prefix: 'zip-it-test' })
   const functionDirectory = join(tmpDir, 'function')
@@ -1241,7 +1209,7 @@ test('Leaves dynamic imports untouched when the `processDynamicNodeImports` conf
   const { tmpDir } = await zipNode(t, fixtureName, {
     opts: { basePath: join(FIXTURES_DIR, fixtureName), config: { '*': { nodeBundler: ESBUILD } } },
   })
-  const functionSource = await pReadFile(`${tmpDir}/src/function.js`, 'utf8')
+  const functionSource = await pReadFile(`${tmpDir}/function.js`, 'utf8')
 
   /* eslint-disable no-template-curly-in-string */
   t.true(functionSource.includes('const require1 = require(`./files/${number}.js`);'))
@@ -1281,7 +1249,7 @@ test('Leaves dynamic imports untouched when the files required to resolve the ex
       config: { '*': { nodeBundler: ESBUILD, processDynamicNodeImports: true } },
     },
   })
-  const functionSource = await pReadFile(`${tmpDir}/src/function.js`, 'utf8')
+  const functionSource = await pReadFile(`${tmpDir}/function.js`, 'utf8')
 
   t.true(functionSource.includes('const require1 = require(number)'))
   // eslint-disable-next-line no-template-curly-in-string
@@ -1351,7 +1319,7 @@ test('Creates dynamic import shims for functions with the same name and same shi
 
 test('Uses the default Node bundler if no configuration object is supplied', async (t) => {
   const { files, tmpDir } = await zipNode(t, 'local-node-module')
-  const requires = await getRequires({ filePath: resolve(tmpDir, 'src/function.js') })
+  const requires = await getRequires({ filePath: resolve(tmpDir, 'function.js') })
 
   t.deepEqual(requires, ['test'])
   t.is(files[0].bundler, 'zisi')
@@ -1400,9 +1368,9 @@ test('Does not generate a sourcemap unless `nodeSourcemap` is set', async (t) =>
     opts: { config: { '*': { nodeBundler: ESBUILD } } },
   })
 
-  t.false(await pathExists(`${tmpDir}/src/function.js.map`))
+  t.false(await pathExists(`${tmpDir}/function.js.map`))
 
-  const functionSource = await pReadFile(`${tmpDir}/src/function.js`, 'utf8')
+  const functionSource = await pReadFile(`${tmpDir}/function.js`, 'utf8')
 
   t.false(functionSource.includes('sourceMappingURL'))
 })
@@ -1412,7 +1380,7 @@ if (platform !== 'win32') {
     const { tmpDir } = await zipNode(t, 'node-module-and-local-imports', {
       opts: { config: { '*': { nodeBundler: ESBUILD, nodeSourcemap: true } } },
     })
-    const sourcemap = await pReadFile(`${tmpDir}/src/function.js.map`, 'utf8')
+    const sourcemap = await pReadFile(`${tmpDir}/function.js.map`, 'utf8')
     const { sourceRoot, sources } = JSON.parse(sourcemap)
 
     await Promise.all(