aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2023-12-16 17:31:12 +0100
committerArmand Philippot <git@armandphilippot.com>2023-12-16 19:43:40 +0100
commitbb2f79e09dd4776d611e4751ede1cbb43340fba0 (patch)
treec519128975c5e18c3657858eab2935a230a3228d
parentbc9a120b56494d5502de9619b79594653b8fd6e6 (diff)
fix(build): handle Next.js errors and warnings during build
* extract Blog component from BlogPage (paginated) and extract Article component from ArticlePage to avoid `Cannot read properties` errors due to fallback route * fix sitemap build (cjs not supported) * fix eslint warnings (react/jsx-no-literals) * update `start` script since I'm using standalone output * update `postbuild` script since we need to copy public and static files to standalone directory (Next.js does not handle it itself because we should use a CDN...)
-rw-r--r--.env.example4
-rw-r--r--package.json5
-rw-r--r--src/components/molecules/modals/tooltip/tooltip.tsx2
-rw-r--r--src/components/organisms/forms/search-form/search-form.tsx6
-rw-r--r--src/components/organisms/nav/main-nav/main-nav.tsx13
-rw-r--r--src/pages/_app.tsx1
-rw-r--r--src/pages/article/[slug].tsx19
-rw-r--r--src/pages/blog/page/[number].tsx44
-rw-r--r--yarn.lock33
9 files changed, 97 insertions, 30 deletions
diff --git a/.env.example b/.env.example
index 12ac09a..5f0c62f 100644
--- a/.env.example
+++ b/.env.example
@@ -35,6 +35,10 @@ NEXT_PUBLIC_ACKEE_FILENAME="tracker.js"
NEXT_PUBLIC_ACKEE_SITE_ID="your-id-string"
NEXT_PUBLIC_GITHUB_TOKEN="your-token"
+# Use this if you get an error like "Error: 'sharp' is required to be installed
+# in standalone mode for the image optimization to function correctly."
+#NEXT_SHARP_PATH="node_modules/sharp"
+
# Use this only in development mode. It prevents "unable to verify the first
# certificate" error when using a local domain with mkcert certificate for
# backend.
diff --git a/package.json b/package.json
index b90b656..f1ba943 100644
--- a/package.json
+++ b/package.json
@@ -23,8 +23,8 @@
"dev": "next dev",
"prebuild": "yarn run i18n:compile",
"build": "next build",
- "postbuild": "next-sitemap",
- "start": "next start",
+ "postbuild": "next-sitemap --config next-sitemap.config.cjs && shx cp -r public .next/standalone && shx cp -r .next/static .next/standalone/.next/static",
+ "start": "node .next/standalone/server.js",
"lint": "next lint && yarn run lint:spelling",
"lint:spelling": "cspell \"**\" --no-progress",
"deploy": "sh ./bin/deploy.sh",
@@ -123,6 +123,7 @@
"postcss": "^8.4.32",
"prettier": "^3.1.1",
"sass": "^1.69.5",
+ "shx": "^0.3.4",
"storybook": "^7.6.5",
"storybook-dark-mode": "^3.0.3",
"stylelint": "^16.0.2",
diff --git a/src/components/molecules/modals/tooltip/tooltip.tsx b/src/components/molecules/modals/tooltip/tooltip.tsx
index 525900d..87e9ac8 100644
--- a/src/components/molecules/modals/tooltip/tooltip.tsx
+++ b/src/components/molecules/modals/tooltip/tooltip.tsx
@@ -83,7 +83,9 @@ export const Tooltip: FC<TooltipProps> = ({
{heading}
</Heading>
}
+ // eslint-disable-next-line react/jsx-no-literals
icon={<Icon aria-hidden shape="help" size="sm" />}
+ // eslint-disable-next-line react/jsx-no-literals
kind="secondary"
ref={modalRef}
>
diff --git a/src/components/organisms/forms/search-form/search-form.tsx b/src/components/organisms/forms/search-form/search-form.tsx
index a803d8c..eb4f51d 100644
--- a/src/components/organisms/forms/search-form/search-form.tsx
+++ b/src/components/organisms/forms/search-form/search-form.tsx
@@ -124,7 +124,11 @@ const SearchFormWithRef: ForwardRefRenderFunction<
</Button>
</Form>
{messages?.error && submitStatus === 'FAILED' ? (
- <Notice className={styles.notice} kind="error">
+ <Notice
+ className={styles.notice}
+ // eslint-disable-next-line react/jsx-no-literals
+ kind="error"
+ >
{messages.error}
</Notice>
) : null}
diff --git a/src/components/organisms/nav/main-nav/main-nav.tsx b/src/components/organisms/nav/main-nav/main-nav.tsx
index 5a19399..57d8d6e 100644
--- a/src/components/organisms/nav/main-nav/main-nav.tsx
+++ b/src/components/organisms/nav/main-nav/main-nav.tsx
@@ -28,10 +28,19 @@ const MainNavWithRef: ForwardRefRenderFunction<HTMLElement, MainNavProps> = (
return (
<Nav {...props} className={wrapperClass} ref={ref}>
- <NavList isInline spacing="2xs">
+ <NavList
+ isInline
+ // eslint-disable-next-line react/jsx-no-literals
+ spacing="2xs"
+ >
{items.map(({ id, ...link }) => (
<NavItem key={id}>
- <NavLink {...link} isStack variant="main" />
+ <NavLink
+ {...link}
+ isStack
+ // eslint-disable-next-line react/jsx-no-literals
+ variant="main"
+ />
</NavItem>
))}
</NavList>
diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx
index 525335f..42b3de4 100644
--- a/src/pages/_app.tsx
+++ b/src/pages/_app.tsx
@@ -22,6 +22,7 @@ const App = ({ Component, pageProps }: AppPropsWithLayout) => {
domainId={CONFIG.ackee.siteId}
server={CONFIG.ackee.url}
storageKey={STORAGE_KEY.ACKEE}
+ // eslint-disable-next-line react/jsx-no-literals
tracking="full"
>
<MotionProvider
diff --git a/src/pages/article/[slug].tsx b/src/pages/article/[slug].tsx
index e18de75..ecff692 100644
--- a/src/pages/article/[slug].tsx
+++ b/src/pages/article/[slug].tsx
@@ -3,7 +3,7 @@ import type { ParsedUrlQuery } from 'querystring';
import type { GetStaticPaths, GetStaticProps } from 'next';
import Head from 'next/head';
import { useRouter } from 'next/router';
-import { useCallback } from 'react';
+import { type FC, useCallback } from 'react';
import { useIntl } from 'react-intl';
import {
getLayout,
@@ -60,12 +60,8 @@ type ArticlePageProps = {
translation: Messages;
};
-/**
- * Article page.
- */
-const ArticlePage: NextPageWithLayout<ArticlePageProps> = ({ data }) => {
+const Article: FC<Pick<ArticlePageProps, 'data'>> = ({ data }) => {
const intl = useIntl();
- const { isFallback } = useRouter();
const { article, isLoading } = useArticle(data.post.slug, data.post);
const { comments, isLoading: areCommentsLoading } = useComments({
fallback: data.comments,
@@ -137,7 +133,7 @@ const ArticlePage: NextPageWithLayout<ArticlePageProps> = ({ data }) => {
[]
);
- if (isFallback || isLoading) return <LoadingPage />;
+ if (isLoading) return <LoadingPage />;
const { content, id, intro, meta, slug, title } = article;
const {
@@ -276,6 +272,15 @@ const ArticlePage: NextPageWithLayout<ArticlePageProps> = ({ data }) => {
);
};
+/**
+ * Article page.
+ */
+const ArticlePage: NextPageWithLayout<ArticlePageProps> = ({ data }) => {
+ const { isFallback } = useRouter();
+
+ return isFallback ? <LoadingPage /> : <Article data={data} />;
+};
+
ArticlePage.getLayout = (page) => getLayout(page);
type PostParams = {
diff --git a/src/pages/blog/page/[number].tsx b/src/pages/blog/page/[number].tsx
index fa1123d..e524a64 100644
--- a/src/pages/blog/page/[number].tsx
+++ b/src/pages/blog/page/[number].tsx
@@ -3,7 +3,7 @@ import type { ParsedUrlQuery } from 'querystring';
import type { GetStaticPaths, GetStaticProps } from 'next';
import Head from 'next/head';
import { useRouter } from 'next/router';
-import { useCallback } from 'react';
+import { type FC, useCallback } from 'react';
import { useIntl } from 'react-intl';
import {
getLayout,
@@ -78,23 +78,12 @@ type BlogPageProps = {
translation: Messages;
};
-/**
- * Blog index page.
- */
-const BlogPage: NextPageWithLayout<BlogPageProps> = ({
+const Blog: FC<Pick<BlogPageProps, 'data' | 'lastCursor' | 'pageNumber'>> = ({
data,
lastCursor,
pageNumber,
}) => {
- useRedirection({
- isReplacing: true,
- to: ROUTES.BLOG,
- whenPathMatches: (path) =>
- path === `${ROUTES.BLOG}${PAGINATED_ROUTE_PREFIX}/1`,
- });
-
const intl = useIntl();
- const { isFallback } = useRouter();
const {
articles,
error,
@@ -256,8 +245,6 @@ const BlogPage: NextPageWithLayout<BlogPageProps> = ({
[intl]
);
- if (isFallback) return <LoadingPage />;
-
const pageUrl = `${CONFIG.url}${ROUTES.BLOG}`;
return (
@@ -359,6 +346,30 @@ const BlogPage: NextPageWithLayout<BlogPageProps> = ({
);
};
+/**
+ * Blog index page.
+ */
+const BlogPage: NextPageWithLayout<BlogPageProps> = ({
+ data,
+ lastCursor,
+ pageNumber,
+}) => {
+ useRedirection({
+ isReplacing: true,
+ to: ROUTES.BLOG,
+ whenPathMatches: (path) =>
+ path === `${ROUTES.BLOG}${PAGINATED_ROUTE_PREFIX}/1`,
+ });
+
+ const { isFallback } = useRouter();
+
+ return isFallback ? (
+ <LoadingPage />
+ ) : (
+ <Blog data={data} lastCursor={lastCursor} pageNumber={pageNumber} />
+ );
+};
+
BlogPage.getLayout = (page) => getLayout(page);
type BlogPageParams = {
@@ -414,7 +425,8 @@ export const getStaticPaths: GetStaticPaths = async () => {
{ length: totalPages },
(_, index) => index + 1
);
- const paths = pagesArray.map((number) => {
+ // We remove /blog/page/1 since it is redirected to /blog
+ const paths = pagesArray.slice(1).map((number) => {
return { params: { number: `${number}` } };
});
diff --git a/yarn.lock b/yarn.lock
index fb98318..9a1c0d0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8747,7 +8747,7 @@ glob@^10.0.0:
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
path-scurry "^1.10.1"
-glob@^7.1.3, glob@^7.1.4:
+glob@^7.0.0, glob@^7.1.3, glob@^7.1.4:
version "7.2.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
@@ -9441,6 +9441,11 @@ internal-slot@^1.0.4, internal-slot@^1.0.5:
hasown "^2.0.0"
side-channel "^1.0.4"
+interpret@^1.0.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
+ integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
+
intl-messageformat@10.5.8:
version "10.5.8"
resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.5.8.tgz#7184da425f360a53a5483a6194e16d666b011fc0"
@@ -12992,6 +12997,13 @@ recast@^0.23.1, recast@^0.23.3:
source-map "~0.6.1"
tslib "^2.0.1"
+rechoir@^0.6.2:
+ version "0.6.2"
+ resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
+ integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==
+ dependencies:
+ resolve "^1.1.6"
+
redent@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f"
@@ -13240,7 +13252,7 @@ resolve.exports@^2.0.0:
resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800"
integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==
-resolve@^1.10.0, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.22.1, resolve@^1.22.4:
+resolve@^1.1.6, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.22.1, resolve@^1.22.4:
version "1.22.8"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d"
integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
@@ -13578,6 +13590,23 @@ shebang-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
+shelljs@^0.8.5:
+ version "0.8.5"
+ resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c"
+ integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==
+ dependencies:
+ glob "^7.0.0"
+ interpret "^1.0.0"
+ rechoir "^0.6.2"
+
+shx@^0.3.4:
+ version "0.3.4"
+ resolved "https://registry.yarnpkg.com/shx/-/shx-0.3.4.tgz#74289230b4b663979167f94e1935901406e40f02"
+ integrity sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==
+ dependencies:
+ minimist "^1.2.3"
+ shelljs "^0.8.5"
+
side-channel@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"