In my preact SSR application, I have utilized Emotion JS 10 for styling purposes.
My goal was to incorporate RTL support into the app. To achieve this, I implemented createEmotion
and createEmotionServer
, leveraging the resulting renderStylesToString
to render the app.
However, in the process of creating createEmotion
, I encountered a challenge where the RTL styles were being consistently applied, whereas I needed them to be applied on a per-request basis.
I searched for a method to instruct Emotion to apply and retrieve the RTL styles for every request, but I couldn't find a straightforward solution tailored for Preact.
One potential solution would involve serving distinct webpack builds for RTL, but this would introduce unnecessary overhead.
EDIT 1: for those interested in implementing something similar, here is my approach
Both on the client side and during server-side rendering:
import stylisRTL from 'stylis-rtl';
import createEmotion from 'create-emotion';
const {
cx: cxRTL,
injectGlobal: injectGlobalRTL,
css: cssRTL,
cache: cacheRTL,
keyframes: keyframesRTL
} = createEmotion({
key: 'c',
stylisPlugins: [stylisRTL]
});
const {
cx: cxLTR,
injectGlobal: injectGlobalLTR,
css: cssLTR,
cache: cacheLTR,
keyframes: keyframesLTR
} = createEmotion({
key: 'c',
stylisPlugins: []
});
const runForBoth = (rtlFn, ltrFn) => (...args) => {
//this would be ur store sent in html to check whether it is in rtl or ltr mode
const isRTL = typeof window !== 'undefined' && window.__PRELOADED_STATE__.shell.RTL;
let result;
if (__BROWSER__) {
if (isRTL) {
result = rtlFn(...args);
} else {
result = ltrFn(...args);
}
} else {
result = ltrFn(...args);
rtlFn(...args);
}
return result;
};
export const cx = runForBoth(cxRTL, cxLTR);
export const injectGlobal = runForBoth(injectGlobalRTL, injectGlobalLTR);
export const css = runForBoth(cssRTL, cssLTR);
export const keyframes = runForBoth(keyframesRTL, keyframesLTR);
export const cacheEmotionLTR = cacheLTR;
export const cacheEmotionRTL = cacheRTL;
And for server-side rendering:
const { renderStylesToString: renderStylesToStringLTR } = createEmotionServer(cacheEmotionLTR);
const { renderStylesToString: renderStylesToStringRTL } = createEmotionServer(cacheEmotionRTL);
I establish two caches and based on request headers, I determine which renderStylesToString
to utilize.
There's a minor concern with runForBoth
technically not being accurate. However, it currently functions as intended.
I opted not to alter the way the css
function is imported, allowing me to seamlessly integrate these custom Emotion imports by aliasing them in webpack configurations