Skip to content

Commit

Permalink
feat: meta tags and other improvements for spa
Browse files Browse the repository at this point in the history
  • Loading branch information
CA-MKSingh committed Oct 24, 2024
1 parent 443b8fb commit 037efa6
Show file tree
Hide file tree
Showing 6 changed files with 210 additions and 150 deletions.
18 changes: 18 additions & 0 deletions app/entry.client.nonSpa.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* By default, Remix will handle hydrating your app on the client for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/file-conventions/entry.client
*/

import { startTransition, StrictMode } from 'react';
import { RemixBrowser } from '@remix-run/react';
import { hydrateRoot } from 'react-dom/client';

startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<RemixBrowser />
</StrictMode>
);
});
24 changes: 9 additions & 15 deletions app/entry.client.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
/**
* By default, Remix will handle hydrating your app on the client for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/file-conventions/entry.client
*/

import { RemixBrowser } from "@remix-run/react";
import { startTransition, StrictMode } from "react";
import { hydrateRoot } from "react-dom/client";
import { startTransition, StrictMode } from 'react';
import { RemixBrowser } from '@remix-run/react';
import { hydrateRoot } from 'react-dom/client';

startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<RemixBrowser />
</StrictMode>
);
hydrateRoot(
document.querySelector('#app')!,
<StrictMode>
<RemixBrowser />
</StrictMode>
);
});
105 changes: 105 additions & 0 deletions app/entry.server.nonSpa.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/**
* By default, Remix will handle generating the HTTP Response for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/file-conventions/entry.server
*/

import type { AppLoadContext, EntryContext } from '@remix-run/node';
import { createReadableStreamFromReadable } from '@remix-run/node';
import { RemixServer } from '@remix-run/react';
import { isbot } from 'isbot';
import { PassThrough } from 'node:stream';
import { renderToPipeableStream } from 'react-dom/server';

const ABORT_DELAY = 5_000;

export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
// This is ignored so we can keep it in the template for visibility. Feel
// free to delete this parameter in your app if you're not using it!
// eslint-disable-next-line @typescript-eslint/no-unused-vars
loadContext: AppLoadContext
) {
return isbot(request.headers.get('user-agent') || '')
? handleBotRequest(request, responseStatusCode, responseHeaders, remixContext)
: handleBrowserRequest(request, responseStatusCode, responseHeaders, remixContext);
}

function handleBotRequest(request: Request, responseStatusCode: number, responseHeaders: Headers, remixContext: EntryContext) {
return new Promise((resolve, reject) => {
let shellRendered = false;
const { pipe, abort } = renderToPipeableStream(<RemixServer context={remixContext} url={request.url} abortDelay={ABORT_DELAY} />, {
onAllReady() {
shellRendered = true;
const body = new PassThrough();
const stream = createReadableStreamFromReadable(body);

responseHeaders.set('Content-Type', 'text/html');

resolve(
new Response(stream, {
headers: responseHeaders,
status: responseStatusCode,
})
);

pipe(body);
},
onShellError(error: unknown) {
reject(error);
},
onError(error: unknown) {
responseStatusCode = 500;
// Log streaming rendering errors from inside the shell. Don't log
// errors encountered during initial shell rendering since they'll
// reject and get logged in handleDocumentRequest.
if (shellRendered) {
console.error(error);
}
},
});

setTimeout(abort, ABORT_DELAY);
});
}

function handleBrowserRequest(request: Request, responseStatusCode: number, responseHeaders: Headers, remixContext: EntryContext) {
return new Promise((resolve, reject) => {
let shellRendered = false;
const { pipe, abort } = renderToPipeableStream(<RemixServer context={remixContext} url={request.url} abortDelay={ABORT_DELAY} />, {
onShellReady() {
shellRendered = true;
const body = new PassThrough();
const stream = createReadableStreamFromReadable(body);

responseHeaders.set('Content-Type', 'text/html');

resolve(
new Response(stream, {
headers: responseHeaders,
status: responseStatusCode,
})
);

pipe(body);
},
onShellError(error: unknown) {
reject(error);
},
onError(error: unknown) {
responseStatusCode = 500;
// Log streaming rendering errors from inside the shell. Don't log
// errors encountered during initial shell rendering since they'll
// reject and get logged in handleDocumentRequest.
if (shellRendered) {
console.error(error);
}
},
});

setTimeout(abort, ABORT_DELAY);
});
}
148 changes: 13 additions & 135 deletions app/entry.server.tsx
Original file line number Diff line number Diff line change
@@ -1,140 +1,18 @@
/**
* By default, Remix will handle generating the HTTP Response for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/file-conventions/entry.server
*/
import type { EntryContext } from '@remix-run/node';
import { RemixServer } from '@remix-run/react';
import fs from 'node:fs';
import path from 'node:path';
import { renderToString } from 'react-dom/server';

