From e6a4bf4f9f34af49c41bb3cbe8ed69d34023eea2 Mon Sep 17 00:00:00 2001 From: Leo McArdle Date: Wed, 8 Jan 2025 12:05:36 +0000 Subject: [PATCH] chore(lit): move into separate folder and make tsconfig stricter (#12398) --- client/src/about/index.tsx | 2 +- client/src/community/index.tsx | 2 +- client/src/curriculum/landing.tsx | 2 +- client/src/curriculum/module.tsx | 2 +- .../custom-elements.js => lit/about.js} | 0 .../{ => lit}/community/contributor-list.js | 0 .../{ => lit}/community/contributor-list.scss | 2 +- client/src/{ => lit}/community/types.d.ts | 0 .../curriculum/scrim-inline.global.css | 2 +- .../src/{ => lit}/curriculum/scrim-inline.js | 6 +- .../{ => lit}/curriculum/scrim-inline.scss | 12 +- client/src/lit/globals.d.ts | 14 ++ client/src/lit/modules.d.ts | 12 ++ .../src/{playground => lit/play}/console.js | 0 .../src/{playground => lit/play}/console.scss | 0 .../src/{playground => lit/play}/types.d.ts | 0 client/src/lit/tsconfig.json | 30 +++++ client/src/playground/index.tsx | 4 +- .../plus/collections/frequently-viewed.tsx | 21 +-- client/src/react-app.d.ts | 36 ------ client/src/settings/mdn-worker.tsx | 2 +- client/src/telemetry/glean-context.tsx | 13 +- client/src/user-context.tsx | 4 +- client/tsconfig.json | 8 +- server/react-app.d.ts | 91 ------------- ssr/modules.d.ts | 9 ++ ssr/react-app.d.ts | 122 ------------------ ssr/tsconfig.json | 2 +- 28 files changed, 109 insertions(+), 289 deletions(-) rename client/src/{about/custom-elements.js => lit/about.js} (100%) rename client/src/{ => lit}/community/contributor-list.js (100%) rename client/src/{ => lit}/community/contributor-list.scss (99%) rename client/src/{ => lit}/community/types.d.ts (100%) rename client/src/{ => lit}/curriculum/scrim-inline.global.css (65%) rename client/src/{ => lit}/curriculum/scrim-inline.js (96%) rename client/src/{ => lit}/curriculum/scrim-inline.scss (88%) create mode 100644 client/src/lit/globals.d.ts create mode 100644 client/src/lit/modules.d.ts rename client/src/{playground => lit/play}/console.js (100%) rename client/src/{playground => lit/play}/console.scss (100%) rename client/src/{playground => lit/play}/types.d.ts (100%) create mode 100644 client/src/lit/tsconfig.json delete mode 100644 server/react-app.d.ts create mode 100644 ssr/modules.d.ts delete mode 100644 ssr/react-app.d.ts diff --git a/client/src/about/index.tsx b/client/src/about/index.tsx index 92055d8c82f2..3c5ae1b1785a 100644 --- a/client/src/about/index.tsx +++ b/client/src/about/index.tsx @@ -7,7 +7,7 @@ import { WRITER_MODE } from "../env"; import { Prose } from "../document/ingredients/prose"; import "./index.scss"; -import "./custom-elements"; +import "../lit/about"; import { useGleanClick } from "../telemetry/glean-context"; import { ABOUT } from "../telemetry/constants"; diff --git a/client/src/community/index.tsx b/client/src/community/index.tsx index e2290d123a52..37af5b68c086 100644 --- a/client/src/community/index.tsx +++ b/client/src/community/index.tsx @@ -11,7 +11,7 @@ export function Community(appProps: HydrationData) { const doc = useAboutDoc(appProps); useEffect(() => { - import("./contributor-list"); + import("../lit/community/contributor-list"); }, []); return ( diff --git a/client/src/curriculum/landing.tsx b/client/src/curriculum/landing.tsx index bc3cbd5c96bd..9b60e447a671 100644 --- a/client/src/curriculum/landing.tsx +++ b/client/src/curriculum/landing.tsx @@ -20,7 +20,7 @@ import scrimBg from "../assets/curriculum/landing-scrim.png"; import { useGleanClick } from "../telemetry/glean-context"; import { CURRICULUM } from "../telemetry/constants"; -const ScrimInline = lazy(() => import("./scrim-inline")); +const ScrimInline = lazy(() => import("../lit/curriculum/scrim-inline")); export function CurriculumLanding(appProps: HydrationData) { const doc = useCurriculumDoc(appProps as CurriculumData); diff --git a/client/src/curriculum/module.tsx b/client/src/curriculum/module.tsx index 07cf874ad478..3804dedfbf2b 100644 --- a/client/src/curriculum/module.tsx +++ b/client/src/curriculum/module.tsx @@ -14,7 +14,7 @@ export function CurriculumModule(props: HydrationData) { const doc = useCurriculumDoc(props as CurriculumData); useEffect(() => { - import("./scrim-inline"); + import("../lit/curriculum/scrim-inline"); }, []); return ( diff --git a/client/src/about/custom-elements.js b/client/src/lit/about.js similarity index 100% rename from client/src/about/custom-elements.js rename to client/src/lit/about.js diff --git a/client/src/community/contributor-list.js b/client/src/lit/community/contributor-list.js similarity index 100% rename from client/src/community/contributor-list.js rename to client/src/lit/community/contributor-list.js diff --git a/client/src/community/contributor-list.scss b/client/src/lit/community/contributor-list.scss similarity index 99% rename from client/src/community/contributor-list.scss rename to client/src/lit/community/contributor-list.scss index 232d5e7a6949..e2d6b20c81d6 100644 --- a/client/src/community/contributor-list.scss +++ b/client/src/lit/community/contributor-list.scss @@ -1,4 +1,4 @@ -@use "../ui/vars" as *; +@use "../../ui/vars" as *; * { box-sizing: border-box; diff --git a/client/src/community/types.d.ts b/client/src/lit/community/types.d.ts similarity index 100% rename from client/src/community/types.d.ts rename to client/src/lit/community/types.d.ts diff --git a/client/src/curriculum/scrim-inline.global.css b/client/src/lit/curriculum/scrim-inline.global.css similarity index 65% rename from client/src/curriculum/scrim-inline.global.css rename to client/src/lit/curriculum/scrim-inline.global.css index ac55e7fa316a..716a41ddcec5 100644 --- a/client/src/curriculum/scrim-inline.global.css +++ b/client/src/lit/curriculum/scrim-inline.global.css @@ -4,5 +4,5 @@ font-display: block; src: local("BarlowCondensed-SemiBold"), - url("../assets/fonts/BarlowCondensed-SemiBold.woff2") format("woff2"); + url("../../assets/fonts/BarlowCondensed-SemiBold.woff2") format("woff2"); } diff --git a/client/src/curriculum/scrim-inline.js b/client/src/lit/curriculum/scrim-inline.js similarity index 96% rename from client/src/curriculum/scrim-inline.js rename to client/src/lit/curriculum/scrim-inline.js index 894e7d529599..2340ba55746c 100644 --- a/client/src/curriculum/scrim-inline.js +++ b/client/src/lit/curriculum/scrim-inline.js @@ -4,13 +4,13 @@ import { styleMap } from "lit/directives/style-map.js"; import { ifDefined } from "lit/directives/if-defined.js"; import { createComponent } from "@lit/react"; import React from "react"; -import { CURRICULUM } from "../telemetry/constants.ts"; +import { CURRICULUM } from "../../telemetry/constants.ts"; import "./scrim-inline.global.css"; import styles from "./scrim-inline.scss?css" with { type: "css" }; -import playSvg from "../assets/curriculum/scrim-play.svg?raw"; +import playSvg from "../../assets/curriculum/scrim-play.svg?raw"; -class ScrimInline extends LitElement { +export class ScrimInline extends LitElement { static properties = { url: { type: String }, img: { type: String }, diff --git a/client/src/curriculum/scrim-inline.scss b/client/src/lit/curriculum/scrim-inline.scss similarity index 88% rename from client/src/curriculum/scrim-inline.scss rename to client/src/lit/curriculum/scrim-inline.scss index 6618fb42ac2f..ef70efbe675f 100644 --- a/client/src/curriculum/scrim-inline.scss +++ b/client/src/lit/curriculum/scrim-inline.scss @@ -88,16 +88,16 @@ dialog { .toggle { &.enter { - mask-image: url("../assets/icons/fullscreen-enter.svg"); + mask-image: url("../../assets/icons/fullscreen-enter.svg"); } &.exit { - mask-image: url("../assets/icons/cancel.svg"); + mask-image: url("../../assets/icons/cancel.svg"); } } .external { - mask-image: url("../assets/icons/external.svg"); + mask-image: url("../../assets/icons/external.svg"); mask-size: 75%; } @@ -109,9 +109,9 @@ dialog { .background { background-color: #453c78; - background-image: url("../assets/curriculum/scrimba-logo.svg"), - url("../assets/curriculum/scrim-hexagons.svg"), - url("../assets/curriculum/scrim-bg.png"); + background-image: url("../../assets/curriculum/scrimba-logo.svg"), + url("../../assets/curriculum/scrim-hexagons.svg"), + url("../../assets/curriculum/scrim-bg.png"); background-position: 1.5em 1.5em, right, diff --git a/client/src/lit/globals.d.ts b/client/src/lit/globals.d.ts new file mode 100644 index 000000000000..51d5a73c8baf --- /dev/null +++ b/client/src/lit/globals.d.ts @@ -0,0 +1,14 @@ +import { MDNImageHistory, TeamMember } from "./about"; +import { ContributorList } from "./community/contributor-list"; +import { ScrimInline } from "./curriculum/scrim-inline"; +import { PlayConsole } from "./play/console"; + +declare global { + interface HTMLElementTagNameMap { + "mdn-image-history": MDNImageHistory; + "team-member": TeamMember; + "contributor-list": ContributorList; + "scrim-inline": ScrimInline; + "play-console": PlayConsole; + } +} diff --git a/client/src/lit/modules.d.ts b/client/src/lit/modules.d.ts new file mode 100644 index 000000000000..c5fc9cfff13e --- /dev/null +++ b/client/src/lit/modules.d.ts @@ -0,0 +1,12 @@ +// once https://github.com/microsoft/TypeScript/issues/46135 is fixed +// we'll be able to do something like: +// declare module '*' with {type: 'css'} { +declare module "*?css" { + const sheet: CSSStyleSheet; + export default sheet; +} + +declare module "*?raw" { + const src: string; + export default src; +} diff --git a/client/src/playground/console.js b/client/src/lit/play/console.js similarity index 100% rename from client/src/playground/console.js rename to client/src/lit/play/console.js diff --git a/client/src/playground/console.scss b/client/src/lit/play/console.scss similarity index 100% rename from client/src/playground/console.scss rename to client/src/lit/play/console.scss diff --git a/client/src/playground/types.d.ts b/client/src/lit/play/types.d.ts similarity index 100% rename from client/src/playground/types.d.ts rename to client/src/lit/play/types.d.ts diff --git a/client/src/lit/tsconfig.json b/client/src/lit/tsconfig.json new file mode 100644 index 000000000000..a3708bfbf670 --- /dev/null +++ b/client/src/lit/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "strict": true, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noEmit": true, + "noFallthroughCasesInSwitch": true, + "allowImportingTsExtensions": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["dom", "dom.iterable", "es2021"], + "module": "ESNext", + "moduleResolution": "Node", + "target": "ES2020", + "plugins": [ + { + "name": "ts-lit-plugin", + "strict": true + } + ] + }, + "include": ["**/*"] +} diff --git a/client/src/playground/index.tsx b/client/src/playground/index.tsx index 67d54f06ab42..c023cccf3811 100644 --- a/client/src/playground/index.tsx +++ b/client/src/playground/index.tsx @@ -21,10 +21,10 @@ import { import "./index.scss"; import { PLAYGROUND_BASE_HOST } from "../env"; import { FlagForm, ShareForm } from "./forms"; -import { ReactPlayConsole } from "./console"; +import { ReactPlayConsole } from "../lit/play/console"; import { useGleanClick } from "../telemetry/glean-context"; import { PLAYGROUND } from "../telemetry/constants"; -import type { VConsole } from "./types"; +import type { VConsole } from "../lit/play/types"; const HTML_DEFAULT = ""; const CSS_DEFAULT = ""; diff --git a/client/src/plus/collections/frequently-viewed.tsx b/client/src/plus/collections/frequently-viewed.tsx index 63352fbd817d..6d329e351a7a 100644 --- a/client/src/plus/collections/frequently-viewed.tsx +++ b/client/src/plus/collections/frequently-viewed.tsx @@ -78,8 +78,13 @@ const sortByVisitsThenTimestampsDesc = ( //'Each timestamp represents one visit. The first is the most recent visit. if (first.timestamps.length > second.timestamps.length) return -1; if (first.timestamps.length < second.timestamps.length) return 1; - if (first.timestamps[0] < second.timestamps[0]) return 1; - if (first.timestamps[0] > second.timestamps[0]) return -1; + if ( + typeof first.timestamps[0] !== "undefined" && + typeof second.timestamps[0] !== "undefined" + ) { + if (first.timestamps[0] < second.timestamps[0]) return 1; + if (first.timestamps[0] > second.timestamps[0]) return -1; + } return 0; }; @@ -98,7 +103,7 @@ function getNextFrequentlyViewedSerial( export function useFrequentlyViewed( limit: number = 0, offset: number = 10, - setEnd?: (bool) => void + setEnd?: (bool: boolean) => void ): FrequentlyViewedCollection { const [collection, setCollection] = useState({ article_count: 0, @@ -130,7 +135,7 @@ export function useFrequentlyViewed( ...c, article_count: freqViewed.length, items: paged, - updated_at: freqViewed[0] + updated_at: freqViewed[0]?.timestamps[0] ? new Date(freqViewed[0].timestamps[0]).toISOString() : new Date().toISOString(), }; @@ -208,12 +213,12 @@ export function useIncrementFrequentlyViewed(doc: Doc | undefined) { let frequentlyViewed = getFrequentlyViewed(); - const index = frequentlyViewed.findIndex( + const foundEntry = frequentlyViewed.find( (entry) => entry.url === doc.mdn_url ); - if (index !== -1) { - frequentlyViewed[index].timestamps.unshift(Date.now()); + if (foundEntry) { + foundEntry.timestamps.unshift(Date.now()); } else { const newEntry: FrequentlyViewedEntry = { serial: getNextFrequentlyViewedSerial(frequentlyViewed), @@ -236,7 +241,7 @@ export function useIncrementFrequentlyViewed(doc: Doc | undefined) { }, [user?.isAuthenticated, doc]); } -const filterFrequentlyViewed = (frequentlyViewed) => { +const filterFrequentlyViewed = (frequentlyViewed: FrequentlyViewedEntry[]) => { //1. Remove timestamps older than 30 days. //2. Filter all values with no remaining timestamps return frequentlyViewed diff --git a/client/src/react-app.d.ts b/client/src/react-app.d.ts index 23b53c872707..20002b3e2305 100644 --- a/client/src/react-app.d.ts +++ b/client/src/react-app.d.ts @@ -78,39 +78,3 @@ declare module "*.svg" { const src: string; export default src; } - -declare module "*?raw" { - const src: string; - export default src; -} - -// once https://github.com/microsoft/TypeScript/issues/46135 is fixed -// we'll be able to do something like: -// declare module '*' with {type: 'css'} { -declare module "*?css" { - const sheet: CSSStyleSheet; - export default sheet; -} - -// once https://github.com/microsoft/TypeScript/issues/46135 is fixed -// we'll be able to do something like: -// declare module '*' with {type: 'css'} { -declare module "*?css" { - const sheet: CSSStyleSheet; - export default sheet; -} - -declare module "*.module.css" { - const classes: { readonly [key: string]: string }; - export default classes; -} - -declare module "*.module.scss" { - const classes: { readonly [key: string]: string }; - export default classes; -} - -declare module "*.module.sass" { - const classes: { readonly [key: string]: string }; - export default classes; -} diff --git a/client/src/settings/mdn-worker.tsx b/client/src/settings/mdn-worker.tsx index c2f58230aa4c..602b845f424b 100644 --- a/client/src/settings/mdn-worker.tsx +++ b/client/src/settings/mdn-worker.tsx @@ -35,7 +35,7 @@ export class MDNWorker { this.timeout = setTimeout(() => this.autoUpdate(), 60 * 60 * 1000); } - messageHandler(event) { + messageHandler(event: MessageEvent) { switch (event.data.type) { case "pong": console.log("pong"); diff --git a/client/src/telemetry/glean-context.tsx b/client/src/telemetry/glean-context.tsx index 599d77f09260..caa8acb3b30e 100644 --- a/client/src/telemetry/glean-context.tsx +++ b/client/src/telemetry/glean-context.tsx @@ -78,8 +78,8 @@ function glean(): GleanAnalytics { if (typeof window === "undefined" || !GLEAN_ENABLED) { //SSR return noop. return { - page: (page: PageProps) => () => {}, - click: (element: ElementClickedProps) => {}, + page: () => () => {}, + click: () => {}, }; } const userIsOptedOut = document.cookie @@ -114,8 +114,13 @@ function glean(): GleanAnalytics { if (page.isBaseline) { pageMetric.isBaseline.set(page.isBaseline); } - for (const param in page.utm) { - pageMetric.utm[param].set(page.utm[param]); + for (const param of Object.keys(page.utm) as Array< + keyof typeof page.utm + >) { + const value = page.utm[param]; + if (value) { + pageMetric.utm[param]?.set(value); + } } pageMetric.httpStatus.set(page.httpStatus); if (page.geo) { diff --git a/client/src/user-context.tsx b/client/src/user-context.tsx index d59b371995c2..109b6abe8857 100644 --- a/client/src/user-context.tsx +++ b/client/src/user-context.tsx @@ -121,8 +121,8 @@ function getSessionStorageData() { } } catch (error: any) { console.warn("sessionStorage.getItem didn't work", error.toString()); - return undefined; } + return undefined; } export function cleanupUserData() { @@ -184,7 +184,7 @@ function setNoPlacementFlag(noAds: boolean) { export function UserDataProvider(props: { children: React.ReactNode }) { const { data, error, isLoading, mutate } = useSWR( DISABLE_AUTH ? null : "/api/v1/whoami", - async (url) => { + async (url: string) => { const response = await fetch(url); if (!response.ok) { removeSessionStorageData(); diff --git a/client/tsconfig.json b/client/tsconfig.json index 262b9c47b077..d82d4baedb94 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -19,13 +19,7 @@ "skipLibCheck": true, "sourceMap": true, "strict": true, - "target": "ES2020", - "plugins": [ - { - "name": "ts-lit-plugin", - "strict": true - } - ] + "target": "ES2020" }, "include": ["src"] } diff --git a/server/react-app.d.ts b/server/react-app.d.ts deleted file mode 100644 index 8206136fee8c..000000000000 --- a/server/react-app.d.ts +++ /dev/null @@ -1,91 +0,0 @@ -declare namespace NodeJS { - interface ProcessEnv { - readonly NODE_ENV: "development" | "production" | "test"; - } -} - -declare module "*.avif" { - const src: string; - export default src; -} - -declare module "*.bmp" { - const src: string; - export default src; -} - -declare module "*.gif" { - const src: string; - export default src; -} - -declare module "*.jpg" { - const src: string; - export default src; -} - -declare module "*.jpeg" { - const src: string; - export default src; -} - -declare module "*.mp3" { - const src: string; - export default src; -} - -declare module "*.mp4" { - const src: string; - export default src; -} - -declare module "*.ogg" { - const src: string; - export default src; -} - -declare module "*.png" { - const src: string; - export default src; -} - -declare module "*.webm" { - const src: string; - export default src; -} - -declare module "*.webp" { - const src: string; - export default src; -} - -declare module "*.woff2" { - const src: string; - export default src; -} - -declare module "*.svg" { - import * as React from "react"; - - export const ReactComponent: React.FunctionComponent< - React.SVGProps & { title?: string } - >; - - const src: string; - export default src; -} - -declare module "*.module.css" { - const classes: { readonly [key: string]: string }; - export default classes; -} - -declare module "*.module.scss" { - const classes: { readonly [key: string]: string }; - export default classes; -} - -declare module "*.module.sass" { - const classes: { readonly [key: string]: string }; - export default classes; -} diff --git a/ssr/modules.d.ts b/ssr/modules.d.ts new file mode 100644 index 000000000000..9f24738429e9 --- /dev/null +++ b/ssr/modules.d.ts @@ -0,0 +1,9 @@ +declare module "*?inline" { + const source: string; + export default source; +} + +declare module "*?public" { + const src: string; + export default src; +} diff --git a/ssr/react-app.d.ts b/ssr/react-app.d.ts deleted file mode 100644 index 4822f4144835..000000000000 --- a/ssr/react-app.d.ts +++ /dev/null @@ -1,122 +0,0 @@ -declare namespace NodeJS { - interface ProcessEnv { - readonly NODE_ENV: "development" | "production" | "test"; - } -} - -declare module "*.avif" { - const src: string; - export default src; -} - -declare module "*.bmp" { - const src: string; - export default src; -} - -declare module "*.gif" { - const src: string; - export default src; -} - -declare module "*.jpg" { - const src: string; - export default src; -} - -declare module "*.jpeg" { - const src: string; - export default src; -} - -declare module "*.mp3" { - const src: string; - export default src; -} - -declare module "*.mp4" { - const src: string; - export default src; -} - -declare module "*.ogg" { - const src: string; - export default src; -} - -declare module "*.png" { - const src: string; - export default src; -} - -declare module "*.webm" { - const src: string; - export default src; -} - -declare module "*.webp" { - const src: string; - export default src; -} - -declare module "*.woff2" { - const src: string; - export default src; -} - -declare module "*.svg" { - import * as React from "react"; - - export const ReactComponent: React.FunctionComponent< - React.SVGProps & { title?: string } - >; - - const src: string; - export default src; -} - -declare module "*?raw" { - const src: string; - export default src; -} - -// once https://github.com/microsoft/TypeScript/issues/46135 is fixed -// we'll be able to do something like: -// declare module '*' with {type: 'css'} { -declare module "*?css" { - const sheet: CSSStyleSheet; - export default sheet; -} - -// once https://github.com/microsoft/TypeScript/issues/46135 is fixed -// we'll be able to do something like: -// declare module '*' with {type: 'css'} { -declare module "*?css" { - const sheet: CSSStyleSheet; - export default sheet; -} - -declare module "*.module.css" { - const classes: { readonly [key: string]: string }; - export default classes; -} - -declare module "*.module.scss" { - const classes: { readonly [key: string]: string }; - export default classes; -} - -declare module "*.module.sass" { - const classes: { readonly [key: string]: string }; - export default classes; -} - -declare module "*?inline" { - const source: string; - export default source; -} - -declare module "*?public" { - const src: string; - export default src; -} diff --git a/ssr/tsconfig.json b/ssr/tsconfig.json index bf2c0bd5252e..e86b2592693b 100644 --- a/ssr/tsconfig.json +++ b/ssr/tsconfig.json @@ -1,5 +1,5 @@ { "extends": "../client/tsconfig.json", - "include": ["."], + "include": [".", "../client/**/*.d.ts"], "exclude": ["dist"] }