Skip to content

Commit

Permalink
feat: Upgrade Next.js to v15 and React to v19 in storefront (#95)
Browse files Browse the repository at this point in the history
  • Loading branch information
karolkarolka committed Nov 29, 2024
1 parent 6700dd3 commit 173a78f
Show file tree
Hide file tree
Showing 81 changed files with 3,295 additions and 1,216 deletions.
21 changes: 8 additions & 13 deletions apps/storefront/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,15 @@ interface Set<T> {
}

declare module "*.svg" {
const ReactComponent: React.FC<React.SVGProps<SVGSVGElement>>;
const content: string;
import { type FC, type SVGProps } from "react";
const content: FC<SVGProps<SVGElement>>;

export default content;
}

declare module "*.svg?url" {
const content: any;

export { ReactComponent };
export default content;
}

Expand All @@ -70,13 +75,3 @@ declare global {
interface NextFetchRequestConfig {
tags?: RevalidateTag[];
}

type NextPageProps<
TParams extends Record<string, string> = {},
TSearchParams extends Record<string, string> = {},
> = {
params: {
locale: "en" | "de";
} & TParams;
searchParams: TSearchParams;
};
65 changes: 32 additions & 33 deletions apps/storefront/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ const nextConfig = withNextIntl({
},
},
experimental: {
instrumentationHook: true,
serverComponentsExternalPackages: ["pino"],
},
images: {
Expand All @@ -55,41 +54,41 @@ const nextConfig = withNextIntl({
if (isServer) {
config.ignoreWarnings = [{ module: /opentelemetry/ }];
}
config.module.rules.push({
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: "@svgr/webpack",
options: {
prettier: true,
svgo: true,
svgoConfig: {
plugins: [
{
name: "preset-default",
cleanupIDs: false,
convertShapeToPath: false,
removeDimensions: true,
removeViewBox: false,
removeXMLNS: true,
},
],
},
},
},
{
loader: "file-loader",
options: {
name: "[name].[ext]",
outputPath: "static/images/",
publicPath: "/_next/static/images/",
},
},
],
});
const fileLoaderRule = config.module.rules.find((rule) =>
rule.test?.test?.(".svg"),
);

config.module.rules.push(
// Reapply the existing rule, but only for svg imports ending in ?url
{
...fileLoaderRule,
test: /\.svg$/i,
resourceQuery: /url/, // *.svg?url
},
// Convert all other *.svg imports to React components
{
test: /\.svg$/i,
issuer: fileLoaderRule.issuer,
resourceQuery: { not: [...fileLoaderRule.resourceQuery.not, /url/] }, // exclude if *.svg?url
use: ["@svgr/webpack"],
},
);

// Modify the file loader rule to ignore *.svg, since we have it handled now.
fileLoaderRule.exclude = /\.svg$/i;

return config;
},
experimental: {
turbo: {
rules: {
"*.svg": {
loaders: ["@svgr/webpack"],
as: "*.js",
},
},
},
},
});

