Skip to content

Commit

Permalink
fix(imports) Insert React Import For Modules (#5710)
Browse files Browse the repository at this point in the history
- `evaluateJs` now streamlines an import for React into the code, if there isn't already one.
- Added `addReactImport`, `includesReactImport` and `isJSXLikeFilePath` utility functions.
  • Loading branch information
seanparsons authored May 24, 2024
1 parent 17a8370 commit e471d3f
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 20 deletions.
1 change: 1 addition & 0 deletions editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@
},
"dependencies": {
"@babel/code-frame": "7.14.5",
"@babel/parser": "7.24.5",
"@babel/plugin-external-helpers": "7.14.5",
"@babel/plugin-proposal-class-properties": "7.16.7",
"@babel/plugin-proposal-export-namespace-from": "7.14.5",
Expand Down
32 changes: 13 additions & 19 deletions editor/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 36 additions & 1 deletion editor/src/core/es-modules/evaluator/evaluator.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { safeFunction } from '../../shared/code-exec-utils'
import * as Babel from '@babel/standalone'
import * as BabelParser from '@babel/parser'
import traverse from '@babel/traverse'
import * as BabelTransformCommonJS from '@babel/plugin-transform-modules-commonjs'
import * as BabelExportNamespaceFrom from '@babel/plugin-proposal-export-namespace-from'
import * as BabelClassProperties from '@babel/plugin-proposal-class-properties'
Expand All @@ -12,6 +14,11 @@ function getFileExtension(filepath: string) {
return filepath.slice(lastDot + 1)
}

function isJSXLikeFilePath(filepath: string): boolean {
const fileExtension = getFileExtension(filepath)
return fileExtension === 'jsx' || fileExtension === 'tsx'
}

function isEsModuleError(error: Error) {
return (
error.name === 'SyntaxError' &&
Expand Down Expand Up @@ -47,13 +54,41 @@ function transformToCommonJS(
}
}

function includesReactImport(moduleCode: string): boolean {
const ast = BabelParser.parse(moduleCode, { sourceType: 'module', plugins: ['jsx'] })
let reactImportFound: boolean = false
traverse(ast, {
ImportDeclaration: (path) => {
if (path.node.specifiers.some((specifier) => specifier.local.name === 'React')) {
reactImportFound = true
path.stop()
}
},
})
return reactImportFound
}

const reactImportText = `import * as React from 'react'`

function addReactImport(filePath: string, moduleCode: string): string {
if (isJSXLikeFilePath(filePath) && !includesReactImport(moduleCode)) {
return `${reactImportText}\n${moduleCode}`
} else {
return moduleCode
}
}

function evaluateJs(
filePath: string,
moduleCode: string,
moduleCodeBefore: string,
fileEvaluationCache: FileEvaluationCache,
requireFn: (toImport: string) => unknown,
): any {
let module = fileEvaluationCache
// With a lot of configurations of how to handle JSX, a React import is implicitly added to the code.
// As this is a fallback case for code in the project and the code hasn't been transpiled yet, it may not have a React import.
// This streamlines in a React import if it's missing, so that the transpiled code can refer to `React.createElement`.
const moduleCode = addReactImport(filePath, moduleCodeBefore)

function firstErrorHandler(error: Error): void {
if (isEsModuleError(error)) {
Expand Down

0 comments on commit e471d3f

Please sign in to comment.