react-intl v3 Upgrade
Taking advantage of the weekend to upgrade the react-intl library. The current latest version is
v4.6.9
, while the project is using versionv2.3.18
. I’ve decided to upgrade tov3@latest
.
Benefits of the Upgrade
- Fixes known bugs - in the previous version, when I passed
de-de
, internationalization would fail. The workaround at the time was to always set the localData key to ’en' - Reduces bundle size for the localeData portion, as it now uses the browser’s built-in Intl APIs
- Migration from
withRef
toforwardRef
, which is the current standard way for component reference passing, beneficial for consistency - Since React, Redux, and other major libraries have already been upgraded, upgrading Intl helps with future iteration upgrades for the overall framework
- Previous internationalization methods like formatMessage returned Node elements (containing Span tags), while v3 returns text. Strictly speaking, rendering will also reduce browser overhead since there are fewer nodes. Of course, for places that only need simple text, this directly satisfies the requirement
Open source may be free, but version upgrades require caution. However, staying stagnant is detrimental to both evolving web technologies and the product project itself, so progressive upgrades are necessary.
Upgrade Details
The official documentation provides a v2 to v3 upgrade guide, but upgrades are never completely smooth. Here I’ll explain the key points one by one.
Configuration
How to upgrade? Look here - I’ve listed the main key points. For things like values type files, etc., just directly replace and modify based on the error prompts.
package.json
"react-intl": "^3.12.1"
Note
v3 comes with built-in TypeScript type definitions, so the previous @types/react-intl
needs to be removed
tsconfig.json
"lib": ["es2015", "es2017", "dom", "es2018.intl", "esnext.intl"]
typings.d.ts
Because I extend the global window property by assigning the intl instance to it, I need the following definition:
import { IntlShape } from 'react-intl';
declare global {
interface Window {
intl: IntlShape;
}
}
Note
- If not needed, skip this configuration
- There’s a conflict between
declare module '*.svg';
anddeclare global
module declarations - they need to be physically separated into two declaration files. If the global declaration has no imports, thendeclare global
can be omitted
Unit Tests
The intl upgrade also affects unit tests, mainly in the utility functions. Configuration is as follows:
import { mount, render, shallow } from 'enzyme';
import React from 'react';
import { createIntl, IntlProvider } from 'react-intl';
import renderer from 'react-test-renderer';
const messages = {}; // en.json
const intl = createIntl({ locale: 'en', messages, onError: () => '' });
function nodeWithIntlProp(node) {
return React.cloneElement(node, { intl });
}
export function mountWithIntl(node) {
return mount(node, {
// @ts-ignore
wrappingComponent: IntlProvider,
wrappingComponentProps: {
locale: 'en',
defaultLocale: 'en',
messages
}
});
}
export function renderWithIntl(node) {
return render(<IntlProvider locale='en' messages={messages} onError={() => ''}>{node}</IntlProvider>);
}
export function rendererWithIntl(node) {
return renderer.create(<IntlProvider locale='en' messages={messages} onError={() => ''}>{node}</IntlProvider>);
}
Interface Definition Changes
InjectedIntlProps => WrappedComponentProps, withRef => forwardRef
You can do a global replace, but be careful not to make mistakes.
Final Thoughts
With the above configuration, the upgrade can be completed. Of course, considering system stability, I didn’t upgrade directly from v2 to v4, but after a quick look, the changes from 3 to 4 are relatively minor. So I’ll wait for the system to stabilize for a while before doing the next upgrade.