Skip to content

Commit 819f66e

Browse files
committed
feature #2006 [React] Improve error handling in resolveReactComponent (teklakct)
This PR was merged into the 2.x branch. Discussion ---------- [React] Improve error handling in `resolveReactComponent` | Q | A | ------------- | --- | Bug fix? | no | New feature? | no | Issues | | License | MIT ## WHAT Improve error handling and readability in `window.resolveReactComponent` function - Enhance error messages for clarity: - Indicate when a module exists but lacks a default export. - (still) List available controllers when a specified controller does not exist. With those changes, when resolving a module with no default export, an error message with a hint will be shown: ``` React controller "${name}" could not be resolved. Ensure the module exports the controller as default. ``` ## WHY I found that when someone creates a module without a default export then the error message is quite confusing. For example: ```js // NoDefaultExportComponent.jsx export const SomeRandomName = () => { return <div>Hello</div>; } ``` Whenever there will be an element like this ```html <div data-controller="NoDefaultExportComponent"> ... </div> ``` An error like below in console appear: > Error connecting controller > > React controller "**NoDefaultExportComponent**" does not exist. Possible values: SomeComponent, AnotherComponent, **NoDefaultExportComponent** Which is not exactly true. The module `NoDefaultExportComponent` was found but there is no required default export. Commits ------- 9e36018 [React] Improve error handling in `resolveReactComponent`
2 parents 53515c6 + 9e36018 commit 819f66e

File tree

5 files changed

+30
-2
lines changed

5 files changed

+30
-2
lines changed

src/React/CHANGELOG.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
# CHANGELOG
22

3+
## 2.26.0
4+
5+
- Improve error handling when resolving a React component
6+
37
## 2.21.0
48

5-
- Add `permanent` option to the `react_component` Twig function, to prevent the
6-
_unmounting_ when the component is deconnected and immediately re-connected.
9+
- Add `permanent` option to the `react_component` Twig function, to prevent the
10+
_unmounting_ when the component is deconnected and immediately re-connected
711

812
## 2.13.2
913

src/React/assets/dist/register_controller.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ function registerReactControllerComponents(context) {
1010
const component = reactControllers[`./${name}.jsx`] || reactControllers[`./${name}.tsx`];
1111
if (typeof component === 'undefined') {
1212
const possibleValues = Object.keys(reactControllers).map((key) => key.replace('./', '').replace('.jsx', '').replace('.tsx', ''));
13+
if (possibleValues.includes(name)) {
14+
throw new Error(`
15+
React controller "${name}" could not be resolved. Ensure the module exports the controller as a default export.`);
16+
}
1317
throw new Error(`React controller "${name}" does not exist. Possible values: ${possibleValues.join(', ')}`);
1418
}
1519
return component;

src/React/assets/src/register_controller.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ export function registerReactControllerComponents(context: __WebpackModuleApi.Re
3737
const possibleValues = Object.keys(reactControllers).map((key) =>
3838
key.replace('./', '').replace('.jsx', '').replace('.tsx', '')
3939
);
40+
41+
if (possibleValues.includes(name)) {
42+
throw new Error(`
43+
React controller "${name}" could not be resolved. Ensure the module exports the controller as a default export.`);
44+
}
45+
4046
throw new Error(`React controller "${name}" does not exist. Possible values: ${possibleValues.join(', ')}`);
4147
}
4248

src/React/assets/test/register_controller.test.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const createFakeFixturesContext = (): RequireContext => {
1717
const files: any = {
1818
'./MyJsxComponent.jsx': { default: MyJsxComponent },
1919
'./MyTsxComponent.tsx': { default: MyTsxComponent },
20+
'./NoDefaultExportComponent.jsx': { default: undefined },
2021
};
2122

2223
const context = (id: string): any => files[id];
@@ -45,4 +46,13 @@ describe('registerReactControllerComponents', () => {
4546
'React controller "MyABCComponent" does not exist. Possible values: MyJsxComponent, MyTsxComponent'
4647
);
4748
});
49+
50+
it('throws when no default export found in imported module', () => {
51+
registerReactControllerComponents(createFakeFixturesContext());
52+
const resolveComponent = (window as any).resolveReactComponent;
53+
54+
expect(() => resolveComponent('NoDefaultExportComponent')).toThrow(
55+
'React controller "NoDefaultExportComponent" could not be resolved. Ensure the module exports the controller as a default export.'
56+
);
57+
});
4858
});

src/React/doc/index.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ For example:
8181
return <div>Hello {props.fullName}</div>;
8282
}
8383
84+
.. note::
85+
86+
Ensure your module exports the controller as the ``export default``. The default export is used when resolving components.
87+
8488
.. code-block:: html+twig
8589

8690
{# templates/home.html.twig #}

0 commit comments

Comments
 (0)