After recently migrating a project over from Flow to TypeScript I've noticed a difference when using the Fragment shorthand (<></>). We have the following utility:
export const FragmentPassThrough: React.FC<{ children: React.ReactNode }> = ({
children
}) => <>{children}</>;
With Flow, it compiled as follows:
ro = function(e) {
return t.createElement(n.Fragment, null, e.children);
};
After moving to TS though, it doesn't take `Fragment` from React (eg. `n`):
Kr = function Kr(e) {
return t.createElement(Fragment, null, e.children);
}
Resulting in the following error when using the bundle:

index.js:formatted:1 Uncaught ReferenceError: Fragment is not defined
at Kr (index.js:formatted:1)
at renderWithHooks (index.js:formatted:1)
at mountIndeterminateComponent (index.js:formatted:1)
at beginWork (index.js:formatted:1)
at performUnitOfWork (index.js:formatted:1)
at workLoop (index.js:formatted:1)
at HTMLUnknownElement.callCallback (index.js:formatted:1)
at Object.invokeGuardedCallbackDev (index.js:formatted:1)
at invokeGuardedCallback (index.js:formatted:1)
at replayUnitOfWork (index.js:formatted:1)
at renderRoot (index.js:formatted:1)
at performWorkOnRoot (index.js:formatted:1)
at performWork (index.js:formatted:1)
at performSyncWork (index.js:formatted:1)
at interactiveUpdates$1 (index.js:formatted:1)
at interactiveUpdates (index.js:formatted:1)
at dispatchInteractiveEvent (index.js:formatted:1)
Kr @ index.js:formatted:1
renderWithHooks @ index.js:formatted:1
mountIndeterminateComponent @ index.js:formatted:1
beginWork @ index.js:formatted:1
performUnitOfWork @ index.js:formatted:1
workLoop @ index.js:formatted:1
callCallback @ index.js:formatted:1
invokeGuardedCallbackDev @ index.js:formatted:1
invokeGuardedCallback @ index.js:formatted:1
replayUnitOfWork @ index.js:formatted:1
renderRoot @ index.js:formatted:1
performWorkOnRoot @ index.js:formatted:1
performWork @ index.js:formatted:1
performSyncWork @ index.js:formatted:1
interactiveUpdates$1 @ index.js:formatted:1
interactiveUpdates @ index.js:formatted:1
dispatchInteractiveEvent @ index.js:formatted:1
index.js:formatted:1 The above error occurred in the component:
in Kr (created by r)
in div (created by Context.Consumer)
in EmotionCssPropInternal (created by SelectContainer)
in SelectContainer (created by r)
in r (created by r)
in r (created by Context.Consumer)
in StyledComponent (created by Styled(r))
in Styled(r)
in Unknown (at createForm.js:117)
in div (created by Context.Consumer)
in StyledComponent (created by styled.div)
in styled.div (at createForm.js:116)
in div (created by Context.Consumer)
in StyledComponent (created by styled.div)
in styled.div (at createForm.js:108)
in div (created by Context.Consumer)
in StyledComponent (created by styled.div)
in styled.div (at Form/index.js:91)
in Form (at FormTable.js:291)
in div (created by Context.Consumer)
in StyledComponent (created by styled.div)
in styled.div (at FormTable.js:289)
in div (created by Context.Consumer)
in StyledComponent (created by styled.div)
in styled.div (at FormTable.js:281)
in div (created by Context.Consumer)
in StyledComponent (created by styled.div)
in styled.div
in Unknown (at FormTable.js:268)
in FormTable (at createForm.js:148)
in div (created by Context.Consumer)
in StyledComponent (created by styled.div)
in styled.div (at createForm.js:147)
in div (created by Context.Consumer)
in StyledComponent (created by styled.div)
in styled.div (at Form/index.js:91)
in Form (at FieldGroupModal.js:24)
in div (created by Context.Consumer)
in StyledComponent (created by styled.div)
in styled.div (created by Me)
in div (created by ModalPortal)
in div (created by ModalPortal)
in ModalPortal (created by Modal)
in Modal
in Unknown (created by Context.Consumer)
in StyledComponent (created by Styled(Component))
in Styled(Component) (created by Me)
in Me (at FieldGroupModal.js:23)
in FieldGroupModal (at GroupsTab.js:180)
in GroupsTab (at Edit/index.js:33)
in div (created by TabPanel)
in TabPanel
in div (created by UncontrolledTabs)
in UncontrolledTabs (created by Tabs)
in Tabs
in Unknown (at Edit/index.js:45)
in div (created by Context.Consumer)
in StyledComponent (created by styled.div)
in styled.div (at Edit/index.js:44)
in Edit (created by Context.Consumer)
in Route (at App.js:35)
in Switch (at App.js:32)
in main (created by Context.Consumer)
in StyledComponent (created by styled.main)
in styled.main (at PageWrap.js:37)
in PageWrap (at App.js:31)
in App (at src/index.js:59)
in Router (created by BrowserRouter)
in BrowserRouter (at src/index.js:58)
in AppContextProvider (at src/index.js:56)
in ApolloProvider (at src/index.js:55)
Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://fb.me/react-error-boundaries to learn more about error boundaries.
console. @ index.js:formatted:1
r @ backend.js:6
logCapturedError @ index.js:formatted:1
logError @ index.js:formatted:1
update.callback @ index.js:formatted:1
callCallback @ index.js:formatted:1
commitUpdateEffects @ index.js:formatted:1
commitUpdateQueue @ index.js:formatted:1
commitLifeCycles @ index.js:formatted:1
commitAllLifeCycles @ index.js:formatted:1
callCallback @ index.js:formatted:1
invokeGuardedCallbackDev @ index.js:formatted:1
invokeGuardedCallback @ index.js:formatted:1
commitRoot @ index.js:formatted:1
(anonymous) @ index.js:formatted:1
unstable_runWithPriority @ index.js:formatted:1
completeRoot @ index.js:formatted:1
performWorkOnRoot @ index.js:formatted:1
performWork @ index.js:formatted:1
performSyncWork @ index.js:formatted:1
interactiveUpdates$1 @ index.js:formatted:1
interactiveUpdates @ index.js:formatted:1
dispatchInteractiveEvent @ index.js:formatted:1
index.js:formatted:1 Uncaught ReferenceError: Fragment is not defined
at Kr (index.js:formatted:1)
at renderWithHooks (index.js:formatted:1)
at mountIndeterminateComponent (index.js:formatted:1)
at beginWork (index.js:formatted:1)
at performUnitOfWork (index.js:formatted:1)
at workLoop (index.js:formatted:1)
at renderRoot (index.js:formatted:1)
at performWorkOnRoot (index.js:formatted:1)
at performWork (index.js:formatted:1)
at performSyncWork (index.js:formatted:1)
at interactiveUpdates$1 (index.js:formatted:1)
at interactiveUpdates (index.js:formatted:1)
at dispatchInteractiveEvent (index.js:formatted:1)
Kr @ index.js:formatted:1
renderWithHooks @ index.js:formatted:1
mountIndeterminateComponent @ index.js:formatted:1
beginWork @ index.js:formatted:1
performUnitOfWork @ index.js:formatted:1
workLoop @ index.js:formatted:1
renderRoot @ index.js:formatted:1
performWorkOnRoot @ index.js:formatted:1
performWork @ index.js:formatted:1
performSyncWork @ index.js:formatted:1
interactiveUpdates$1 @ index.js:formatted:1
interactiveUpdates @ index.js:formatted:1
dispatchInteractiveEvent @ index.js:formatted:1
As a temporary solution we've replaced the shorthand with an imported Fragment and it now compiles as expected:
export const FragmentPassThrough: React.FC<{ children: React.ReactNode }> = ({
children
}) => <Fragment>{children}</Fragment>;
Kr = function Kr(e) {
return t.createElement(n.Fragment, null, e.children);
}
0.12.0-next.816.12.03.7.5microbundle --jsx React.createElement --format cjs,umd
@breadadams does this still break if you set the following in your tsconfig.json?
{
"compilerOptions": {
"jsx": "preserve"
}
}
Apparently yes @developit, we already have that property set - sorry, should have shared our tsconfig:
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"noEmit": true,
"jsx": "preserve"
},
"include": ["src"]
}
I _think_ it's pretty much the default from a CRA.
I think we are accidentally processing JSX in TypeScript here:
https://github.com/developit/microbundle/blob/8cc0d7b3374c5dcaa745ea37b21b5ee7f975c882/src/index.js#L553-L554
We should probably be doing it in Babel (draft PR), since TypeScript has been dragging their heels on supporting configurable Fragment pragma for over a year.
Now, if I'm wrong about the above, you should be able to get fragment syntax working properly by setting the --jsxFragment command line flag:
microbundle --jsxFragment React.Fragment
Most helpful comment
I think we are accidentally processing JSX in TypeScript here:
https://github.com/developit/microbundle/blob/8cc0d7b3374c5dcaa745ea37b21b5ee7f975c882/src/index.js#L553-L554
We should probably be doing it in Babel (draft PR), since TypeScript has been dragging their heels on supporting configurable Fragment pragma for over a year.
Now, if I'm wrong about the above, you should be able to get fragment syntax working properly by setting the
--jsxFragmentcommand line flag: