Unwrap settings front components in the front component build (#23631)

## Summary

The front-component build transform only unwrapped
`defineFrontComponent`, so a file using `defineSettingsFrontComponent`
skipped the transform and built its ValidationResult object as the
default export. The front-component renderer then crashed at load with
"componentModule.default is not a function".

Broadens the unwrap patterns to cover both define functions and adds a
spec case. Introduced in #23256 alongside the new define function; no
app exercises the path yet.

## Validation

```
cd packages/twenty-sdk && npx vitest run --config vitest.unit.config.ts src/cli/utilities/build/common/front-component-build/utils/__tests__/unwrap-define-front-component-to-direct-export.spec.ts
```

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/23631?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
This commit is contained in:
nitin
2026-07-31 18:24:15 +05:30
committed by GitHub
parent d02332834b
commit 4019b990c5
2 changed files with 27 additions and 2 deletions
@@ -34,6 +34,19 @@ export default defineFrontComponent({
});
`;
const SETTINGS_COMPONENT_SOURCE = `import { defineSettingsFrontComponent } from 'twenty-sdk/define';
import { APP_SETTINGS_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
import { AppSettings } from 'src/front-components/components/AppSettings';
export default defineSettingsFrontComponent({
universalIdentifier: APP_SETTINGS_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER,
name: 'app-settings',
description: 'Custom settings tab',
component: AppSettings,
});
`;
describe('unwrapDefineFrontComponentToDirectExport', () => {
it('renders the component when component is an inline factory call', () => {
const output = unwrapDefineFrontComponentToDirectExport(
@@ -76,6 +89,18 @@ describe('unwrapDefineFrontComponentToDirectExport', () => {
expect(identifierOutput).toContain(renderer);
});
it('renders the component when defined with defineSettingsFrontComponent', () => {
const output = unwrapDefineFrontComponentToDirectExport(
SETTINGS_COMPONENT_SOURCE,
);
expect(output).toContain('component: AppSettings,');
expect(output).toContain(
'__frontComponentJsx(__frontComponentDefinition.component, {})',
);
expect(output).not.toContain('defineSettingsFrontComponent');
});
it('leaves a source without a defineFrontComponent default export untouched', () => {
const source = `import { useEffect } from 'react';
@@ -1,8 +1,8 @@
const DEFINE_FRONT_COMPONENT_IMPORT_PATTERN =
/import\s*\{\s*defineFrontComponent\s*\}\s*from\s*['"][^'"]+['"];?\n?/g;
/import\s*\{\s*define(?:Settings)?FrontComponent\s*\}\s*from\s*['"][^'"]+['"];?\n?/g;
const DEFINE_FRONT_COMPONENT_EXPORT_OPENING_PATTERN =
/export\s+default\s+defineFrontComponent\s*\(/;
/export\s+default\s+define(?:Settings)?FrontComponent\s*\(/;
const IDENTIFIER_COMPONENT_VALUE_PATTERN =
/component\s*:\s*([A-Za-z_$][\w$]*)\s*[,}]/;