Skip to content
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
7 changes: 7 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,13 @@ jobs:

- name: Build Next.js frontend
run: yarn workspace main build
env:
NODE_ENV: production
NEXT_PUBLIC_ORIGIN: https://ci.learn.mit.edu
NEXT_PUBLIC_MITOL_API_BASE_URL: https://api.ci.learn.mit.edu
NEXT_PUBLIC_CSRF_COOKIE_NAME: cookie-monster
NEXT_PUBLIC_SITE_NAME: MIT Learn
NEXT_PUBLIC_MITOL_SUPPORT_EMAIL: help@ci.learn.mit.edu
# do this before typecheck. See https://github.com/vercel/next.js/issues/53959#issuecomment-1735563224

- name: Typecheck
Expand Down
3 changes: 3 additions & 0 deletions frontends/main/next.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
// @ts-check
const { validateEnv } = require("./validateEnv")

validateEnv()

/** @type {import('next').NextConfig} */
const nextConfig = {
Expand Down
4 changes: 4 additions & 0 deletions frontends/main/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Footer from "@/page-components/Footer/Footer"
import { PageWrapper, PageWrapperInner } from "./styled"
import Providers from "./providers"
import { MITLearnGlobalStyles } from "ol-components"
import Script from "next/script"

import "./GlobalStyles"

Expand All @@ -26,6 +27,9 @@ export default function RootLayout({
</PageWrapper>
</Providers>
</body>
{process.env.NEXT_PUBLIC_APPZI_URL ? (
<Script async src={process.env.NEXT_PUBLIC_APPZI_URL} />
) : null}
</html>
)
}
2 changes: 2 additions & 0 deletions frontends/main/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export async function generateMetadata({
return await getMetadataAsync({
title: "Learn with MIT",
searchParams,
robots:
process.env.MITOL_NOINDEX === "true" ? "noindex, nofollow" : undefined,
})
}

Expand Down
9 changes: 7 additions & 2 deletions frontends/main/src/common/metadata.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { RESOURCE_DRAWER_QUERY_PARAM } from "@/common/urls"
import { learningResourcesApi } from "api/clients"
import type { Metadata } from "next"

const DEFAULT_OG_IMAGE = `${process.env.NEXT_PUBLIC_ORIGIN}/images/opengraph-image.jpg`

Expand All @@ -10,7 +11,7 @@ type MetadataAsyncProps = {
imageAlt?: string
searchParams?: { [key: string]: string | string[] | undefined }
social?: boolean
}
} & Metadata

/*
* Fetch metadata for the current page.
Expand All @@ -23,6 +24,7 @@ export const getMetadataAsync = async ({
imageAlt,
searchParams,
social = true,
...otherMeta
}: MetadataAsyncProps) => {
// The learning resource drawer is open
const learningResourceId = searchParams?.[RESOURCE_DRAWER_QUERY_PARAM]
Expand Down Expand Up @@ -50,6 +52,7 @@ export const getMetadataAsync = async ({
image,
imageAlt,
social,
...otherMeta,
})
}

Expand All @@ -65,7 +68,8 @@ export const standardizeMetadata = ({
image = DEFAULT_OG_IMAGE,
imageAlt,
social = true,
}: MetadataProps) => {
...otherMeta
}: MetadataProps): Metadata => {
title = `${title} | ${process.env.NEXT_PUBLIC_SITE_NAME}`
const socialMetadata = social
? {
Expand Down Expand Up @@ -98,5 +102,6 @@ export const standardizeMetadata = ({
title,
description,
...socialMetadata,
...otherMeta,
}
}
28 changes: 28 additions & 0 deletions frontends/main/validateEnv.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Validate the environment variables we use throughout the app.
*
* This only validates them. It does not transform them (e.g., into a boolean).
* Env vars should still be accessed via process.env.ENV_VAR
*/
// eslint-disable-next-line @typescript-eslint/no-var-requires
const yup = require("yup")

const schema = yup.object().shape({
// Server-only env vars
MITOL_NOINDEX: yup.string().oneOf(["true", "false"]),
// Client or Server env vars
NEXT_PUBLIC_APPZI_URL: yup.string(),
NEXT_PUBLIC_ORIGIN: yup.string().required(),
NEXT_PUBLIC_MITOL_API_BASE_URL: yup.string().required(),
NEXT_PUBLIC_SITE_NAME: yup.string().required(),
NEXT_PUBLIC_MITOL_SUPPORT_EMAIL: yup.string().required(),
NEXT_PUBLIC_EMBEDLY_KEY: yup.string(),
NEXT_PUBLIC_MITOL_AXIOS_WITH_CREDENTIALS: yup
.string()
.oneOf(["true", "false"]),
NEXT_PUBLIC_CSRF_COOKIE_NAME: yup.string().required(),
})

const validateEnv = () => schema.validateSync(process.env)

module.exports = { validateEnv }
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,26 @@
import React from "react"
import { css, Global } from "@emotion/react"
import { theme } from "./ThemeProvider"
import { preload } from "react-dom"

/**
Font files for Adobe neue haas grotesk.
WARNING: This is linked to chudzick@mit.edu's Adobe account.
We'd prefer a non-personal MIT account to be used.
See https://github.com/mitodl/hq/issues/4237 for more.

Ideally the font would be loaded via a <link /> tag; see
- https://nextjs.org/docs/app/api-reference/functions/generate-metadata#unsupported-metadata
- https://github.com/vercel/next.js/discussions/52877
- https://github.com/vercel/next.js/discussions/50796
*/
const ADOBE_FONT_URL = "https://use.typekit.net/lbk1xay.css"

const pageCss = css`
@import url("${ADOBE_FONT_URL}"); /**
@import must come before other styles, including comments
*/

html {
font-family: ${theme.typography.body1.fontFamily};
color: ${theme.typography.body1.color};
Expand Down Expand Up @@ -101,6 +119,11 @@ const muiCss = css`
`

const MITLearnGlobalStyles: React.FC = () => {
/**
* Preload the font just in case emotion doesn't put the import near top of
* HTML.
*/
preload(ADOBE_FONT_URL, { as: "style", fetchPriority: "high" })
return <Global styles={[pageCss, formCss, muiCss]}></Global>
}

Expand Down