Repository: codesandbox/codesandbox-client (language: javascript)

Issue:
SyntaxError expected Expression, got '<'
# 🐛 bug report

## Description of the problem

![Screenshot from 2021-05-25 13-22-06](https://user-images.githubusercontent.com/1069456/119497061-67283680-bd64-11eb-9462-2aea031b927f.png)

see also: https://github.com/codesandbox/codesandbox-client/issues/1513

### Link to sandbox: [https://codesandbox.io/s/thirsty-hooks-v8tfs?file=/src/App.vue]()

### Your Environment

| Software         | Name/Version |
| ---------------- | ------------ |
| Сodesandbox      |      currently online version        |
| Browser          |     Firefox  88         |
| Operating System |    Ubuntu 20.04         |



Discussion / hints:

Fix patch:
diff --git a/packages/app/package.json b/packages/app/package.json
index ea2488bca66..f1409442c68 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -92,7 +92,7 @@
     "apollo-boost": "^0.4.4",
     "apollo-link-batch-http": "^1.2.12",
     "apollo-link-context": "^1.0.18",
-    "astring": "^1.4.3",
+    "astring": "^1.7.4",
     "axios": "^0.19.0",
     "babel-code-frame": "^6.26.0",
     "babel-macros": "^2.0.0",
diff --git a/packages/app/src/sandbox/eval/transpilers/babel/ast/collect-dependencies.ts b/packages/app/src/sandbox/eval/transpilers/babel/ast/collect-dependencies.ts
new file mode 100644
index 00000000000..e40dd5f738e
--- /dev/null
+++ b/packages/app/src/sandbox/eval/transpilers/babel/ast/collect-dependencies.ts
@@ -0,0 +1,30 @@
+import { walk } from 'estree-walker';
+import { ESTreeAST } from './utils';
+
+interface Dependency {
+  type: string;
+  path: string;
+  isGlob?: boolean;
+}
+
+export function collectDependencies(ast: ESTreeAST): Array<Dependency> {
+  const deps: Array<Dependency> = [];
+  walk(ast.program, {
+    enter(node) {
+      // @ts-ignore
+      if (node.type === 'CallExpression' && node.callee.name === 'require') {
+        // @ts-ignore
+        if (node.arguments.length && node.arguments[0].value) {
+          deps.push({
+            type: 'direct',
+            // @ts-ignore
+            path: node.arguments[0].value,
+          });
+        }
+
+        this.skip();
+      }
+    },
+  });
+  return deps;
+}
diff --git a/packages/app/src/sandbox/eval/transpilers/babel/convert-esmodule/generator-jsx.ts b/packages/app/src/sandbox/eval/transpilers/babel/ast/generator-jsx.ts
similarity index 100%
rename from packages/app/src/sandbox/eval/transpilers/babel/convert-esmodule/generator-jsx.ts
rename to packages/app/src/sandbox/eval/transpilers/babel/ast/generator-jsx.ts
diff --git a/packages/app/src/sandbox/eval/transpilers/babel/convert-esmodule/generator.ts b/packages/app/src/sandbox/eval/transpilers/babel/ast/generator.ts
similarity index 95%
rename from packages/app/src/sandbox/eval/transpilers/babel/convert-esmodule/generator.ts
rename to packages/app/src/sandbox/eval/transpilers/babel/ast/generator.ts
index 331e5d2e58d..11a8268bc14 100644
--- a/packages/app/src/sandbox/eval/transpilers/babel/convert-esmodule/generator.ts
+++ b/packages/app/src/sandbox/eval/transpilers/babel/ast/generator.ts
@@ -40,7 +40,8 @@ const EXPRESSIONS_PRECEDENCE = {
  * Add support for next syntax
  */
 export const customGenerator = {
-  ...astring.baseGenerator,
+  // @ts-ignore baseGenerator is deprecated, and GENERATOR is not in the types?
+  ...astring.GENERATOR,
   FieldDefinition(
     node: meriyah.ESTree.FieldDefinition,
     state: { write(s: string): void }
diff --git a/packages/app/src/sandbox/eval/transpilers/babel/ast/utils.ts b/packages/app/src/sandbox/eval/transpilers/babel/ast/utils.ts
new file mode 100644
index 00000000000..4f13d6a9c27
--- /dev/null
+++ b/packages/app/src/sandbox/eval/transpilers/babel/ast/utils.ts
@@ -0,0 +1,27 @@
+import * as meriyah from 'meriyah';
+import * as astring from 'astring';
+import { customGenerator } from './generator';
+
+export interface ESTreeAST {
+  isDirty: boolean;
+  program: meriyah.ESTree.Program;
+}
+
+export function parseModule(code: string): ESTreeAST {
+  return {
+    isDirty: false,
+    program: meriyah.parseModule(code, {
+      next: true,
+      raw: true,
+      jsx: true,
+    }),
+  };
+}
+
+export function generateCode(ast: ESTreeAST) {
+  const finalCode = astring.generate(ast.program as any, {
+    generator: customGenerator,
+  });
+
+  return `"use strict";\n${finalCode}`;
+}
diff --git a/packages/app/src/sandbox/eval/transpilers/babel/check.ts b/packages/app/src/sandbox/eval/transpilers/babel/check.ts
index 03d5b18c387..c8f70057dfc 100644
--- a/packages/app/src/sandbox/eval/transpilers/babel/check.ts
+++ b/packages/app/src/sandbox/eval/transpilers/babel/check.ts
@@ -2,9 +2,5 @@ import { getSyntaxInfoFromCode } from './syntax-info';
 
 export function shouldTranspile(code: string, path: string) {
   const syntaxInformation = getSyntaxInfoFromCode(code, path);
-  if (syntaxInformation.esm) {
-    return true;
-  }
-
-  return syntaxInformation.jsx;
+  return syntaxInformation.esm || syntaxInformation.jsx;
 }
diff --git a/packages/app/src/sandbox/eval/transpilers/babel/convert-esmodule/index.ts b/packages/app/src/sandbox/eval/transpilers/babel/convert-esmodule/index.ts
index 9cd63b9bce2..eb9e0b0a809 100644
--- a/packages/app/src/sandbox/eval/transpilers/babel/convert-esmodule/index.ts
+++ b/packages/app/src/sandbox/eval/transpilers/babel/convert-esmodule/index.ts
@@ -1,7 +1,6 @@
 // This code is written to be performant, that's why we opted to ignore these linting issues
 /* eslint-disable no-loop-func, no-continue */
 import * as meriyah from 'meriyah';
-import * as astring from 'astring';
 import * as escope from 'escope';
 import { basename } from 'path';
 import { walk } from 'estree-walker';
@@ -22,14 +21,16 @@ import {
   generateInteropRequireExpression,
   generateExportGetter,
 } from './utils';
-import { customGenerator } from './generator';
+import { ESTreeAST } from '../ast/utils';
 
+// TODO: Don't generate or parse in this method... we can re-use the ast...
 /**
  * Converts esmodule code to commonjs code, built to be as fast as possible
  */
-export function convertEsModule(
-  code: string
-): { code: string; ast: meriyah.ESTree.Program } {
+export function convertEsModule(ast: ESTreeAST) {
+  const program = ast.program;
+  ast.isDirty = true;
+
   const usedVarNames = {};
   const varsToRename = {};
   const trackedExports = {};
@@ -47,12 +48,6 @@ export function convertEsModule(
     return usedName;
   };
 
-  let program = meriyah.parseModule(code, {
-    next: true,
-    raw: true,
-    jsx: true,
-  });
-
   let i = 0;
   let importOffset = 0;
 
@@ -145,8 +140,8 @@ export function convertEsModule(
   // If there is a declaration of `exports` (`var exports = []`), we need to rename this
   // variable as it's a reserved keyword
   let exportsDefined = false;
-  // @ts-ignore
-  program = walk(program, {
+
+  walk(program, {
     enter(node, parent) {
       if (node.type === n.VariableDeclaration) {
         // We don't rename exports vars in functions, only on root level
@@ -560,8 +555,7 @@ export function convertEsModule(
   ) {
     // Convert all the object shorthands to not shorthands, needed later when we rename variables so we
     // don't change to the key literals
-    // @ts-ignore
-    program = walk(program, {
+    walk(program, {
       enter(node, parent, prop, index) {
         if (node.type === n.Property) {
           const property = node as Property;
@@ -617,9 +611,4 @@ export function convertEsModule(
   }
 
   addExportVoids();
-  const finalCode = astring.generate(program as any, {
-    generator: customGenerator,
-  });
-
-  return { code: `"use strict";\n${finalCode}`, ast: program };
 }
diff --git a/packages/app/src/sandbox/eval/transpilers/babel/index.ts b/packages/app/src/sandbox/eval/transpilers/babel/index.ts
index 97d13f0eefb..e3c70711000 100644
--- a/packages/app/src/sandbox/eval/transpilers/babel/index.ts
+++ b/packages/app/src/sandbox/eval/transpilers/babel/index.ts
@@ -7,13 +7,13 @@ import BabelWorker from 'worker-loader?publicPath=/&name=babel-transpiler.[hash:
 
 import delay from '@codesandbox/common/lib/utils/delay';
 import { endMeasure, measure } from '@codesandbox/common/lib/utils/metrics';
-import { Program } from 'meriyah/dist/estree';
 import { LoaderContext, Manager } from 'sandpack-core';
 import WorkerTranspiler from '../worker-transpiler';
 import getBabelConfig from './babel-parser';
 import { convertEsModule } from './convert-esmodule';
-import regexGetRequireStatements from './worker/simple-get-require-statements';
-import { getSyntaxInfoFromAst, getSyntaxInfoFromCode } from './syntax-info';
+import { getSyntaxInfoFromAst } from './syntax-info';
+import { ESTreeAST, generateCode, parseModule } from './ast/utils';
+import { collectDependencies } from './ast/collect-dependencies';
 
 const global = window as any;
 const WORKER_COUNT = process.env.SANDPACK ? 1 : 3;
@@ -52,8 +52,6 @@ class BabelTranspiler extends WorkerTranspiler {
   ): Promise<{ transpiledCode: string }> {
     return new Promise((resolve, reject) => {
       const { path } = loaderContext;
-      let newCode = code;
-
       const isNodeModule = path.startsWith('/node_modules');
 
       /**
@@ -62,60 +60,50 @@ class BabelTranspiler extends WorkerTranspiler {
        * would then break the code (because it expects `this` to be global). No transpiler
        * can fix this, and because of this we need to just specifically ignore this file.
        */
-      const shouldIgnore = path === '/node_modules/babel-standalone/babel.js';
-
-      if (shouldIgnore) {
+      if (path === '/node_modules/babel-standalone/babel.js') {
         resolve({ transpiledCode: code });
         return;
       }
 
-      let convertedToEsmodule = false;
-      let ast: Program | undefined;
-      if (isESModule(newCode) && isNodeModule) {
+      // Check if we can take a shortcut, we have a custom pipeline for transforming
+      // node_modules to commonjs and collecting deps
+      if (loaderContext.options.simpleRequire || isNodeModule) {
         try {
-          measure(`esconvert-${path}`);
-          const esModuleInfo = convertEsModule(newCode);
-          newCode = esModuleInfo.code;
-          endMeasure(`esconvert-${path}`, { silent: true });
-          ast = esModuleInfo.ast;
-          convertedToEsmodule = true;
-        } catch (e) {
-          console.warn(
-            `Error when converting '${path}' esmodule to commonjs: ${e.message}`
-          );
-        }
-      }
+          const ast: ESTreeAST = parseModule(code);
+          if (isESModule(code)) {
+            measure(`esconvert-${path}`);
+            convertEsModule(ast);
+            endMeasure(`esconvert-${path}`, { silent: true });
+          }
 
-      const syntaxInfo = ast
-        ? getSyntaxInfoFromAst(ast)
-        : getSyntaxInfoFromCode(newCode, path);
-      try {
-        // When we find a node_module that already is commonjs we will just get the
-        // dependencies from the file and return the same code. We get the dependencies
-        // with a regex since commonjs modules just have `require` and regex is MUCH
-        // faster than generating an AST from the code.
-        if (
-          (loaderContext.options.simpleRequire || isNodeModule) &&
-          !syntaxInfo.jsx &&
-          !(!convertedToEsmodule && syntaxInfo.esm)
-        ) {
-          regexGetRequireStatements(newCode).forEach(dependency => {
-            if (dependency.isGlob) {
-              loaderContext.addDependenciesInDirectory(dependency.path);
-            } else {
-              loaderContext.addDependency(dependency.path);
-            }
-          });
+          const syntaxInfo = getSyntaxInfoFromAst(ast);
+          // If the code is commonjs and does not contain any more jsx, we generate and return the code.
+          if (!syntaxInfo.jsx && !syntaxInfo.esm) {
+            measure(`dep-collection-${path}`);
+            collectDependencies(ast).forEach(dependency => {
+              if (dependency.isGlob) {
+                loaderContext.addDependenciesInDirectory(dependency.path);
+              } else {
+                loaderContext.addDependency(dependency.path);
+              }
+            });
+            endMeasure(`dep-collection-${path}`, { silent: true });
+
+            resolve({
+              transpiledCode: ast.isDirty ? generateCode(ast) : code,
+            });
+            return;
+          }
 
-          resolve({
-            transpiledCode: newCode,
-          });
-          return;
+          // TODO: Sourcemaps?
+          // eslint-disable-next-line no-param-reassign
+          code = ast.isDirty ? generateCode(ast) : code;
+        } catch (err) {
+          console.warn(
+            `Error occurred while trying to quickly transform '${path}'`
+          );
+          console.warn(err);
         }
-      } catch (e) {
-        console.warn(
-          `Error when reading dependencies of '${path}' using quick method: '${e.message}'`
-        );
       }
 
       const configs = loaderContext.options.configurations;
@@ -150,7 +138,7 @@ class BabelTranspiler extends WorkerTranspiler {
 
       this.queueTask(
         {
-          code: newCode,
+          code,
           config: babelConfig,
           path,
           loaderOptions,
diff --git a/packages/app/src/sandbox/eval/transpilers/babel/syntax-info.ts b/packages/app/src/sandbox/eval/transpilers/babel/syntax-info.ts
index c49382fef06..2a46a076543 100644
--- a/packages/app/src/sandbox/eval/transpilers/babel/syntax-info.ts
+++ b/packages/app/src/sandbox/eval/transpilers/babel/syntax-info.ts
@@ -1,16 +1,16 @@
 import { walk } from 'estree-walker';
-import { Program } from 'meriyah/dist/estree';
 import isESModule from 'sandbox/eval/utils/is-es-module';
 import { Syntax as n } from './convert-esmodule/syntax';
+import { ESTreeAST } from './ast/utils';
 
 export interface SyntaxInfo {
   jsx: boolean;
   esm: boolean;
 }
 
-export function getSyntaxInfoFromAst(program: Program): SyntaxInfo {
+export function getSyntaxInfoFromAst(ast: ESTreeAST): SyntaxInfo {
   const syntaxInfo: SyntaxInfo = { jsx: false, esm: false };
-  walk(program, {
+  walk(ast.program, {
     enter(node) {
       const esmTypes: string[] = [
         n.ImportDeclaration,
diff --git a/packages/app/src/sandbox/eval/transpilers/babel/worker/dynamic-download.ts b/packages/app/src/sandbox/eval/transpilers/babel/worker/dynamic-download.ts
index c073018cafb..9b4cb52b2fb 100644
--- a/packages/app/src/sandbox/eval/transpilers/babel/worker/dynamic-download.ts
+++ b/packages/app/src/sandbox/eval/transpilers/babel/worker/dynamic-download.ts
@@ -3,6 +3,7 @@ import { getGlobal } from '@codesandbox/common/lib/utils/global';
 import getRequireStatements from './simple-get-require-statements';
 import { packageFilter } from '../../../utils/resolve-utils';
 import { convertEsModule } from '../convert-esmodule';
+import { generateCode, parseModule } from '../ast/utils';
 
 const global = getGlobal();
 const path = global.BrowserFS.BFSRequire('path');
@@ -177,7 +178,9 @@ export async function downloadPath(
 
   let code = r.code;
   try {
-    code = convertEsModule(r.code).code;
+    const ast = parseModule(r.code);
+    convertEsModule(ast);
+    code = generateCode(ast);
   } catch (e) {
     console.warn(e);
   }
diff --git a/packages/app/src/sandbox/eval/transpilers/babel/worker/simple-get-require-statements.ts b/packages/app/src/sandbox/eval/transpilers/babel/worker/simple-get-require-statements.ts
index 5ba6da4f883..b9d4abc5508 100644
--- a/packages/app/src/sandbox/eval/transpilers/babel/worker/simple-get-require-statements.ts
+++ b/packages/app/src/sandbox/eval/transpilers/babel/worker/simple-get-require-statements.ts
@@ -1,6 +1,6 @@
-const lineRegex = /require\s*\(['|"|`]([^"|'|`]*)['|"|`]\)|require\s*\((.*)\)/g;
-const partRegex = /require\s*\(['|"|`]([^"|'|`]*)['|"|`]\)|require\s*\((.*)\)/;
-const commentRegex = /^(\s*\/?\*)|(\/\/)/;
+const REQUIRE_LINE_RE = /require\s*\(\s*['|"|`]([^\s]*)['|"|`]\s*\)/g;
+const REQUIRE_RE = /require\s*\(\s*['|"|`]([^\s]*)['|"|`]\s*\)/;
+const COMMENT_RE = /^(\s*\/?\*)|(\/\/)/;
 
 /**
  * This is the regex version of getting all require statements, it makes the assumption
@@ -10,7 +10,7 @@ export default function getRequireStatements(code: string) {
   const results = [];
   code.split('\n').forEach(line => {
     const commentMatch =
-      line.indexOf('/*#__PURE__*/') === -1 && commentRegex.exec(line);
+      line.indexOf('/*#__PURE__*/') === -1 && COMMENT_RE.exec(line);
 
     if (commentMatch && commentMatch.index === 0) {
       return;
@@ -20,11 +20,11 @@ export default function getRequireStatements(code: string) {
       throw new Error('Glob require is part of statement');
     }
 
-    const matches = line.match(lineRegex);
+    const matches = line.match(REQUIRE_LINE_RE);
 
     if (matches) {
       matches.forEach(codePart => {
-        const match = codePart.match(partRegex);
+        const match = codePart.match(REQUIRE_RE);
 
         if (match) {
           if (commentMatch && line.indexOf(codePart) > commentMatch.index) {
diff --git a/packages/sandpack-core/src/transpiled-module/transpiled-module.ts b/packages/sandpack-core/src/transpiled-module/transpiled-module.ts
index d6270cb6772..88f4eaf7837 100644
--- a/packages/sandpack-core/src/transpiled-module/transpiled-module.ts
+++ b/packages/sandpack-core/src/transpiled-module/transpiled-module.ts
@@ -796,7 +796,11 @@ export class TranspiledModule {
         return {};
       }
 
-      if (this.module.path.startsWith('/node_modules')) {
+      // TODO: Never return untranspiled modules, as these can always have side-effects...
+      if (
+        this.module.path.startsWith('/node_modules') &&
+        !this.module.path.endsWith('.vue')
+      ) {
         if (process.env.NODE_ENV === 'development') {
           console.warn(
             `[WARN] Sandpack: loading an untranspiled module: ${this.module.path}`
@@ -826,7 +830,7 @@ export class TranspiledModule {
         // this state is to just hard reload everything.
         manager.clearCache();
 
-        throw new Error(`${this.module.path} hasn't been transpiled yet.`);
+        throw new Error(`${this.getId()} hasn't been transpiled yet.`);
       }
     }
 
diff --git a/packages/vue3-transpiler/src/index.ts b/packages/vue3-transpiler/src/index.ts
index d6e289b1cbc..d9a0b5206eb 100644
--- a/packages/vue3-transpiler/src/index.ts
+++ b/packages/vue3-transpiler/src/index.ts
@@ -145,7 +145,7 @@ export default function loader(
       query
     )}`;
     templateRequest = stringifyRequest(importers + '!' + src);
-    templateImport = `import { ${renderFnName} } from ${templateRequest}`;
+    templateImport = `import { ${renderFnName} } from ${templateRequest};`;
   }
 
   // styles
diff --git a/packages/vue3-transpiler/src/templateLoader.ts b/packages/vue3-transpiler/src/templateLoader.ts
index 99c78b255fe..5afc2893cae 100644
--- a/packages/vue3-transpiler/src/templateLoader.ts
+++ b/packages/vue3-transpiler/src/templateLoader.ts
@@ -1,15 +1,17 @@
 import qs from 'querystring';
 import { LoaderContext } from 'sandpack-core';
 import loaderUtils from 'sandpack-core/lib/transpiler/utils/loader-utils';
-import { VueLoaderOptions } from './';
-import { formatError } from './formatError';
 import { compileTemplate, TemplateCompiler } from 'vue3-browser-compiler';
 import { WarningStructure } from 'sandpack-core/lib/transpiler/utils/worker-warning-handler';
 
+import { VueLoaderOptions } from './index';
+import { formatError } from './formatError';
+
 // Loader that compiles raw template into JavaScript functions.
 // This is injected by the global pitcher (../pitch) for template
 // selection requests initiated from vue files.
-const TemplateLoader = function(source: string, loaderContext: LoaderContext) {
+function TemplateLoader(source: string, loaderContext: LoaderContext) {
+  // eslint-disable-next-line no-param-reassign
   source = String(source);
   const inMap = undefined;
 
@@ -19,8 +21,6 @@ const TemplateLoader = function(source: string, loaderContext: LoaderContext) {
   const options = (loaderUtils.getOptions(loaderContext) ||
     {}) as VueLoaderOptions;
 
-  // const isServer = loaderContext.target === 'node'
-  // const isProduction = options.productionMode || loaderContext.minimize || process.env.NODE_ENV === 'production'
   const query = qs.parse(loaderContext.resourceQuery.slice(1));
   const scopeId = query.scoped ? `data-v-${query.id}` : null;
 
@@ -82,6 +82,6 @@ const TemplateLoader = function(source: string, loaderContext: LoaderContext) {
   const { code, map } = compiled;
   // loaderContext.callback(null, code, map);
   return { transpiledCode: code, sourceMap: map };
-};
+}
 
 export default TemplateLoader;
diff --git a/yarn.lock b/yarn.lock
index c96a54532f4..4879d0a2914 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6987,10 +6987,10 @@ astral-regex@^1.0.0:
   resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
   integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==
 
-astring@^1.4.3:
-  version "1.4.3"
-  resolved "https://registry.yarnpkg.com/astring/-/astring-1.4.3.tgz#b99d4b0349bc7b28934bb9f03f86ec34d69c3a09"
-  integrity sha512-yJlJU/bmN820vL+cbWShu2YQU87dBP5V7BH2N4wODapRv27A2dZtUD0LgjP9lZENvPe9XRoSyWx+pZR6qKqNBw==
+astring@^1.7.4:
+  version "1.7.4"
+  resolved "https://registry.yarnpkg.com/astring/-/astring-1.7.4.tgz#06aa7f72ad30097210dee1ae8f7d9615cd3b57d4"
+  integrity sha512-WiVqDJV0AayUUH65FfUrbnBO4KD10854cyU49lK30+2n/lEkJDRqBKj/2fYGhZSD3uIt1H1VfW/pQtO07kR2Xg==
 
 async-each@^1.0.0, async-each@^1.0.1:
   version "1.0.3"


Test patch:
diff --git a/packages/app/src/sandbox/eval/transpilers/babel/ast/collect-dependencies.test.ts b/packages/app/src/sandbox/eval/transpilers/babel/ast/collect-dependencies.test.ts
new file mode 100644
index 00000000000..a4b3f425d9d
--- /dev/null
+++ b/packages/app/src/sandbox/eval/transpilers/babel/ast/collect-dependencies.test.ts
@@ -0,0 +1,93 @@
+import { parseModule } from './utils';
+import { collectDependencies } from './collect-dependencies';
+
+describe('simple-get-require-statements', () => {
+  it('finds a simple require statement', () => {
+    const code = `require('test')`;
+
+    expect(collectDependencies(parseModule(code))).toStrictEqual([
+      { type: 'direct', path: 'test' },
+    ]);
+  });
+
+  it('finds multiple require statement', () => {
+    const code = `require('test');
+    require('test2')`;
+
+    expect(collectDependencies(parseModule(code))).toStrictEqual([
+      { type: 'direct', path: 'test' },
+      { type: 'direct', path: 'test2' },
+    ]);
+  });
+
+  it('ignores commented require statement', () => {
+    const code = `require('test');
+    // require('test2')`;
+
+    expect(collectDependencies(parseModule(code))).toStrictEqual([
+      { type: 'direct', path: 'test' },
+    ]);
+  });
+
+  it("doesn't ignore pure markers", () => {
+    const code = `  /*#__PURE__*/ require('@emotion/stylis')`;
+
+    expect(collectDependencies(parseModule(code))).toStrictEqual([
+      { type: 'direct', path: '@emotion/stylis' },
+    ]);
+  });
+
+  it('allow comments in require statement', () => {
+    const code = `  /*#__PURE__*/ require(/*TYPE=ESM*/ '@emotion/stylis')`;
+
+    expect(collectDependencies(parseModule(code))).toStrictEqual([
+      { type: 'direct', path: '@emotion/stylis' },
+    ]);
+  });
+
+  it('allows comment after require statement', () => {
+    const code = `require('test');
+    require('test2') // yes very nice`;
+
+    expect(collectDependencies(parseModule(code))).toStrictEqual([
+      { type: 'direct', path: 'test' },
+      { type: 'direct', path: 'test2' },
+    ]);
+  });
+
+  it('ignores second comment after require statement', () => {
+    const code = `require('test');
+    require('test2') // yes very nice require('nice')`;
+
+    expect(collectDependencies(parseModule(code))).toStrictEqual([
+      { type: 'direct', path: 'test' },
+      { type: 'direct', path: 'test2' },
+    ]);
+  });
+
+  it('ignores dependencies with no quotes', () => {
+    const code = `require(test);`;
+
+    expect(collectDependencies(parseModule(code))).toStrictEqual([]);
+  });
+
+  it('handles a * that looks like a comment', () => {
+    const code = `$export($export.S + $export.F * !require('./_iter-detect')(function (iter) { Array.from(iter); }), 'Array', {})`;
+
+    expect(collectDependencies(parseModule(code))).toStrictEqual([
+      { type: 'direct', path: './_iter-detect' },
+    ]);
+  });
+
+  it('handles quotes in a require statement', () => {
+    const code = `var $csb__Textareavue = require("!babel-loader!vue-template-loader!vue-loader?vue&type=template&id=d8507872&bindings={\\"modelValue\\":\\"props\\",\\"autoResize\\":\\"props\\",\\"resize\\":\\"options\\",\\"onInput\\":\\"options\\",\\"filled\\":\\"options\\"}!./Textarea.vue");`;
+
+    expect(collectDependencies(parseModule(code))).toStrictEqual([
+      {
+        type: 'direct',
+        path:
+          '!babel-loader!vue-template-loader!vue-loader?vue&type=template&id=d8507872&bindings={"modelValue":"props","autoResize":"props","resize":"options","onInput":"options","filled":"options"}!./Textarea.vue',
+      },
+    ]);
+  });
+});
diff --git a/packages/app/src/sandbox/eval/transpilers/babel/convert-esmodule/index.test.ts b/packages/app/src/sandbox/eval/transpilers/babel/convert-esmodule/index.test.ts
index 11ae4b5d888..b834fd49940 100644
--- a/packages/app/src/sandbox/eval/transpilers/babel/convert-esmodule/index.test.ts
+++ b/packages/app/src/sandbox/eval/transpilers/babel/convert-esmodule/index.test.ts
@@ -1,8 +1,11 @@
 import { convertEsModule as convert } from '.';
+import { generateCode, parseModule } from '../ast/utils';
 import { getSyntaxInfoFromAst } from '../syntax-info';
 
 function convertEsModule(code: string) {
-  return convert(code).code;
+  const ast = parseModule(code);
+  convert(ast);
+  return generateCode(ast);
 }
 
 describe('convert-esmodule', () => {
@@ -590,15 +593,17 @@ export function test3() {
   describe('syntax info', () => {
     it('can detect jsx', () => {
       const code = `const a = <div>Hello</div>`;
-      const info = convert(code);
-      const syntaxInfo = getSyntaxInfoFromAst(info.ast);
+      const ast = parseModule(code);
+      convert(ast);
+      const syntaxInfo = getSyntaxInfoFromAst(ast);
       expect(syntaxInfo.jsx).toBeTruthy();
     });
 
     it('can detect non jsx', () => {
       const code = `const a = /<div>Hello<\\/div>/`;
-      const info = convert(code);
-      const syntaxInfo = getSyntaxInfoFromAst(info.ast);
+      const ast = parseModule(code);
+      convert(ast);
+      const syntaxInfo = getSyntaxInfoFromAst(ast);
       expect(syntaxInfo.jsx).toBeFalsy();
     });
   });
diff --git a/packages/app/src/sandbox/eval/transpilers/babel/worker/simple-get-require-statements.test.ts b/packages/app/src/sandbox/eval/transpilers/babel/worker/simple-get-require-statements.test.ts
index a93fcd175ea..db7bcf0d30b 100644
--- a/packages/app/src/sandbox/eval/transpilers/babel/worker/simple-get-require-statements.test.ts
+++ b/packages/app/src/sandbox/eval/transpilers/babel/worker/simple-get-require-statements.test.ts
@@ -69,4 +69,16 @@ describe('simple-get-require-statements', () => {
       { type: 'direct', path: './_iter-detect' },
     ]);
   });
+
+  it('handles quotes in a require statement', () => {
+    const code = `var $csb__Textareavue = require("!babel-loader!vue-template-loader!vue-loader?vue&type=template&id=d8507872&bindings={"modelValue":"props","autoResize":"props","resize":"options","onInput":"options","filled":"options"}!./Textarea.vue");`;
+
+    expect(getRequireStatements(code)).toStrictEqual([
+      {
+        type: 'direct',
+        path:
+          '!babel-loader!vue-template-loader!vue-loader?vue&type=template&id=d8507872&bindings={"modelValue":"props","autoResize":"props","resize":"options","onInput":"options","filled":"options"}!./Textarea.vue',
+      },
+    ]);
+  });
 });