Skip to content

Commit

Permalink
fix: Fix compatibility with moduleResolution: 'Bundler' (#694)
Browse files Browse the repository at this point in the history
Fixes #690
  • Loading branch information
amannn committed Dec 5, 2023
1 parent 1782e9a commit f7425a5
Show file tree
Hide file tree
Showing 12 changed files with 101 additions and 19 deletions.
2 changes: 1 addition & 1 deletion examples/example-app-router/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
Expand Down
9 changes: 5 additions & 4 deletions packages/next-intl/src/server/react-client/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import type {
getFormatter as getFormatter_type,
getNow as getNow_type,
getTimeZone as getTimeZone_type,
getTranslations as getTranslations_type,
getMessages as getMessages_type,
getLocale as getLocale_type,
unstable_setRequestLocale as unstable_setRequestLocale_type
Expand Down Expand Up @@ -36,14 +35,16 @@ export const getNow = notSupported('getNow') as typeof getNow_type;
export const getTimeZone = notSupported(
'getTimeZone'
) as typeof getTimeZone_type;
export const getTranslations = notSupported(
'getTranslations'
) as typeof getTranslations_type;
export const getMessages = notSupported(
'getMessages'
) as typeof getMessages_type;
export const getLocale = notSupported('getLocale') as typeof getLocale_type;

// The type of `getTranslations` is not assigned here because it
// causes a type error. The types use the `react-server` entry
// anyway, therefore this is irrelevant.
export const getTranslations = notSupported('getTranslations');

export const unstable_setRequestLocale = notSupported(
'unstable_setRequestLocale'
) as typeof unstable_setRequestLocale_type;
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
// @ts-expect-error
// eslint-disable-next-line import/no-extraneous-dependencies
import getRuntimeConfig from 'next-intl/config';
import type {IntlConfig} from 'use-intl/core';
import type {GetRequestConfigParams} from './getRequestConfig';

export default getRuntimeConfig as (
export default getRuntimeConfig as unknown as (
params: GetRequestConfigParams
) => IntlConfig | Promise<IntlConfig>;
26 changes: 20 additions & 6 deletions packages/next-intl/src/server/react-server/getConfig.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {cache} from 'react';
import {initializeConfig} from 'use-intl/core';
import {initializeConfig, IntlConfig} from 'use-intl/core';
import createRequestConfig from './createRequestConfig';

// Make sure `now` is consistent across the request in case none was configured
Expand All @@ -25,10 +25,24 @@ const receiveRuntimeConfig = cache(
}
);

const getConfig = cache(async (locale: string) => {
const runtimeConfig = await receiveRuntimeConfig(locale, createRequestConfig);
const opts = {...runtimeConfig, locale};
return initializeConfig(opts);
});
const getConfig = cache(
async (
locale: string
): Promise<
IntlConfig & {
getMessageFallback: NonNullable<IntlConfig['getMessageFallback']>;
now: NonNullable<IntlConfig['now']>;
onError: NonNullable<IntlConfig['onError']>;
timeZone: NonNullable<IntlConfig['timeZone']>;
}
> => {
const runtimeConfig = await receiveRuntimeConfig(
locale,
createRequestConfig
);
const opts = {...runtimeConfig, locale};
return initializeConfig(opts);
}
);

export default getConfig;
4 changes: 3 additions & 1 deletion packages/next-intl/src/server/react-server/getFormatter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ const getFormatterImpl = cache(async (locale: string) => {
* The formatter automatically receives the request config, but
* you can override it by passing in additional options.
*/
export default async function getFormatter(opts?: {locale?: string}) {
export default async function getFormatter(opts?: {
locale?: string;
}): Promise<ReturnType<typeof createFormatter>> {
const locale = await resolveLocaleArg(opts);
return getFormatterImpl(locale);
}
5 changes: 4 additions & 1 deletion packages/next-intl/src/server/react-server/getMessages.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {cache} from 'react';
import type {AbstractIntlMessages} from 'use-intl';
import getConfig from './getConfig';
import resolveLocaleArg from './resolveLocaleArg';

Expand All @@ -14,7 +15,9 @@ const getMessagesImpl = cache(async (locale: string) => {
return config.messages;
});

export default async function getMessages(opts?: {locale?: string}) {
export default async function getMessages(opts?: {
locale?: string;
}): Promise<AbstractIntlMessages> {
const locale = await resolveLocaleArg(opts);
return getMessagesImpl(locale);
}
2 changes: 1 addition & 1 deletion packages/next-intl/src/server/react-server/getNow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const getNowImpl = cache(async (locale: string) => {
return config.now;
});

export default async function getNow(opts?: {locale?: string}) {
export default async function getNow(opts?: {locale?: string}): Promise<Date> {
const locale = await resolveLocaleArg(opts);
return getNowImpl(locale);
}
4 changes: 3 additions & 1 deletion packages/next-intl/src/server/react-server/getTimeZone.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ const getTimeZoneImpl = cache(async (locale: string) => {
return config.timeZone;
});

export default async function getTimeZone(opts?: {locale?: string}) {
export default async function getTimeZone(opts?: {
locale?: string;
}): Promise<string> {
const locale = await resolveLocaleArg(opts);
return getTimeZoneImpl(locale);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import getLocale from './getLocale';
// We need to define these with function overloads, otherwise TypeScript
// messes up the return type.

// CALL SIGNATURE 1: `getTranslations(namespace)`
function getTranslations<
NestedKey extends NamespaceKeys<
IntlMessages,
Expand Down Expand Up @@ -104,6 +105,7 @@ Promise<{
key: [TargetKey] extends [never] ? string : TargetKey
): any;
}>;
// CALL SIGNATURE 2: `getTranslations({locale, namespace})`
function getTranslations<
NestedKey extends NamespaceKeys<
IntlMessages,
Expand Down Expand Up @@ -192,6 +194,7 @@ Promise<{
key: TargetKey
): any;
}>;
// IMPLEMENTATION
async function getTranslations<
NestedKey extends NamespaceKeys<
IntlMessages,
Expand Down
56 changes: 56 additions & 0 deletions packages/next-intl/test/server/react-server/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,17 @@ describe('getTranslations', () => {
const t = await getTranslations({locale: 'en', namespace: 'About'});
expect(t.raw('rich')).toBe('<link>{name}</link>');
});

// eslint-disable-next-line @typescript-eslint/no-unused-vars
async function TypeTests() {
const t = await getTranslations();

// Valid
t('About.basic');

// @ts-expect-error Invalid argument
t(2);
}
});

describe('getFormatter', () => {
Expand All @@ -96,6 +107,18 @@ describe('getFormatter', () => {
'1/1/2020'
);
});

// eslint-disable-next-line @typescript-eslint/no-unused-vars
async function TypeTests() {
const format = await getFormatter();
const date = new Date('2020-01-01T00:00:00.000Z');

// Valid
format.dateTime(date, {dateStyle: 'full'});

// @ts-expect-error Invalid argument
format.dateTime(date, {dateStyle: 'unknown'});
}
});

describe('getNow', () => {
Expand All @@ -108,6 +131,17 @@ describe('getNow', () => {
'2020-01-01T00:00:00.000Z'
);
});

// eslint-disable-next-line @typescript-eslint/no-unused-vars
async function TypeTests() {
const now = await getNow();

// Valid
now.toISOString();

// @ts-expect-error Invalid argument
now.unknown();
}
});

describe('getMessages', () => {
Expand All @@ -118,6 +152,17 @@ describe('getMessages', () => {
it('returns the messages', async () => {
expect(await getMessages({locale: 'en'})).toHaveProperty('About');
});

// eslint-disable-next-line @typescript-eslint/no-unused-vars
async function TypeTests() {
const messages = await getMessages();

// @ts-expect-error
messages.about();

// Valid
return messages.about;
}
});

describe('getTimeZone', () => {
Expand All @@ -128,4 +173,15 @@ describe('getTimeZone', () => {
it('returns the time zone', async () => {
expect(await getTimeZone({locale: 'en'})).toBe('Europe/London');
});

// eslint-disable-next-line @typescript-eslint/no-unused-vars
async function TypeTests() {
const timeZone = await getTimeZone();

// Valid
timeZone.toUpperCase();

// @ts-expect-error Invalid argument
timeZone.unknown();
}
});
4 changes: 3 additions & 1 deletion packages/next-intl/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@
"extends": "eslint-config-molindo/tsconfig.json",
"include": ["src", "test", "types", "next-env.d.ts"],
"compilerOptions": {
"moduleDetection": "force",
"isolatedModules": true,
"module": "esnext",
"lib": ["dom", "esnext"],
"target": "ES2020",
"importHelpers": false,
"declaration": true,
"sourceMap": true,
"rootDir": ".",
"moduleResolution": "node",
"moduleResolution": "Bundler",
"jsx": "react",
"esModuleInterop": true,
"skipLibCheck": true,
Expand Down
2 changes: 1 addition & 1 deletion packages/use-intl/src/core/initializeConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import validateMessages from './validateMessages';
export default function initializeConfig<
// This is a generic to allow for stricter typing. E.g.
// the RSC integration always provides a `now` value.
Props extends Omit<IntlConfig, 'children'>
Props extends IntlConfig
>({getMessageFallback, messages, onError, ...rest}: Props) {
const finalOnError = onError || defaultOnError;
const finalGetMessageFallback =
Expand Down

2 comments on commit f7425a5

@vercel
Copy link

@vercel vercel bot commented on f7425a5 Dec 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on f7425a5 Dec 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

next-intl-docs – ./docs

next-intl-docs.vercel.app
next-intl-docs-git-main-next-intl.vercel.app
next-intl-docs-next-intl.vercel.app

Please sign in to comment.