Skip to content

Commit

Permalink
Prevent cyclic dependencies in remix projects (#4557)
Browse files Browse the repository at this point in the history
* fix(editor) Prevent cyclic dependencies in remix projects

* chore(editor) Added a test for remix cyclic dependencies
  • Loading branch information
Rheeseyb authored Nov 24, 2023
1 parent 75ccd4b commit e0d9f35
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,15 @@ async function renderRemixProject(project: PersistentModel) {
}

describe('Remix content', () => {
it('Renders the remix container with actual content', async () => {
it('Renders the remix container with actual content and a cyclic dependency', async () => {
const project = createModifiedProject({
[StoryboardFilePath]: `import * as React from 'react'
import { RemixScene, Storyboard } from 'utopia-api'
import { Card } from '/app/components/card'
export function gimmeData() {
return '${DefaultRouteTextContent}'
}
export var storyboard = (
<Storyboard>
Expand All @@ -90,6 +95,16 @@ describe('Remix content', () => {
</Storyboard>
)
`,
['/app/components/card.js']: `import * as React from 'react'
import { gimmeData } from '${StoryboardFilePath}'
export const Card = (props) => {
const data = gimmeData()
return (
<h1>{data}</h1>
)
}
`,
['/app/root.js']: `import React from 'react'
import { Outlet } from '@remix-run/react'
Expand All @@ -103,9 +118,10 @@ describe('Remix content', () => {
}
`,
['/app/routes/_index.js']: `import React from 'react'
import { Card } from '/app/components/card'
export default function Index() {
return <h1>${DefaultRouteTextContent}</h1>
return <Card />
}
`,
})
Expand Down
9 changes: 5 additions & 4 deletions editor/src/components/canvas/remix/remix-utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ function getRemixExportsOfModule(
displayNoneInstances: Array<ElementPath>,
metadataContext: UiJsxCanvasContextData,
) => {
let resolvedFiles: MapLike<Array<string>> = {}
let resolvedFiles: MapLike<MapLike<any>> = {}
let resolvedFileNames: Array<string> = [filename]

const requireFn = curriedRequireFn(innerProjectContents)
Expand All @@ -267,11 +267,12 @@ function getRemixExportsOfModule(
}
let resolvedFromThisOrigin = resolvedFiles[importOrigin]

const alreadyResolved = resolvedFromThisOrigin.includes(toImport) // We're inside a cyclic dependency, so trigger the below fallback const filePathResolveResult = alreadyResolved
const alreadyResolved = resolvedFromThisOrigin[toImport] !== undefined
const filePathResolveResult = alreadyResolved
? left<string, string>('Already resolved')
: resolve(importOrigin, toImport)

forEachRight(alreadyResolved, (filepath) => resolvedFileNames.push(filepath))
forEachRight(filePathResolveResult, (filepath) => resolvedFileNames.push(filepath))

const resolvedParseSuccess: Either<string, MapLike<any>> = attemptToResolveParsedComponents(
resolvedFromThisOrigin,
Expand All @@ -287,7 +288,7 @@ function getRemixExportsOfModule(
metadataContext,
NO_OP,
false,
alreadyResolved,
filePathResolveResult,
null,
)
return foldEither(
Expand Down

0 comments on commit e0d9f35

Please sign in to comment.