Skip to main content

app

  • app:1.0 does:
    • print the information of request parameters
    • demonstrate how CSS modules works when dealing with SSR
    • show which manifest and entry are used to perform SSR
  • app:2.0 does:
    • demonstrate how routes and entries work together
  • app:3.0 does:

Basic and single entry app:1.0

1. Build and run it

npm run app:1.0:start

2. Check 1.0.development.js

module.exports = {
__VERSION__: "1.0.development",
__ENTRIES__: { "a.node.js": "a.node.<hash>.js" },
__ROUTES__: [
{
pattern: "/a.node",
entry: () => "a.node",
},
],
}
  • 1.0.development.js lets you locate the server chunks via a stable name. You will need this to generate a static HTML.
  • If the incoming request url is in /a.node, then use the entry a.node.js to perform SSR.

3. Generate HTML

Assume you want to generate a static page with this url http://127.0.0.1:8080/a.node.

cd examples/app/dist
node -e "require('./' + require('./1.0.development')['__ENTRIES__']['a.node.js']).default({'url': { 'href': '/a.node'}, '__VERSION__': '1.0.development'}).then((result) => console.log(result.body))" > index.html
note

To get this command working, you need to use yarn app:1.0. yarn app:1.0:start will write the server chunks to memory file system.

tip

Now you can gernerate all static pages with different input parameters and you do not need to start a web server.

Intermediate and multi entries app:2.0

1. Build and run it

npm run app:2.0:start

2. Check 2.0.development.js

module.exports = {
__VERSION__: "2.0.development",
__ENTRIES__: {
"a.node.js": "a.node.<hash>.js",
"b.node.js": "b.node.<hash>.js",
},
__ROUTES__: [
{
pattern: "/:entry",
entry: ({ params }) => params.entry,
},
],
}
  • 2.0.development.js shows it will handle two routes, /a.node and /b.node.

  • /a.node and /b.node use a.node.js and b.node.js respectively to handle the request.

  • If you hit /c.node, it will return HTTP 404.

    note

    404 is handled by webpack-dev-server

Advanced and single entry with react-router app:3.0

1. Build and run it

npm run app:3.0:start

2. Check 3.0.development.js

module.exports = {
__VERSION__: "3.0.development",
__ENTRIES__: { "index.node.js": "index.node.<hash>.js" },
__ROUTES__: [
{
pattern: "/(.*)",
entry: () => "index.node",
},
],
}
  • 3.0.development.js shows it will handle all kinds of urls.

  • /a.node, /b.node and /c.node use the same entry index.node.js to handle the request.

  • If you hit /c.node, it will return HTTP 404.

    note

    404 is handled by app logic. See the followings

    examples/app/3.0/App.jsx
    export function App(props) {
    return <StrictMode>
    <GlobalStyle />
    <Routes>
    <Route path="a.node" element={
    <DivWrapper flexDirection="column" color="#d63384" align={"center"}>
    <Suspense fallback={<div>loading...</div>}>
    <Img />
    </Suspense>
    <Code {...props} to={"b.node"} />
    </DivWrapper>
    }/>
    <Route path="b.node" element={
    <DivWrapper flexDirection="row">
    <img src={svg} />
    <Code {...props} to={"a.node"} />
    </DivWrapper>
    }/>
    <Route path="/*" element={
    <NotFound />
    }/>
    </Routes>
    </StrictMode>;
    }
    examples/app/3.0/common.jsx
    export function NotFound() {
    const statusCode = useContext(StatusCodeContext);
    const location = useLocation();
    statusCode.current = 404;
    return <Pre>
    Cannot GET {`${location.pathname}${location.search}`}
    </Pre>;
    }
    examples/app/3.0/index.node.js
    export default async (props = {}) => {
    const sheet = new ServerStyleSheet();
    const statusCode = createRef();
    statusCode.current = 200;

    const div = renderToString(
    sheet.collectStyles(
    <StatusCodeContext.Provider value={statusCode}>
    <StaticRouter location={props.url.path}>
    <App {...props} />
    </StaticRouter>
    </StatusCodeContext.Provider>
    )
    );

    // there is no point to dynamicially change the head at runtime
    // when users share a link, crawler will hit that link again
    const body = "<!DOCTYPE html>" + renderToStaticMarkup(<html>
    <head>
    <meta charSet="utf-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkqAcAAIUAgUW0RjgAAAAASUVORK5CYII="></link>
    <style dangerouslySetInnerHTML={{"__html": __SOURCES__["index.web.css"]}}></style>
    <script dangerouslySetInnerHTML={{"__html": `globalThis.props = ${JSON.stringify(props).replace(/</g, "\\u003c")}`}} />
    <script dangerouslySetInnerHTML={{"__html": __SOURCES__["index.web.js"]}} />
    {sheet.getStyleElement()}
    </head>
    <body>
    <div id="root" dangerouslySetInnerHTML={{"__html": div}} />
    <script integrity={__DIGESTS__["vendors.js"]} src={`${__webpack_public_path__}${__FILES__["vendors.js"]}`} crossOrigin="anonymous" />
    </body>
    </html>);

    return {
    body,
    "statusCode": statusCode.current,
    };
    };