ic-ui-kit icon indicating copy to clipboard operation
ic-ui-kit copied to clipboard

Add support for React SSR / Pre-rendering (Next.js / Vite)

Open GCHQDeveloper682 opened this issue 7 months ago • 7 comments

(Depends on https://github.com/mi6/ic-ui-kit/issues/1623)

Summary

At the moment, @ukic/react components cannot be rendered on the server, and attempting to do so will result in a build error for various reasons.

💬 Description

Stencil can now support SSR-compatible React output targets (see: https://stenciljs.com/docs/react#hydratemodule), which I have tested with ICDS and does work (after some effort). There are a few outstanding issues which block the implementation of an SSR output:

  • Declarative Shadow DOM (DSD) needs to be enabled (see: https://github.com/mi6/ic-ui-kit/issues/1623)
  • Needs @stencil/react-output-target@^1.0.1, which has a minimum React peer dependency of v18 (currently ICDS supports React v16.7.0 and above, with the @ukic/react dev dependency being pinned to v16.14.0, whilst @ukic/web-components has a dev dependency of React ^17.0.0)
  • The way @ukic/react uses a Barrel file to re-export everything from components.ts and add SlottedSVG to the exports: https://github.com/mi6/ic-ui-kit/blob/0e0197e19d7fcf61d2e2fb3f78bb97c25a0f8e22/packages/react/src/index.ts#L1 causes ESM issues when trying to build on the server
  • The DEVICE_SIZES map in @ukic/web-components contains browser-dependent code which runs on module import, which throws an error when run on the server: https://github.com/mi6/ic-ui-kit/blob/0e0197e19d7fcf61d2e2fb3f78bb97c25a0f8e22/packages/web-components/src/utils/helpers.ts#L483

We should provide a SSR React output and resolve the above issues to enable SSR to work out of the box for developers.

💰 Use value

Modern React is making a push towards more server-side rendering and partial pre-rendering of the React DOM. This has quite a few benefits, such as allowing progressive enhancement, and improving app initial load times / preventing flash of unstyled content. The major React-compatible frameworks (in particular Next.js and Remix / Vite) also put emphasis on SSR. This would also enable static site generation (building static html pages from a React app) and partial pre-rendering of components, each of which have their own developer use cases.

Even when developers don't want to make use of SSR, SSG, or pre-rendering of React components in ICDS, the lack of SSR support causes compatibility issues with frameworks like Remix and Next.js, which require workarounds that introduce complexity to getting started in ICDS.

🚨 Urgency (low, medium or high)

Medium (this is a significant pain point for developers starting new React projects with ICDS, or bringing ICDS into existing React-based projects).

GCHQDeveloper682 avatar Jun 19 '25 07:06 GCHQDeveloper682

Part of this ticket can be completed now, see internal discussions

MI6-255 avatar Jul 09 '25 08:07 MI6-255

Once this ticket is completed, unblock #3686

GCHQ-Developer-299 avatar Jul 17 '25 09:07 GCHQ-Developer-299

Put this back into "ready for dev". I have had a go with this ticket but I have been struggling a lot - I've had very little experience with tickets like this previously (i.e. SSR, and updating / changing dependencies and config) and I have found it a bit stressful as I have felt like I don't have enough knowledge sometimes to know if I'm changing the right things (and not breaking things for customers). The documentation online is also limited which hasn't helped.

If anyone else would like to have a go with this, that would be great. If not I can maybe try again with this at a later date after having had a break from it.


I have put everything I've done so far into branch feat/3669-add-ssr-support. The commit messages should give a rough summary of my changes, but here are some other notes to explain certain changes more specifically:

  • I decided to upgrade to React 18 instead of 19, because I tried 19 but had the issue mentioned on #3158 where storybook-addon-performance doesn't support React 19 yet

  • I updated the typescript version; this was recommended by Copilot when I asked what other dependencies I should update when upgrading to React 18

  • I had to put @stencil/react-output-target in the core dependencies in package.json for the react and canary-react packages because I would otherwise get this error when trying to use the packages (npm packed locally) in a test app:

    Image
  • I tested @ukic/react and @ukic/canary-react from my branch (with just the first two commits) in a test app using React 16 and 19. It all seems to work fine (the components render at least); the only issue with the React 16 app is that it said there were dependency conflicts (only a warning, not an error) when doing an npm i, but I think this is fine (at least expected considering I have made @stencil/react-output-target a core dependency)

  • I've put @ts-expect-error (i.e. TypeScript ignore) comments in certain files e.g. createOverlayComponent.tsx. This is because I kept getting a type error (same as this comment). Documentation about this in particular is very minimal; I ended up searching all repos in GitHub for the same file and found some repos which had just taken this approach so assumed it would be fine to do the same. (FYI I believe most of the files in react-component-lib were copied and pasted from Ionic a while ago, and they're not auto-generated)

  • I had to change some of the stencil.config.ts options due to the updated @stencil/react-output-target version. I'm not 100% sure if the options / values are correct but they were my best guess based on the docs

  • The latest commit is just an attempt at getting the other steps from the spike write-up sorted ("Expose the hydrate module" and "Expose the server entry point"). I've had issues with this as I keep getting errors in the components.server.ts file about imports not resolving. I thought changing the tsconfig.json module resolution (e.g. see Stencil docs) might fix it, but no luck

GCHQ-Developer-847 avatar Jul 22 '25 15:07 GCHQ-Developer-847

In the second attempt with this ticket, we have created a new branch: feat/2-3669-add-ssr-support, where we have also rebased onto develop to make sure everything is up-to-date (this brought up errors with text field and search bar, but they have been fixed - by removing the autocorrect props, which weren't actually being used within the components' code).

However, the breaking change with @stencil/react-output-target (props no longer being reflected unless reflect has been set to true) is causing issues with some styling and behaviour. Therefore, we can't complete the upgrade to React 18 until #3837 has been completed.

I am moving this ticket back into "Ready for dev" for now (not "On hold") so that it's still visible within this sprint. Anyway we might hopefully be able to pick it up again later on in this sprint now that #3837 has been moved in.

GCHQ-Developer-847 avatar Aug 07 '25 14:08 GCHQ-Developer-847

added #3857 which will also be required to complete this work.

ad9242 avatar Aug 08 '25 07:08 ad9242

added #3861, which can be worked on to solve styling issues, without introducing breaking changes

ad9242 avatar Aug 12 '25 11:08 ad9242

Moved to v3 breaking changes to be worked on alongside: https://github.com/mi6/ic-ui-kit/issues/3861. Based on internal discussions that this would result in dropping React 16 support, making it a breaking change, and we're not in a position to get bump a major version of ICDS yet. Therefore, this work is on hold until then. Our plan is to push for v4 release for roughly the v3 1-year anniversary, to bring this change in sooner

MI6-255 avatar Aug 12 '25 12:08 MI6-255