const configWithSentry = withSentryConfig(nextConfig, {
Expand Down
27 changes: 17 additions & 10 deletions apps/storefront/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"type": "module",
"scripts": {
"dev": "next dev",
"dev": "next dev --turbopack",
"dev:inspect": "NODE_OPTIONS='--inspect' next dev",
"build": "next build",
"start": "next start",
Expand All @@ -23,30 +23,31 @@
"@vercel/otel": "^1.9.1",
"clsx": "2.0.0",
"editorjs-html": "3.4.3",
"eslint-config-next": "15.0.3",
"jose": "^5.2.2",
"js-cookie": "3.0.5",
"lodash": "4.17.21",
"lucide-react": "^0.368.0",
"next": "14.2.12",
"next": "15.0.3",
"next-auth": "5.0.0-beta.17",
"next-intl": "3.19.3",
"next-intl": "3.23.5",
"nextjs-routes": "2.1.0",
"react": "18.3.1",
"react-dom": "18.3.1",
"react": "19.0.0-rc.1",
"react-dom": "19.0.0-rc.1",
"react-error-boundary": "4.0.13",
"react-hook-form": "7.51.5",
"react-hook-form": "7.53.2",
"schema-dts": "1.1.2",
"tailwind-merge": "2.0.0",
"tailwindcss-animate": "1.0.7",
"ts-import": "5.0.0-beta.0",
"ts-invariant": "0.10.3",
"usehooks-ts": "2.13.0",
"xss": "1.0.15",
"zod": "^3.22.4"
"zod": "^3.23.8"
},
"devDependencies": {
"@graphql-typed-document-node/core": "3.2.0",
"@next/env": "14.2.5",
"@next/env": "15.0.3",
"@nimara/codegen": "workspace:*",
"@nimara/config": "workspace:*",
"@nimara/domain": "workspace:*",
Expand All @@ -57,8 +58,8 @@
"@types/js-cookie": "3.0.6",
"@types/lodash": "4.17.7",
"@types/node": "20.14.12",
"@types/react": "18.3.3",
"@types/react-dom": "18.3.0",
"@types/react": "npm:[email protected]",
"@types/react-dom": "npm:[email protected]",
"@typescript-eslint/eslint-plugin": "^6.12.0",
"@typescript-eslint/parser": "^6.12.0",
"autoprefixer": "10.4.20",
Expand All @@ -81,5 +82,11 @@
},
"engines": {
"node": "^20"
},
"pnpm": {
"overrides": {
"@types/react": "npm:[email protected]",
"@types/react-dom": "npm:[email protected]"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ import { getTranslations } from "next-intl/server";
import { paths } from "@/lib/paths";
import { authService } from "@/services";

export default async function ConfirmAccountRegistrationPage({
searchParams,
}: {
searchParams?: Record<"email" | "token", string>;
export default async function ConfirmAccountRegistrationPage(props: {
searchParams?: Promise<Record<"email" | "token", string>>;
}) {
const searchParams = await props.searchParams;
const t = await getTranslations();
const email = searchParams?.email;
const token = searchParams?.token;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ import { paths } from "@/lib/paths";
import { getCurrentRegion } from "@/regions/server";
import { userService } from "@/services";

export default async function ConfirmEmailChangePage({
searchParams,
}: {
searchParams?: Record<string, string>;
export default async function ConfirmEmailChangePage(props: {
searchParams?: Promise<Record<string, string>>;
}) {
const searchParams = await props.searchParams;
const token = searchParams?.token ?? "";
const accessToken = getAccessToken();
const accessToken = await getAccessToken();

const [region, t] = await Promise.all([
getCurrentRegion(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export async function registerAccount(values: FormSchema) {
languageCode: region?.language?.code,
redirectUrl: new URL(
paths.confirmAccountRegistration.asPath(),
getStoreUrl(),
await getStoreUrl(),
).toString(),
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@ export async function generateMetadata() {
};
}

export default async function SignUpPage({
searchParams,
}: {
searchParams?: Record<string, string>;
export default async function SignUpPage(props: {
searchParams?: Promise<Record<string, string>>;
}) {
const searchParams = await props.searchParams;
const t = await getTranslations();

const isSuccess = searchParams?.success === "true";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { paths } from "@/lib/paths";
import { userService } from "@/services";

export async function deleteUserAccount(token: string) {
const accessToken = getAccessToken();
const accessToken = await getAccessToken();

if (accessToken) {
const data = await userService.accountDelete({ accessToken, token });
Expand Down
10 changes: 4 additions & 6 deletions apps/storefront/src/app/[locale]/(auth)/delete-account/page.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
"use client";

import { useSearchParams } from "next/navigation";
import { useEffect } from "react";

import { Spinner } from "@nimara/ui/components/spinner";

import { deleteUserAccount } from "./actions";

export default function ConfirmAccountDeletionPage({
searchParams,
}: {
searchParams?: Record<string, string>;
}) {
const token = searchParams?.token ?? "";
export default function ConfirmAccountDeletionPage() {
const searchParams = useSearchParams();
const token = searchParams.get("token") ?? "";

// INFO: Cookies cannot be set during the render because of
// the e.g. streaming issues. Do not rewrite the component to RSC.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { authService } from "@/services";
import { type FormSchema } from "./schema";

export async function setPassword({ password }: FormSchema) {
const searchParams = new URL(headers().get("referer")!).searchParams;
const searchParams = new URL((await headers()).get("referer")!).searchParams;
const email = searchParams.get("email") ?? "";
const token = searchParams.get("token") ?? "";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import { ShippingAddressSection } from "../../_sections/shipping-address-section
import { DeliveryMethodForm } from "./form";

export default async function Page() {
const checkoutId = cookies().get(COOKIE_KEY.checkoutId)?.value;
const checkoutId = (await cookies()).get(COOKIE_KEY.checkoutId)?.value;

const accessToken = getAccessToken();
const accessToken = await getAccessToken();

const region = await getCurrentRegion();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export async function updateBillingAddress({
"sameAsShippingAddress" | "billingAddress" | "saveAddressForFutureUse"
>;
}) {
const accessToken = getAccessToken();
const accessToken = await getAccessToken();

const data = await updateCheckoutAddressAction({
checkoutId: checkout.id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ import { Payment } from "./payment";

export const runtime = "nodejs";

export default async function Page({
searchParams,
}: NextPageProps<{}, { country?: CountryCode; errorCode?: string }>) {
type SearchParams = Promise<{ country?: CountryCode; errorCode?: string }>;

export default async function Page(props: { searchParams: SearchParams }) {
const searchParams = await props.searchParams;
const checkout = await getCheckoutOrRedirect();

if (checkout?.problems.insufficientStock.length) {
Expand All @@ -32,7 +33,7 @@ export default async function Page({

const marketCountryCode = region.market.countryCode;

const storeUrl = getStoreUrl();
const storeUrl = await getStoreUrl();

const { countries } = await addressService.countriesGet({
channelSlug: region.market.channel,
Expand Down Expand Up @@ -61,7 +62,7 @@ export default async function Page({
return paramsCountryCode;
})() as CountryCode;

const accessToken = getAccessToken();
const accessToken = await getAccessToken();

const user = await userService.userGet(accessToken);
const [addresses, { addressFormRows }] = await Promise.all([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export async function updateShippingAddress({
id: string;
input: FormSchema;
}) {
const accessToken = getAccessToken();
const accessToken = await getAccessToken();

const data = await userService.accountAddressUpdate({
accessToken,
Expand All @@ -40,7 +40,7 @@ export async function createCheckoutShippingAddress({
checkoutId: Checkout["id"];
input: FormSchema;
}) {
const accessToken = getAccessToken();
const accessToken = await getAccessToken();

const data = await updateCheckoutAddressAction({
checkoutId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ import { PaymentSection } from "../../_sections/payment-section";
import { ShippingAddressForm } from "./_forms/guest-form";
import { AddressTab } from "./_tabs/address-tab";

export default async function Page({
searchParams,
}: NextPageProps<{}, { country?: CountryCode }>) {
const checkoutId = cookies().get(COOKIE_KEY.checkoutId)?.value;
const accessToken = getAccessToken();
type SearchParams = Promise<{ country?: CountryCode }>;

export default async function Page(props: { searchParams: SearchParams }) {
const searchParams = await props.searchParams;
const checkoutId = (await cookies()).get(COOKIE_KEY.checkoutId)?.value;
const accessToken = await getAccessToken();

const region = await getCurrentRegion();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ import { ShippingAddressSection } from "../../_sections/shipping-address-section
import { UserDetailsForm } from "./form";

export default async function Page() {
const checkoutId = cookies().get(COOKIE_KEY.checkoutId)?.value;
const checkoutId = (await cookies()).get(COOKIE_KEY.checkoutId)?.value;

const region = await getCurrentRegion();

if (!checkoutId) {
redirect(paths.cart.asPath());
}

const accessToken = getAccessToken();
const accessToken = await getAccessToken();

const [{ checkout }, user] = await Promise.all([
checkoutService.checkoutGet({
Expand Down
Loading

0 comments on commit 173a78f

Please sign in to comment.