Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Next.js 13 RSC integration #139

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Use Next.js internal request storage
  • Loading branch information
amannn committed Nov 15, 2022
commit 3ad8b5930250986ce5205a0c8344dbeda921700a
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
.DS_Store
node_modules
dist
.vscode
10 changes: 8 additions & 2 deletions packages/example/src/app/[locale]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import Storage from '../../utils/Storage';

export function generateStaticParams() {
return ['de', 'en'].map((locale) => ({locale}));
}
Expand All @@ -9,9 +11,13 @@ type Props = {
};

export default function Index({params: {locale}}: Props) {
// TODO: Validate locale or redirect to default locale
const value = Storage.get();

return <p>Hello {locale}</p>;
return (
<p>
Hello {locale} ({value.now})
</p>
);
}

// import {useTranslations} from 'next-intl';
Expand Down
8 changes: 5 additions & 3 deletions packages/example/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import {ReactNode} from 'react';
// import Provider from './Provider';
import Storage from '../utils/Storage';
import ServerOnlyContext from './ServerOnlyContext';

type Props = {
children: ReactNode;
};

export default function RootLayout({children, ...rest}: Props) {
console.log(rest);
export default function RootLayout({children}: Props) {
const now = new Date().toISOString();
Storage.set({now});

// How to get this from the URL?
Copy link

Choose a reason for hiding this comment

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

Maybe wrap all pages under optional [[locale]] then get using params

https://beta.nextjs.org/docs/routing/defining-routes#example

Copy link
Owner Author

Choose a reason for hiding this comment

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

Hey and thank you for your interest! Yep, that seems to work, I've experimented with it here:

export default function Index({params: {locale}}: Props) {
// TODO: Validate locale or redirect to default locale
return <p>Hello {locale}</p>;
}

I think that part is doable, the part where I currently don't see an ergonomic solution is how global configuration like messages can be passed to the library (see the topic about context in the PR description).

Copy link

@fdarian fdarian Nov 11, 2022

Choose a reason for hiding this comment

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

I've tried some workarounds,
1, Using singleton — Failed because for RSC, initializing on root layout requires 2 render to assign the messages object.
2. Using third-party state manager like zustand — Failed because of the same reason as number 1.

Probably the solution is gonna be around client component. To use in a server component we could provide utility component like <T key='dashboard.hi' />. Performance-wise, next will also server-render client components so the downside is on developer experience. But won't be much I think.

ps: I can't find any documentation for createServerContext, but I just try to use it regardless the type-error and it seems like it works without sacrificing DX. However, we need to refactor functions out of the context.

// TODO: Validate locale or redirect to default locale
const locale = 'en';

return (
Expand Down
27 changes: 27 additions & 0 deletions packages/example/src/utils/Storage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {requestAsyncStorage} from 'next/dist/client/components/request-async-storage';

const key = '__next-intl';

/**
* Returns the request-level storage of Nex.js where typically headers
* and cookies are stored. This is recreated for every request.
*/
function getStorage() {
const requestStore =
requestAsyncStorage && 'getStore' in requestAsyncStorage
? requestAsyncStorage.getStore()!
: requestAsyncStorage;

return requestStore;
}

export default {
set(value: any) {
const storage = getStorage();
(storage as any)[key] = value;
},
get() {
const storage = getStorage();
return (storage as any)[key];
}
};