How to use different versions of a file for client and server rendering
There are 3 main ways to use different code for server vs. client rendering.
A. Using different Entry Points
Many projects will have different entry points for client and server rendering. This only works for a top-level entry point such as the entry point for a react-router app component.
Your Client Entry can look like this:
import ReactOnRails from 'react-on-rails';
import App from './ClientApp';
ReactOnRails.register({ App })
So your Server Entry can look like:
import ReactOnRails from 'react-on-rails';
import App from './ServerApp';
ReactOnRails.register({ App })
Note that the only difference is on the second line of each of these examples.
B. Two Options for Using Webpack Resolve Alias in the Webpack Config
Per Webpack Docs.
1. Update webpack/set-resolve.js
to have a different resolution for the exact file:
function setResolve(builderConfig, webpackConfig) {
// Use a different resolution for Client and Server file
let SomeJsFile;
if (builderConfig.serverRendering) {
SomeJsFile = path.resolve(__dirname, "../bundles/SomeJsFileServer");
} else {
SomeJsFile = path.resolve(__dirname, "../bundles/SomeJsFileClient");
}
const resolve = {
alias: {
... // blah blah
SomeJsFile,
... // blah blah
},
Then you have this import:
import SomeJsFile from 'SomeJsFile';
2. Use a different resolution for the right directory of client or server files:
a. Update webpack/set-resolve.js
to have something like:
function setResolve(builderConfig, webpackConfig) {
// Use a different resolution for Client and Server file
let variant;
if (builderConfig.serverRendering) {
variant = path.resolve(__dirname, "../bundles/variant/ClientOnly");
} else {
variant = path.resolve(__dirname, "../bundles/variant/serverOnly");
}
const resolve = {
alias: {
... // blah blah
variant
... // blah blah
},
b. Add different versions of the file to the bundles/variant/ClientOnly
and bundles/variant/ServerOnly
directories
c. Use the variant
in import in a file that can be used both for client and server rendering:
import SomeJsFile from 'variant/SomeJsFile';
import AnotherJsFile from 'variant/AnotherJsFile';
C. Conditional code that can check if window
is defined.
This is probably the ugliest and hackiest way to do this, but it's quick! Essentially you wrap code that cannot execute server side in a conditional:
if (window) { // window should be falsy on the server side
doSomethingClientOnly();
// or do an import
const foobar = require('foobar').default;
}