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

Next.js + Vercel! ▲ #1

Draft
wants to merge 48 commits into
base: latest
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
8917b5d
Installs Next.js, removes Babel, configures Emotion (what Simorgh use…
manovotny Aug 5, 2022
b918444
Fixes lint errors.
manovotny Aug 5, 2022
245e395
Attempting to fix import aliases.
manovotny Aug 5, 2022
2d90607
Adds custom webpack moment timezone config.
manovotny Aug 5, 2022
c9ff0a9
Missed asterisks. 🤦‍♂️
manovotny Aug 5, 2022
6eba7bb
Ignoring lint on build (at least for now).
manovotny Aug 5, 2022
8775285
Starts to wire things up, largely based on setting up React Context i…
manovotny Aug 9, 2022
eb4b6fd
RENDERING!!!
manovotny Aug 10, 2022
5d255a3
Filters page data.
manovotny Aug 10, 2022
d903cb0
Fixes missing `tz` (moment timezone) data at build time.
manovotny Aug 10, 2022
cd2a576
Changes hardcoded `/news` to dynamic service.
manovotny Aug 10, 2022
b2bd31e
Swaps `getServerSideProps` for `getStaticPaths` and `getStaticProps`.
manovotny Aug 11, 2022
97f7432
Inlines front page filtering.
manovotny Aug 12, 2022
165e4e3
Adds most read section.
manovotny Aug 12, 2022
1b223e4
Adds article route / page.
manovotny Aug 13, 2022
80dfa76
Comments out unused `OptimizelyPageViewTracking` import.
manovotny Aug 13, 2022
ba2a0ed
Fixes `manifest.json` error.
manovotny Aug 13, 2022
52fef75
Removes react-helmet.
manovotny Aug 13, 2022
cc7b0b9
Fixes `pathname` undefined.
manovotny Aug 13, 2022
55bc771
Fixes WebVitals error.
manovotny Aug 14, 2022
a896926
Fixes `mostRead` prop types error.
manovotny Aug 14, 2022
5de5fb4
Updates client environment variables.
manovotny Aug 15, 2022
5bacb15
Fixes prop type error.
manovotny Aug 15, 2022
8f5bc94
Fixes article data errors due to missing filters.
manovotny Aug 15, 2022
5431714
Adds `pageType` to page routes.
manovotny Aug 15, 2022
6128a03
Updates scripts to use next/script.
manovotny Aug 15, 2022
f418e99
Fixes toggles.
manovotny Aug 16, 2022
0831d7f
Creates fake api.
manovotny Aug 16, 2022
7c851d7
Changes logger to noop.
manovotny Aug 16, 2022
cb6b004
Cleans up scripts.
manovotny Aug 16, 2022
ba19ae5
Removes helmet dependency.
manovotny Aug 16, 2022
fe51f71
Removes react-router.
manovotny Aug 16, 2022
75b33a1
Removes webpack dependencies.
manovotny Aug 16, 2022
b597af4
Removes babel dependencies.
manovotny Aug 16, 2022
9edee97
Removes express dependencies.
manovotny Aug 16, 2022
ba9fe1b
Removes isomorphic-fetch.
manovotny Aug 16, 2022
05ba343
Removes dotenv.
manovotny Aug 16, 2022
71c9f66
Removes unnecessary files.
manovotny Aug 16, 2022
c8311b7
Moves statusCode to fake API and handles error page.
manovotny Aug 17, 2022
1b0a2ea
Fixes dangling comma in template literal script code.
manovotny Aug 18, 2022
3c36090
Fixes adcampaign.
manovotny Aug 18, 2022
7d80311
Fixes Optimizely.
manovotny Aug 19, 2022
c7d1914
Removes SWR.
manovotny Aug 20, 2022
2aeb8e4
Removes webpack scripts.
manovotny Aug 23, 2022
483c5b9
Uses `withOptimizelyProvider` HOC on ArticlePage instead.
manovotny Aug 23, 2022
fe685bf
Moves environment variables to Vercel.
manovotny Aug 23, 2022
5441a38
Fixes `manifest.json` link...again.
manovotny Aug 23, 2022
bee1f79
Adds a custom `_document.js` to handle dynamic `dir` and `lang` HTML …
manovotny Aug 23, 2022
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
77 changes: 0 additions & 77 deletions .babelrc.js

This file was deleted.

4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@ yarn-error.log
!.yarn/sdks
!.yarn/versions
secret.env
tsconfig.tsbuildinfo
tsconfig.tsbuildinfo
.next
.vercel
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v12.18.4
14
Copy link
Collaborator Author

@manovotny manovotny Aug 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The move to Next.js didn't require this. Running anything below Node 14 is painful on an M1 Mac, so it was bumped up.

6 changes: 3 additions & 3 deletions .storybook/helpers/ampDecorator/index.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { Helmet } from 'react-helmet';
import Head from 'next/head';
import {
AMP_SCRIPT,
AMP_NO_SCRIPT,
Expand All @@ -15,7 +15,7 @@ import {

const AmpDecorator = storyFn => (
<div>
<Helmet htmlAttributes={{ amp: '' }}>
<Head>
<link rel="canonical" href="http://foobar.com" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,minimum-scale=1" />
Expand All @@ -25,7 +25,7 @@ const AmpDecorator = storyFn => (
{AMP_GEO_JS}
{AMP_CONSENT_JS}
{AMP_ANALYTICS_JS}
</Helmet>
</Head>
{storyFn()}
</div>
);
Expand Down
32 changes: 0 additions & 32 deletions envConfig/live.env

This file was deleted.

32 changes: 0 additions & 32 deletions envConfig/local.env

This file was deleted.

32 changes: 0 additions & 32 deletions envConfig/test.env

This file was deleted.

153 changes: 153 additions & 0 deletions lib/fake-bbc-api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import path from 'node:path';
import fs from 'node:fs/promises';
import glob from 'glob';
import { ARTICLE_PAGE, FRONT_PAGE } from '#app/routes/utils/pageTypes';
import getToggles from '#lib/utilities/getToggles';
import filterUnknownContentTypes from '#app/routes/utils/sharedDataTransformers/filterUnknownContentTypes';
import filterEmptyGroupItems from '#app/routes/utils/sharedDataTransformers/filterEmptyGroupItems';
import squashTopStories from '#app/routes/utils/sharedDataTransformers/squashTopStories';
import addIdsToGroups from '#app/routes/utils/sharedDataTransformers/addIdsToGroups';
import filterGroupsWithoutStraplines from '#app/routes/utils/sharedDataTransformers/filterGroupsWithoutStraplines';
import handleGroupBlocks from '#app/routes/article/handleGroupBlocks';
import handleEmptyParagraphBlocks from '#app/routes/article/handleEmptyParagraphBlocks';
import handlePromoData from '#app/routes/article/handlePromoData';
import addMpuBlock from '#app/routes/article/getInitialData/addMpuBlock';
import {
augmentWithTimestamp,
addIdsToBlocks,
applyBlockPositioning,
addIndexesToEmbeds,
addNoCookieToEmbeds,
} from '#app/routes/utils/sharedDataTransformers';
import isListWithLink from '#app/routes/utils/isListWithLink';
import addIndexToBlockGroups from '#app/routes/utils/sharedDataTransformers/addIndexToBlockGroups';

const getLanguageAndDirection = async s => {
const { service } = await import(`#lib/config/services/${s}`);
const { dir, lang } = service.default;

return {
dir,
lang,
};
};

const getServices = () =>
glob
.sync(`./data/**/frontpage/index.json`)
.map(result => result.split('/')[2]);

const getServicePath = service => path.join(process.cwd(), 'data', service);

const getMostRead = async service => {
let mostRead = {};

const servicePath = getServicePath(service);
const mostReadPath = path.join(servicePath, 'mostRead', 'index.json');

try {
mostRead = JSON.parse(await fs.readFile(mostReadPath, 'utf-8'));
} catch {}

return mostRead;
};

const getFrontPageProps = async service => {
const servicePath = getServicePath(service);
const pageDataPath = path.join(servicePath, 'frontpage', 'index.json');

let pageData = {};

try {
pageData = JSON.parse(await fs.readFile(pageDataPath, 'utf-8'));
pageData = filterUnknownContentTypes(pageData);
pageData = filterEmptyGroupItems(pageData);
pageData = addIdsToGroups(pageData);
pageData = squashTopStories(pageData);
pageData = filterGroupsWithoutStraplines(pageData);
} catch {
return {
pageType: FRONT_PAGE,
service,
statusCode: 404,
};
}

const mostRead = await getMostRead(service);
const toggles = await getToggles(service);
const { dir, lang } = await getLanguageAndDirection(service);

return {
dir,
lang,
pageData,
pageType: FRONT_PAGE,
mostRead,
service,
statusCode: 200,
toggles,
};
};

const getArticlePageProps = async (service, articleId) => {
const servicePath = getServicePath(service);
const pageDataPath = path.join(servicePath, 'articles', `${articleId}.json`);

let pageData = {};

try {
pageData = JSON.parse(await fs.readFile(pageDataPath, 'utf-8'));
pageData = handleGroupBlocks(pageData);
pageData = handleEmptyParagraphBlocks(pageData);
pageData = handlePromoData(pageData);
pageData = augmentWithTimestamp(pageData);
pageData = addMpuBlock(pageData);
pageData = addNoCookieToEmbeds(pageData);
pageData = addIdsToBlocks(pageData);
pageData = applyBlockPositioning(pageData);
pageData = addIndexesToEmbeds(pageData);
pageData = addIndexToBlockGroups(isListWithLink, {
blockGroupType: 'edOjLinks',
})(pageData);
} catch {
return {
pageType: ARTICLE_PAGE,
service,
statusCode: 404,
};
}

let secondaryColumn = {};

try {
const secondaryColumnPath = path.join(
servicePath,
'secondaryColumn',
'index.json',
);

secondaryColumn = JSON.parse(
await fs.readFile(secondaryColumnPath, 'utf-8'),
);
} catch {}

const mostRead = await getMostRead(service);
const toggles = await getToggles(service);
const { dir, lang } = await getLanguageAndDirection(service);

return {
dir,
lang,
pageData: {
...pageData,
secondaryColumn,
},
pageType: ARTICLE_PAGE,
mostRead,
service,
statusCode: 200,
toggles,
};
};

export { getArticlePageProps, getFrontPageProps, getServices };
5 changes: 5 additions & 0 deletions next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
24 changes: 24 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const { webpackDirAlias } = require('./dirAlias');
const MomentTimezoneInclude = require('./src/app/legacy/psammead/moment-timezone-include/src');

module.exports = {
reactStrictMode: true,
compiler: {
emotion: true,
},
eslint: {
ignoreDuringBuilds: true,
},
webpack: config => {
config.resolve.alias = {
...webpackDirAlias,
...config.resolve.alias,
};

config.plugins.push(
new MomentTimezoneInclude({ startYear: 2010, endYear: 2025 }),
);

return config;
},
};
Copy link
Collaborator Author

@manovotny manovotny Aug 19, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know we wanted to do as little custom configuration here as possible, but there's a few things going on here that are unavoidable without massive changes to the project.

  1. Simorgh uses Emotion for styling, so that needs to be enabled.
  2. Simorgh uses custom import aliases (ie. import ArticlePage from '#pages/ArticlePage/ArticlePage') to avoid dot pathing everything, so the Webpack config is enhanced to accommodate this.
  3. MomentTimezoneInclude is a custom Webpack plugin written by the SImorgh team to limit the size of timezones included to reduce bundle size.
  4. And MomentTimezoneInclude is why we need to disable lint during builds. It's a cyclical problem. We need Webpack to build the app, so the custom MomentTimezoneInclude runs to create the tz directory with the outputted timezones that are imported by other files, but we cannot build the app until it passes lint because imports fail to find tz files. This existing process would need to be modified to run before lint and before build (possibly as a separate script).

Loading