diff --git a/lib/helpers/minifier.ts b/lib/helpers/minifier.ts new file mode 100644 index 00000000..fcaf77b0 --- /dev/null +++ b/lib/helpers/minifier.ts @@ -0,0 +1,25 @@ +import { trimLines } from "trim-lines"; +import stripComments from "strip-comments"; + +// do some _very_ rudimentary JS minifying. +export const minifier = (source: string): string => { + // save the first line for later, it might be important? + const firstLine = source.split("\n")[0]; + + // remove JS comments + source = stripComments(source, { + block: false, + keepProtected: true, + }); + // remove indentation + source = trimLines(source); + // remove newlines + source = source.replace(/\n/g, ""); + + // restore JSX flags if they were there at the beginning + if (firstLine.startsWith("/*@jsx")) { + source = `${firstLine}${source}`; + } + + return source; +}; diff --git a/lib/helpers/posts.ts b/lib/helpers/posts.ts index 4df259e7..665cc570 100644 --- a/lib/helpers/posts.ts +++ b/lib/helpers/posts.ts @@ -6,6 +6,7 @@ import pMap from "p-map"; import pMemoize from "p-memoize"; import matter from "gray-matter"; import { formatDate } from "./format-date"; +import { minifier } from "./minifier"; import type { PostFrontMatter, PostWithSource } from "../../types"; // path to directory with .mdx files, relative to project root @@ -18,15 +19,15 @@ export const getPostData = async ( frontMatter: PostFrontMatter; markdown: string; }> => { - const fullPath = path.join(process.cwd(), POSTS_DIR, `${slug}.mdx`); - const rawContent = await fs.readFile(fullPath, "utf8"); - const { data, content } = matter(rawContent); - const { unified } = await import("unified"); const { remarkParse, remarkSmartypants, remarkRehype, rehypeSanitize, rehypeStringify } = await import( "./remark-rehype-plugins" ); + const fullPath = path.join(process.cwd(), POSTS_DIR, `${slug}.mdx`); + const rawContent = await fs.readFile(fullPath, "utf8"); + const { data, content } = matter(rawContent); + // allow *very* limited markdown to be used in post titles const parseTitle = async (title: string, allowedTags: string[] = []): Promise => { return String( @@ -68,12 +69,12 @@ export const getPostData = async ( // fully parses MDX into JS and returns *everything* about a post export const compilePost = async (slug: string): Promise => { - const { frontMatter, markdown } = await getPostData(slug); - const { remarkGfm, remarkSmartypants, remarkUnwrapImages, rehypeSlug, rehypePrism } = await import( "./remark-rehype-plugins" ); + const { frontMatter, markdown } = await getPostData(slug); + const { compiledSource } = await serialize(markdown, { parseFrontmatter: false, mdxOptions: { @@ -105,7 +106,8 @@ export const compilePost = async (slug: string): Promise => { return { frontMatter, source: { - compiledSource, + // save some bytes + compiledSource: minifier(compiledSource), }, }; }; diff --git a/package.json b/package.json index 98ecacfc..b12025b6 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,6 @@ "@prisma/client": "^5.10.2", "@react-spring/web": "^9.7.3", "@stitches/react": "1.3.1-1", - "@vercel/edge": "^1.1.1", "comma-number": "^2.1.0", "copy-to-clipboard": "^3.3.3", "dayjs": "^1.11.10", @@ -68,19 +67,22 @@ "remark-unwrap-images": "^4.0.0", "sitemap": "^7.1.1", "stitches-normalize": "^3.0.1", + "strip-comments": "^2.0.1", "swr": "^2.2.5", + "trim-lines": "^3.0.1", "unified": "^11.0.4" }, "devDependencies": { "@jakejarvis/eslint-config": "^3.1.0", "@types/comma-number": "^2.1.2", - "@types/node": "^20.11.20", + "@types/node": "^20.11.22", "@types/nodemailer": "^6.4.14", "@types/novnc__novnc": "^1.3.4", "@types/prop-types": "^15.7.11", "@types/react": "^18.2.60", "@types/react-dom": "^18.2.19", "@types/react-is": "^18.2.4", + "@types/strip-comments": "^2.0.4", "@typescript-eslint/eslint-plugin": "^7.1.0", "@typescript-eslint/parser": "^7.1.0", "cross-env": "^7.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cff103a5..07e41f33 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,9 +29,6 @@ dependencies: '@stitches/react': specifier: 1.3.1-1 version: 1.3.1-1(react@18.2.0) - '@vercel/edge': - specifier: ^1.1.1 - version: 1.1.1 comma-number: specifier: ^2.1.0 version: 2.1.0 @@ -155,9 +152,15 @@ dependencies: stitches-normalize: specifier: ^3.0.1 version: 3.0.1(@stitches/react@1.3.1-1) + strip-comments: + specifier: ^2.0.1 + version: 2.0.1 swr: specifier: ^2.2.5 version: 2.2.5(react@18.2.0) + trim-lines: + specifier: ^3.0.1 + version: 3.0.1 unified: specifier: ^11.0.4 version: 11.0.4 @@ -175,8 +178,8 @@ devDependencies: specifier: ^2.1.2 version: 2.1.2 '@types/node': - specifier: ^20.11.20 - version: 20.11.20 + specifier: ^20.11.22 + version: 20.11.22 '@types/nodemailer': specifier: ^6.4.14 version: 6.4.14 @@ -195,6 +198,9 @@ devDependencies: '@types/react-is': specifier: ^18.2.4 version: 18.2.4 + '@types/strip-comments': + specifier: ^2.0.4 + version: 2.0.4 '@typescript-eslint/eslint-plugin': specifier: ^7.1.0 version: 7.1.0(@typescript-eslint/parser@7.1.0)(eslint@8.57.0)(typescript@5.3.3) @@ -943,7 +949,7 @@ packages: /@types/concat-stream@2.0.0: resolution: {integrity: sha512-t3YCerNM7NTVjLuICZo5gYAXYoDvpuuTceCcFQWcDQz26kxUR5uIWolxbIR5jRNIXpMqhOpW/b8imCR1LEmuJw==} dependencies: - '@types/node': 20.11.20 + '@types/node': 20.11.22 dev: true /@types/debug@4.1.12: @@ -1020,15 +1026,15 @@ packages: resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} dev: false - /@types/node@20.11.20: - resolution: {integrity: sha512-7/rR21OS+fq8IyHTgtLkDK949uzsa6n8BkziAKtPVpugIkO6D+/ooXMvzXxDnZrmtXVfjb1bKQafYpb8s89LOg==} + /@types/node@20.11.22: + resolution: {integrity: sha512-/G+IxWxma6V3E+pqK1tSl2Fo1kl41pK1yeCyDsgkF9WlVAme4j5ISYM2zR11bgLFJGLN5sVK40T4RJNuiZbEjA==} dependencies: undici-types: 5.26.5 /@types/nodemailer@6.4.14: resolution: {integrity: sha512-fUWthHO9k9DSdPCSPRqcu6TWhYyxTBg382vlNIttSe9M7XfsT06y0f24KHXtbnijPGGRIcVvdKHTNikOI6qiHA==} dependencies: - '@types/node': 20.11.20 + '@types/node': 20.11.22 dev: true /@types/novnc__novnc@1.3.4: @@ -1064,7 +1070,7 @@ packages: /@types/sax@1.2.5: resolution: {integrity: sha512-9jWta97bBVC027/MShr3gLab8gPhKy4l6qpb+UJLF5pDm3501NvA7uvqVCW+REFtx00oTi6Cq9JzLwgq6evVgw==} dependencies: - '@types/node': 20.11.20 + '@types/node': 20.11.22 dev: false /@types/scheduler@0.16.4: @@ -1074,6 +1080,10 @@ packages: resolution: {integrity: sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==} dev: true + /@types/strip-comments@2.0.4: + resolution: {integrity: sha512-YwcQqIGy90zEHrReYrMTpZfq003Um77WayeE8UwJTHvaM9g9XR9N7GMVSnjRhhDzQYVX375JnB5P6q5kAg221g==} + dev: true + /@types/supports-color@8.1.1: resolution: {integrity: sha512-dPWnWsf+kzIG140B8z2w3fr5D03TLWbOAFQl45xUpI3vcizeXriNR5VYkWZ+WTMsUHqZ9Xlt3hrxGNANFyNQfw==} dev: true @@ -1287,10 +1297,6 @@ packages: /@ungap/structured-clone@1.2.0: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - /@vercel/edge@1.1.1: - resolution: {integrity: sha512-NtKiIbn9Cq6HWGy+qRudz28mz5nxfOJWls5Pnckjw1yCfSX8rhXdvY/il3Sy3Zd5n/sKCM2h7VSCCpJF/oaDrQ==} - dev: false - /abbrev@2.0.0: resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -5601,6 +5607,11 @@ packages: engines: {node: '>=4'} dev: true + /strip-comments@2.0.1: + resolution: {integrity: sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==} + engines: {node: '>=10'} + dev: false + /strip-final-newline@3.0.0: resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} engines: {node: '>=12'} @@ -5821,7 +5832,7 @@ packages: '@types/concat-stream': 2.0.0 '@types/debug': 4.1.12 '@types/is-empty': 1.2.1 - '@types/node': 20.11.20 + '@types/node': 20.11.22 '@types/unist': 3.0.2 '@ungap/structured-clone': 1.2.0 concat-stream: 2.0.0