-
-
Notifications
You must be signed in to change notification settings - Fork 213
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
Add SSR support #79
Comments
@lesmo Hi 👋 I'm not a big user of SSR but it should be do-able. The main pain point is currently to parse and send the Imagine: // on server
import { parseAcceptLanguageHeader } from "react-native-localize/server"
// …
render(<App languages={parseAcceptLanguageHeader(header)} />) In your app: generateConstants(languages) But could it be enough? Another solution could be to switch to lazy, synchronous getters. |
Oh I like that idea! Passing The browser API could be polyfilled for SSR... 🥁 drums for dramatic effect... 🥁 with intl perhaps? Using it as an optional dependency would allow for this magic to happen. |
|
I've looked into that and while it hasn't been updated, I wouldn't say it's unmaintained... just dusty. 😜 While researching for some bugs on my Android build, I found some mentions of that polyfill as a solution to the missing I think a reasonable solution would be to warn and maybe even have users of I believe that's a nice solution. Just rewrite the web stuff to be lazy, and document that it'll need to be run on Node with proper support. I'll see if I can put together a PR. 😀 |
@lesmo I just published a new version with lazy getters on the web version: https://github.com/react-native-community/react-native-localize/releases/tag/1.3.3 Now we are free of code that calls |
Thanks! I'll try this out! I've been thinking about the expressApp.get("/*", (req, res) => {
const { path, query } = req;
const runtimeLocales = parser.parse(req.get('Accept-Language');
const localize = new RNLocalize({ runtimeLocales });
const { navigation, title, options } = handleServerRequest(
AppNavigator.router,
path,
query
);
// register the app
AppRegistry.registerComponent('App', () => App);
// prerender the app
const { element, getStyleElement } = AppRegistry.getApplication('App', {
initialProps: { navigation, localize }, // now <App> has localize prop
});
const markup = renderToString(<AppNavigator navigation={navigation} />);
res.send(
`<!doctype html>
<html lang="">
<head>
<title>${title}</title>
<script src="main.js"></script>
</head>
<body>
<div id="root">${markup}</div>
</body>
</html>`
);
}); This way we can do: // App.js
export default App = ({ localize }) => {
const lang = localize.findBestAvailableLanguage(['en', 'en-GB', 'fr', 'pr']);
return <AnAwesomeApp />
} Or fancier, putting it inside a react context one could use hooks too: // App.js
export default App = ({ runtimeLocales }) => {
return (
// Directly "override" the platform available languages with
// the ones from express
<LocalizeProvider platformLanguages={runtimeLocales}>
<AnAwesomeApp />
</LocalizeProvider>
)
}
// Somewhere.js
export const Somewhere = () => {
const localize = useLocalize();
return (
<Text>{localize.getCountry()}</Text>
);
}; This way there's no direct dependency on global variables and it's SSR friendly... but it's a massive refactor, and I'm not sure it's a good idea (yet) or if could benefit other use cases at all. Something for like v2 maybe? 😅 |
@lesmo Totally in the v2 TODO list 🙂 |
Hi guys, I would be interested in this as well. Do you have some roadmap (for the v2) on when this will be implemented? Cheers! |
Just a heads up, Intl.js will no longer be maintained so... I guess the best route forward would be to consider having implementers make sure they run Node with Intl compiled into the final binary. |
FormatJS offers a full set of polyfills: https://formatjs.io/docs/polyfills |
Actually, the home page says it does so... that's the one! |
We (formatjs) do support Node, although Node 14+ has almost everything you need (sans the bugs that we fixed) |
Feature Request
Support for SSR. Current index.web.js is directly calling browser-only objects, which is not possible while being rendered on the server.
Why it is needed
Because localize all the things everywhere!
Possible implementation
I noticed the calls are to
navigator
andwindow
objects. Those statements are called as soon as any code importsreact-native-localize
, so it would be necessary to "delay" that to a later stage, or call them lazily or even conditionally. I don't know how this module's internals work... yet 😏Code sample
This is a conditional example that would render properly on SSR:
The only complication is how to make
constants
somehow wait or be populated until the browser is ready without breaking anything. This could work:But I'm not sure if an undefined
constants
would break something, and there would of course need to be a way to know from the client which locale to use. I'll get back if I come up with something.The text was updated successfully, but these errors were encountered: