Skip to content
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

SEO feedback #664

Merged
merged 7 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 43 additions & 43 deletions blog-website/api/fallback/redirect.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ describe('redirect', () => {
expect(
redirect(
'https://blog.johnnyreilly.com/2013/12/simple-fading-in-and-out-using-css-transitions.html',
mockLogger as unknown as Logger
)
mockLogger as unknown as Logger,
),
).toEqual({
status: 301,
location:
'https://johnnyreilly.com/simple-fading-in-and-out-using-css-transitions',
});

expect(mockLogger.mock.calls[0][0]).toBe(
'x-ms-original-url: https://blog.johnnyreilly.com/2013/12/simple-fading-in-and-out-using-css-transitions.html'
'x-ms-original-url: https://blog.johnnyreilly.com/2013/12/simple-fading-in-and-out-using-css-transitions.html',
);
expect(mockLogger.mock.calls[1][0]).toBe(
'Redirecting https://blog.johnnyreilly.com/2013/12/simple-fading-in-and-out-using-css-transitions.html to https://johnnyreilly.com/simple-fading-in-and-out-using-css-transitions'
'Redirecting https://blog.johnnyreilly.com/2013/12/simple-fading-in-and-out-using-css-transitions.html to https://johnnyreilly.com/simple-fading-in-and-out-using-css-transitions',
);
});

Expand All @@ -32,19 +32,19 @@ describe('redirect', () => {
expect(
redirect(
'https://blog.johnnyreilly.com/2021/01/30/aspnet-serilog-and-application-insights',
mockLogger as unknown as Logger
)
mockLogger as unknown as Logger,
),
).toEqual({
status: 301,
location:
'https://johnnyreilly.com/aspnet-serilog-and-application-insights',
});

expect(mockLogger.mock.calls[0][0]).toBe(
'x-ms-original-url: https://blog.johnnyreilly.com/2021/01/30/aspnet-serilog-and-application-insights'
'x-ms-original-url: https://blog.johnnyreilly.com/2021/01/30/aspnet-serilog-and-application-insights',
);
expect(mockLogger.mock.calls[1][0]).toBe(
'Redirecting https://blog.johnnyreilly.com/2021/01/30/aspnet-serilog-and-application-insights to https://johnnyreilly.com/aspnet-serilog-and-application-insights'
'Redirecting https://blog.johnnyreilly.com/2021/01/30/aspnet-serilog-and-application-insights to https://johnnyreilly.com/aspnet-serilog-and-application-insights',
);
});

Expand All @@ -54,19 +54,19 @@ describe('redirect', () => {
expect(
redirect(
'https://johnnyreilly.com/2013/12/simple-fading-in-and-out-using-css-transitions.html',
mockLogger as unknown as Logger
)
mockLogger as unknown as Logger,
),
).toEqual({
status: 301,
location:
'https://johnnyreilly.com/simple-fading-in-and-out-using-css-transitions',
});

expect(mockLogger.mock.calls[0][0]).toBe(
'x-ms-original-url: https://johnnyreilly.com/2013/12/simple-fading-in-and-out-using-css-transitions.html'
'x-ms-original-url: https://johnnyreilly.com/2013/12/simple-fading-in-and-out-using-css-transitions.html',
);
expect(mockLogger.mock.calls[1][0]).toBe(
'Redirecting https://johnnyreilly.com/2013/12/simple-fading-in-and-out-using-css-transitions.html to https://johnnyreilly.com/simple-fading-in-and-out-using-css-transitions'
'Redirecting https://johnnyreilly.com/2013/12/simple-fading-in-and-out-using-css-transitions.html to https://johnnyreilly.com/simple-fading-in-and-out-using-css-transitions',
);
});

Expand All @@ -76,18 +76,18 @@ describe('redirect', () => {
expect(
redirect(
'https://johnnyreilly.com/feeds/posts/default?alt=rss',
mockLogger as unknown as Logger
)
mockLogger as unknown as Logger,
),
).toEqual({
status: 301,
location: 'https://johnnyreilly.com/rss.xml',
});

expect(mockLogger.mock.calls[0][0]).toBe(
'x-ms-original-url: https://johnnyreilly.com/feeds/posts/default?alt=rss'
'x-ms-original-url: https://johnnyreilly.com/feeds/posts/default?alt=rss',
);
expect(mockLogger.mock.calls[1][0]).toBe(
'Redirecting https://johnnyreilly.com/feeds/posts/default?alt=rss to https://johnnyreilly.com/rss.xml'
'Redirecting https://johnnyreilly.com/feeds/posts/default?alt=rss to https://johnnyreilly.com/rss.xml',
);
});

Expand All @@ -97,18 +97,18 @@ describe('redirect', () => {
expect(
redirect(
'https://johnnyreilly.com/feeds/posts/default',
mockLogger as unknown as Logger
)
mockLogger as unknown as Logger,
),
).toEqual({
status: 301,
location: 'https://johnnyreilly.com/atom.xml',
});

expect(mockLogger.mock.calls[0][0]).toBe(
'x-ms-original-url: https://johnnyreilly.com/feeds/posts/default'
'x-ms-original-url: https://johnnyreilly.com/feeds/posts/default',
);
expect(mockLogger.mock.calls[1][0]).toBe(
'Redirecting https://johnnyreilly.com/feeds/posts/default to https://johnnyreilly.com/atom.xml'
'Redirecting https://johnnyreilly.com/feeds/posts/default to https://johnnyreilly.com/atom.xml',
);
});

Expand All @@ -118,18 +118,18 @@ describe('redirect', () => {
expect(
redirect(
'https://johnnyreilly.com/search/label/uglifyjs',
mockLogger as unknown as Logger
)
mockLogger as unknown as Logger,
),
).toEqual({
status: 301,
location: 'https://johnnyreilly.com/search?q=uglifyjs',
});

expect(mockLogger.mock.calls[0][0]).toBe(
'x-ms-original-url: https://johnnyreilly.com/search/label/uglifyjs'
'x-ms-original-url: https://johnnyreilly.com/search/label/uglifyjs',
);
expect(mockLogger.mock.calls[1][0]).toBe(
'Redirecting https://johnnyreilly.com/search/label/uglifyjs to https://johnnyreilly.com/search?q=uglifyjs'
'Redirecting https://johnnyreilly.com/search/label/uglifyjs to https://johnnyreilly.com/search?q=uglifyjs',
);
});

Expand All @@ -139,18 +139,18 @@ describe('redirect', () => {
expect(
redirect(
'https://johnnyreilly.com/2020/12/',
mockLogger as unknown as Logger
)
mockLogger as unknown as Logger,
),
).toEqual({
status: 301,
location: 'https://johnnyreilly.com/archive',
location: 'https://johnnyreilly.com/blog',
});

expect(mockLogger.mock.calls[0][0]).toBe(
'x-ms-original-url: https://johnnyreilly.com/2020/12/'
'x-ms-original-url: https://johnnyreilly.com/2020/12/',
);
expect(mockLogger.mock.calls[1][0]).toBe(
'Redirecting https://johnnyreilly.com/2020/12/ to https://johnnyreilly.com/archive'
'Redirecting https://johnnyreilly.com/2020/12/ to https://johnnyreilly.com/blog',
);
});

Expand All @@ -160,18 +160,18 @@ describe('redirect', () => {
expect(
redirect(
'https://johnnyreilly.com/2020/',
mockLogger as unknown as Logger
)
mockLogger as unknown as Logger,
),
).toEqual({
status: 301,
location: 'https://johnnyreilly.com/archive',
location: 'https://johnnyreilly.com/blog',
});

expect(mockLogger.mock.calls[0][0]).toBe(
'x-ms-original-url: https://johnnyreilly.com/2020/'
'x-ms-original-url: https://johnnyreilly.com/2020/',
);
expect(mockLogger.mock.calls[1][0]).toBe(
'Redirecting https://johnnyreilly.com/2020/ to https://johnnyreilly.com/archive'
'Redirecting https://johnnyreilly.com/2020/ to https://johnnyreilly.com/blog',
);
});

Expand All @@ -181,19 +181,19 @@ describe('redirect', () => {
expect(
redirect(
'https://johnnyreilly.com/assets/images/robski-dynamic-auth-9ac401590462e2bece9156353b92d187.png',
mockLogger as unknown as Logger
)
mockLogger as unknown as Logger,
),
).toEqual({
status: 301,
location:
'https://johnnyreilly.com/assets/images/robski-dynamic-auth-b50b7efd118b1c8ed1297a010749e0f4.webp',
});

expect(mockLogger.mock.calls[0][0]).toBe(
'x-ms-original-url: https://johnnyreilly.com/assets/images/robski-dynamic-auth-9ac401590462e2bece9156353b92d187.png'
'x-ms-original-url: https://johnnyreilly.com/assets/images/robski-dynamic-auth-9ac401590462e2bece9156353b92d187.png',
);
expect(mockLogger.mock.calls[1][0]).toBe(
'Redirecting https://johnnyreilly.com/assets/images/robski-dynamic-auth-9ac401590462e2bece9156353b92d187.png to https://johnnyreilly.com/assets/images/robski-dynamic-auth-b50b7efd118b1c8ed1297a010749e0f4.webp'
'Redirecting https://johnnyreilly.com/assets/images/robski-dynamic-auth-9ac401590462e2bece9156353b92d187.png to https://johnnyreilly.com/assets/images/robski-dynamic-auth-b50b7efd118b1c8ed1297a010749e0f4.webp',
);
});

Expand All @@ -206,7 +206,7 @@ describe('redirect', () => {
});

expect(mockLogger.mock.calls[0][0]).toBe(
'Redirecting to https://johnnyreilly.com/404 as no explicit redirect exists'
'Redirecting to https://johnnyreilly.com/404 as no explicit redirect exists',
);
});

Expand All @@ -216,19 +216,19 @@ describe('redirect', () => {
expect(
redirect(
'https://johnnyreilly.com/robots.txt',
mockLogger as unknown as Logger
)
mockLogger as unknown as Logger,
),
).toEqual({
status: 302,
location:
'https://johnnyreilly.com/404?originalUrl=https%3A%2F%2Fjohnnyreilly.com%2Frobots.txt',
});

expect(mockLogger.mock.calls[0][0]).toBe(
'x-ms-original-url: https://johnnyreilly.com/robots.txt'
'x-ms-original-url: https://johnnyreilly.com/robots.txt',
);
expect(mockLogger.mock.calls[1][0]).toBe(
'Redirecting https://johnnyreilly.com/robots.txt to https://johnnyreilly.com/404?originalUrl=https%3A%2F%2Fjohnnyreilly.com%2Frobots.txt as no explicit redirect exists'
'Redirecting https://johnnyreilly.com/robots.txt to https://johnnyreilly.com/404?originalUrl=https%3A%2F%2Fjohnnyreilly.com%2Frobots.txt as no explicit redirect exists',
);
});
});
10 changes: 5 additions & 5 deletions blog-website/api/fallback/redirect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export function redirect(originalUrl: string, log: Logger) {
// parsedURL.pathname example: /2019/06/typescript-webpack-you-down-with-pnp.html

const matchedRoute = redirects.find((route) =>
parsedURL.pathname.includes(route.route)
parsedURL.pathname.includes(route.route),
);

if (matchedRoute) {
Expand Down Expand Up @@ -56,7 +56,7 @@ export function redirect(originalUrl: string, log: Logger) {

// cater for https://johnnyreilly.com/2019/06/ or https://johnnyreilly.com/2019/
if (parsedURL.pathname.match(yearMonthRegex)) {
const bloggerArchiveRedirect = '/archive';
const bloggerArchiveRedirect = '/blog';
return redirect301({
log,
originalUrl,
Expand All @@ -68,11 +68,11 @@ export function redirect(originalUrl: string, log: Logger) {
if (parsedURL.pathname.startsWith('/assets/images/')) {
const fileNameWithoutHashAndSuffix = parsedURL.pathname.substring(
0,
parsedURL.pathname.lastIndexOf('-')
parsedURL.pathname.lastIndexOf('-'),
);

const likelyImageRedirect = imagePaths.find((imageFile) =>
imageFile.includes(fileNameWithoutHashAndSuffix)
imageFile.includes(fileNameWithoutHashAndSuffix),
);

if (likelyImageRedirect) {
Expand All @@ -90,7 +90,7 @@ export function redirect(originalUrl: string, log: Logger) {
: `${baseUrl}/404`;

log(
`Redirecting ${originalUrl} to ${location} as no explicit redirect exists`
`Redirecting ${originalUrl} to ${location} as no explicit redirect exists`,
);

return {
Expand Down
6 changes: 5 additions & 1 deletion blog-website/api/fallback/redirectsBacklinks.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export const redirectsBacklinks = [
{
route: '/cache-rules-everything-around-me',
redirect: '/dotnet-imemorycache-getorcreatefortimespanasync'
redirect: '/dotnet-imemorycache-getorcreatefortimespanasync',
},
{
route: '/2019/10/definitely-typed-movie.html',
Expand Down Expand Up @@ -284,4 +284,8 @@ export const redirectsBacklinks = [
route: '/tags/type-script',
redirect: '/tags/typescript',
},
{
route: '/archive',
redirect: '/blog',
},
];
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,18 @@ function App() {
author: {
'@type': 'Person',
name: 'John Reilly',
url: 'https://twitter.com/johnny_reilly',
url: 'https://johnnyreilly.com/about',
},
};

return (
<div className="App">
<script type="application/ld+json">
{JSON.stringify(articleStructuredData)}
</script>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(articleStructuredData),
}}
/>

<h1>{articleStructuredData.headline}</h1>
<h3>
Expand Down Expand Up @@ -135,7 +138,7 @@ export default App;
If we look at the code above, we can see we're creating a JavaScript object literal named `articleStructuredData` which contains the data of an https://schema.org/Article. `articleStructuredData` is then used to do two things:

1. to contribute to the content of the page
2. to render a JSON-LD script tag: `<script type="application/ld+json">` which is populated by calling `JSON.stringify(articleStructuredData)`
2. to render a JSON-LD script tag: `<script type="application/ld+json">` which is populated by calling `JSON.stringify(articleStructuredData)` (You'll note we're using `dangerouslySetInnerHTML` to do this and that's because otherwise the `"` characters in the JSON-LD would be escaped and that would make the JSON-LD invalid to some parsers. The "HTML" we're actually rendering is JSON, and it's safe to render that as HTML because we know it's valid JSON.)

When we run our site locally with `npm start` we see a simple article site that looks like this:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,12 @@ export default function BlogArchivePageWrapper(props) {

return (
<>
<script type="application/ld+json">
{JSON.stringify(breadcrumbStructuredData)}
</script>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(breadcrumbStructuredData),
}}
/>
<BlogArchivePage {...props} />
</>
);
Expand Down Expand Up @@ -176,9 +179,12 @@ export default function BlogPostPageWrapper(props) {

return (
<>
<script type="application/ld+json">
{JSON.stringify(breadcrumbStructuredData)}
</script>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(breadcrumbStructuredData),
}}
/>
<BlogPostPage {...props} />
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,10 @@ export default function FAQStructuredData(props) {
};
return (
<>
<script type="application/ld+json">
{JSON.stringify(faqStructuredData)}
</script>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(faqStructuredData) }}
/>

<h2>FAQs</h2>
{faqStructuredData.mainEntity.map((faq) => (
Expand Down
2 changes: 1 addition & 1 deletion blog-website/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ const config = {
},
*/
{ to: 'about', label: 'About', position: 'left' },
{ to: 'archive', label: 'Blog Archive', position: 'left' },
{ to: 'blog', label: 'Blog', position: 'left' },
{ to: 'talks', label: 'Talks', position: 'left' },
// {
// href: 'https://polywork.johnnyreilly.com/',
Expand Down
Loading