import { PassThrough } from "node:stream";
export default function handleRequest(request: Request, responseStatusCode: number, responseHeaders: Headers, remixContext: EntryContext) {
const shellHtml = fs.readFileSync(path.join(process.cwd(), 'app/index.html')).toString();

import type { AppLoadContext, EntryContext } from "@remix-run/node";
import { createReadableStreamFromReadable } from "@remix-run/node";
import { RemixServer } from "@remix-run/react";
import { isbot } from "isbot";
import { renderToPipeableStream } from "react-dom/server";
const appHtml = renderToString(<RemixServer context={remixContext} url={request.url} />);

const ABORT_DELAY = 5_000;
const html = shellHtml.replace('<!-- Remix SPA -->', appHtml);

export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
// This is ignored so we can keep it in the template for visibility. Feel
// free to delete this parameter in your app if you're not using it!
// eslint-disable-next-line @typescript-eslint/no-unused-vars
loadContext: AppLoadContext
) {
return isbot(request.headers.get("user-agent") || "")
? handleBotRequest(
request,
responseStatusCode,
responseHeaders,
remixContext
)
: handleBrowserRequest(
request,
responseStatusCode,
responseHeaders,
remixContext
);
}

function handleBotRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
return new Promise((resolve, reject) => {
let shellRendered = false;
const { pipe, abort } = renderToPipeableStream(
<RemixServer
context={remixContext}
url={request.url}
abortDelay={ABORT_DELAY}
/>,
{
onAllReady() {
shellRendered = true;
const body = new PassThrough();
const stream = createReadableStreamFromReadable(body);

responseHeaders.set("Content-Type", "text/html");

resolve(
new Response(stream, {
headers: responseHeaders,
status: responseStatusCode,
})
);

pipe(body);
},
onShellError(error: unknown) {
reject(error);
},
onError(error: unknown) {
responseStatusCode = 500;
// Log streaming rendering errors from inside the shell. Don't log
// errors encountered during initial shell rendering since they'll
// reject and get logged in handleDocumentRequest.
if (shellRendered) {
console.error(error);
}
},
}
);

setTimeout(abort, ABORT_DELAY);
});
}

function handleBrowserRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
return new Promise((resolve, reject) => {
let shellRendered = false;
const { pipe, abort } = renderToPipeableStream(
<RemixServer
context={remixContext}
url={request.url}
abortDelay={ABORT_DELAY}
/>,
{
onShellReady() {
shellRendered = true;
const body = new PassThrough();
const stream = createReadableStreamFromReadable(body);

responseHeaders.set("Content-Type", "text/html");

resolve(
new Response(stream, {
headers: responseHeaders,
status: responseStatusCode,
})
);

pipe(body);
},
onShellError(error: unknown) {
reject(error);
},
onError(error: unknown) {
responseStatusCode = 500;
// Log streaming rendering errors from inside the shell. Don't log
// errors encountered during initial shell rendering since they'll
// reject and get logged in handleDocumentRequest.
if (shellRendered) {
console.error(error);
}
},
}
);

setTimeout(abort, ABORT_DELAY);
});
return new Response(html, {
headers: { 'Content-Type': 'text/html' },
status: responseStatusCode,
});
}
56 changes: 56 additions & 0 deletions app/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<!doctype html>
<html lang="en">
<head>
<title>My Cool App!</title>

<title>Shield</title>
<meta
name="description"
content="Shield delivers a comprehensive solution for Identity and Access Management for modern applications. Built with the fastest and safest programming language to ensure unparalleled security and performance."
/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="robots" content="index, follow" />
<meta name="language" content="English" />
<meta name="author" content="Mukesh Singh" />
<meta
name="keywords"
content="identity, access, management, authentication, authorization, sso, oauth, openid, saml, jwt, iam, auth, security, shield, shield.rs, shield-rs, shield-auth, idp, ciam, identity-access-management, identity-access-management-system, openid-connect, open source auth system"
/>

<meta property="og:title" content="Shield" />
<meta
property="og:description"
content="Shield delivers a comprehensive solution for Identity and Access Management for modern applications. Built with the fastest and safest programming language to ensure unparalleled security and performance."
/>
<meta property="og:image" content="https://www.shield.rs/og-image.png" />
<meta property="og:image:alt" content="Shield preview image" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://www.shield.rs" />
<meta property="og:locale" content="en_US" />
<meta property="og:site_name" content="Shield" />

<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@shield_auth" />
<meta name="twitter:creator" content="@MKSingh_Dev" />
<meta name="twitter:title" content="Shield" />
<meta
name="twitter:description"
content="Shield delivers a comprehensive solution for Identity and Access Management for modern applications. Built with the fastest and safest programming language to ensure unparalleled security and performance."
/>
<meta name="twitter:image" content="https://www.shield.rs/og-image.png" />
<meta name="twitter:image:alt" content="Shield preview image" />

<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="apple-mobile-web-app-title" content="Shield" />

<meta name="theme-color" content="#FF4C00" />

<link rel="canonical" href="https://www.shield.rs" />
</head>
<body>
<div id="app"><!-- Remix SPA --></div>
</body>
</html>
9 changes: 9 additions & 0 deletions app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,12 @@ export function App() {
</html>
);
}

export function HydrateFallback() {
return (
<>
<p>Loading...</p>
<Scripts />
</>
);
}

0 comments on commit 037efa6

Please sign in to comment.