Coming Soon: React 18!

In DXP 2025.Q1 and CE GA 134*, Liferay will be on React 18 instead of React 16. Read on to see how this could affect you...

React 18

Well, we've done it! We've updated finally from React 16 to React 18 at the portal level.

In DXP 2025.Q1 and CE GA 134*, Liferay is no longer going to be based on React 16. This is significant since React 16 was first released in 2017, so we were pretty far behind on an update there. Granted React 18 was released in 2022, so it's really only about 2 years behind, but there was the big technical debt that had to be paid.

* It may be CE GA 134 or GA 135, at this point in time I'm not sure yet what the actual build number will be for the CE release.

From my coworker Bryce Osterhaus:

Upgrading to React 18 is a significant milestone for us because it is the first time we have upgraded out React version. We first added official React support into liferay-portal in 2019, and previously we used it sparingly in individual projects. The first supported version of React in Liferay was 16.8.6 and before this upgrade we were at 16.12.0. Now we will be at 18.3.1 which is the latest React release (React 19 was recently released and we will evaluate that in the future).

So, what will this mean to you and your React 16 fragments and apps?

Liferay is still going to provide React 16 core and DOM modules via JS Import Maps, but you'll need to wire those up manually to get everything to work, and it will require some minor code changes...

Liferay is going to make available two imports, react-16 and react-dom-16. So you'll find your imports changing in your jsx files like so:

import React from "react-16";
import { render } from "react-dom-16";

Since you're doing an upgrade you'd already have React 16 in your dependencies, but if you didn't you would just need to yarn add react@16.12 react-dom@16.12 to get right versions.

Notice the discrepancies, though. The dependencies that you're adding are react and react-dom, not react-16 and react-dom-16. That will cause you some build time problems. The solution to this is going to be using package aliases so the imports map correctly, but then there's the question of the builds...

Depending upon how you build your React component, you'll approach it in different ways...

If you're using Webpack, it has a convenient configuration to support the aliasing of the externals:

const path = require('path');

module.exports = {
  // Other Webpack settings...
  resolve: {
    alias: {
      'react-16': path.resolve(__dirname, 'node_modules/react'),
      'react-dom-16': path.resolve(__dirname, 'node_modules/react-dom'),
    },
  },
  externals: {
    // This makes Webpack ignore React and ReactDOM when building the final bundle
    'react-16': 'React', 
    'react-dom-16': 'ReactDOM',
  },
};

If you're using Vite, you'll need to set up some resolution aliases:

import { defineConfig } from 'vite';

export default defineConfig({
  resolve: {
    alias: {
      // Redirect `react-16` to `react` for transpilation
      'react-16': 'react',
      'react-dom-16': 'react-dom',
    },
  },
  base: '/o/my-react-custom-element',
  build: {
    rollupOptions: {
      external: [
        // Exclude only `react-16` from the bundle
        'react-16',
        'react-dom-16',
        /^(?!@clayui\/css)@clayui.*$/,
      ],
    },
  },
  plugins: [
    react({
      jsxRuntime: 'classic',
    }),
  ]
});

Although this should be a doable path, it could be problematic (of course your mileage may vary). Any time I see something like this where you're using one thing but aliasing it as something else to get something other than the normal operation to work, it just suffers from a kind of "code smell".

Another option is just biting the bullet and take another path: consider updating your code to React 18. If you're wondering how to do this, I found this useful article that is a good starting point that covers a number of reasons why you'd want to upgrade as well as how to do the upgrade: Why and How to Upgrade React From v16.x to v18.x

One thing from the article, it points out automatic batching as a performance improvement for React 18, but it fails to call out that you could face a problem if your code is dependent on setState() happening synchronously with re-renders.

Once you get done with the whys and hows, you should of course read a more official upgrade blog post from ReactJS.org themselves that is chock-full of technical details.

And if you're going to be upgrading your React code, it's a really great time to verify that you're complying to the Rules of React. The rules exist for a reason, and if you're not adhering to them you could cause problems in your own code or in Liferay's runtime.

My Recommendations

First and foremost, I do recommend using Liferay's version of React. I just don't like the idea of possibly multiple versions of React running in a browser window...

So, if you're starting a new project, use Liferay's React 18 version in the same way you built to leverage Liferay's React 16 in the past.

For those projects that are built to leverage Liferay's React 16, I gave a few ways above that you might be able to continue to use Liferay's React 16, but these may or may not work well for you (the whole aliasing thing really depends upon your packaging tool being able to handle it correctly).

An easier path is probably to just package React 16 into your project. So in my From React App to React Client Extension in 5 Easy Steps blog post, in Step 5 where I configure Vite to treat React as an external, I'd just strip that out so when Vite is packaging the app it would include React 16.

Although this would introduce another React version into the browser, it is likely the most pain free and least impacting path that will keep your React apps working as you'd expect.

And when Liferay updates to React 19, I'd follow these same recommendations - Use Liferay's React 19 version in new projects and change existing projects to bundle React 18.

Conclusion

Hopefully this blog will help you prepare for the coming React 18 update and give you the guidance you need to ensure your React code is going to work on the 2025 quarterlies.

But, if you run into problems, on DXP you can open a support ticket, and for CE (and yes even for DXP too) you can post to the Community Slack channels where I or others (some from the frontend team) will be able to help.

You can also go to the Community Slack to ask questions around this, seek guidance, etc.

Good Luck!