Microbundle: Error using Fragment shorthand in React Typescript project

Created on 14 Feb 2020  路  3Comments  路  Source: developit/microbundle

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: ![image](https://user-images.githubusercontent.com/5795227/74535227-b1055880-4f35-11ea-8759-2a6e18eeb906.png)
Full stack trace
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);
}

Versions
  • Microbundle 0.12.0-next.8
  • React 16.12.0
  • Typescript 3.7.5
Build script:

microbundle --jsx React.createElement --format cjs,umd

has-fix

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 --jsxFragment command line flag:

microbundle --jsxFragment React.Fragment

All 3 comments

@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
Was this page helpful?
0 / 5 - 0 ratings

Related issues

yaymukund picture yaymukund  路  4Comments

adriengibrat picture adriengibrat  路  4Comments

retyui picture retyui  路  4Comments

chrstntdd picture chrstntdd  路  4Comments

Kikobeats picture Kikobeats  路  4Comments