1
mirror of https://github.com/jakejarvis/jarv.is.git synced 2026-04-18 20:18:46 -04:00

separate markdown compilation to hopefully reduce function bundle sizes

This commit is contained in:
2022-06-11 11:58:23 -04:00
parent d7bc5f8ab6
commit bde473041a
5 changed files with 82 additions and 129 deletions

View File

@@ -0,0 +1,56 @@
import { serialize } from "next-mdx-remote/serialize";
import { minify } from "uglify-js";
import { getNoteData } from "./parse-notes";
// remark/rehype markdown plugins
import remarkGfm from "remark-gfm";
import remarkSmartypants from "remark-smartypants";
import remarkUnwrapImages from "remark-unwrap-images";
import rehypeSlug from "rehype-slug";
import rehypePrism from "rehype-prism-plus";
import type { Note } from "../../types";
// fully parses MDX into JS and returns *everything* about a note
export const compileNote = async (slug: string): Promise<Note> => {
const { frontMatter, content } = await getNoteData(slug);
const source = await serialize(content, {
parseFrontmatter: false,
mdxOptions: {
remarkPlugins: [
[remarkGfm, { singleTilde: false }],
[
remarkSmartypants,
{
quotes: true,
dashes: "oldschool",
backticks: false,
ellipses: false,
},
],
[remarkUnwrapImages],
],
rehypePlugins: [[rehypeSlug], [rehypePrism, { ignoreMissing: true }]],
},
});
// HACK: next-mdx-remote v4 doesn't (yet?) minify compiled JSX output, see:
// https://github.com/hashicorp/next-mdx-remote/pull/211#issuecomment-1013658514
// ...so for now, let's do it manually (and conservatively) with uglify-js when building for production.
const compiledSource =
process.env.NEXT_PUBLIC_VERCEL_ENV === "production"
? minify(source.compiledSource, {
toplevel: true,
parse: {
bare_returns: true,
},
}).code
: source.compiledSource;
return {
frontMatter,
source: {
compiledSource,
},
};
};

View File

@@ -1,26 +1,15 @@
import fs from "fs/promises";
import path from "path";
import { renderToStaticMarkup } from "react-dom/server";
import { serialize } from "next-mdx-remote/serialize";
import glob from "fast-glob";
import pMap from "p-map";
import matter from "gray-matter";
import { minify } from "uglify-js";
import { compiler } from "markdown-to-jsx";
import { marked } from "marked";
import removeMarkdown from "remove-markdown";
import sanitizeHtml from "sanitize-html";
import pMap from "p-map";
import { formatDateISO } from "./format-date";
import { baseUrl } from "../config";
import { NOTES_DIR } from "../config/constants";
// remark/rehype markdown plugins
import remarkGfm from "remark-gfm";
import remarkSmartypants from "remark-smartypants";
import remarkUnwrapImages from "remark-unwrap-images";
import rehypeSlug from "rehype-slug";
import rehypePrism from "rehype-prism-plus";
import type { Note, NoteFrontMatter } from "../../types";
import type { NoteFrontMatter } from "../../types";
export const getNoteSlugs = async (): Promise<string[]> => {
// list all .mdx files in NOTES_DIR
@@ -43,27 +32,17 @@ export const getNoteData = async (
const rawContent = await fs.readFile(fullPath, "utf8");
const { data, content } = matter(rawContent);
// carefully allow VERY limited markdown in post titles...
const htmlTitle = sanitizeHtml(
renderToStaticMarkup(
compiler(data.title, {
forceInline: true,
disableParsingRawHTML: true,
})
),
{
allowedTags: ["code", "pre", "em", "strong", "del"],
}
);
// return both the parsed YAML front matter (with a few amendments) and the raw, unparsed markdown content
return {
frontMatter: {
...(data as Partial<NoteFrontMatter>),
// zero markdown title:
title: removeMarkdown(data.title),
// parsed markdown title:
htmlTitle,
// allow markdown formatting to appear in post titles in some places (rarely used):
htmlTitle: marked.parseInline(data.title, {
silent: true,
smartypants: true,
}),
slug,
permalink: `${baseUrl}/notes/${slug}/`,
date: formatDateISO(data.date), // validate/normalize the date string provided from front matter
@@ -72,50 +51,6 @@ export const getNoteData = async (
};
};
// fully parses MDX into JS and returns *everything* about a note
export const getNote = async (slug: string): Promise<Note> => {
const { frontMatter, content } = await getNoteData(slug);
const source = await serialize(content, {
parseFrontmatter: false,
mdxOptions: {
remarkPlugins: [
[remarkGfm, { singleTilde: false }],
[
remarkSmartypants,
{
quotes: true,
dashes: "oldschool",
backticks: false,
ellipses: false,
},
],
[remarkUnwrapImages],
],
rehypePlugins: [[rehypeSlug], [rehypePrism, { ignoreMissing: true }]],
},
});
// HACK: next-mdx-remote v4 doesn't (yet?) minify compiled JSX output, see:
// https://github.com/hashicorp/next-mdx-remote/pull/211#issuecomment-1013658514
// ...so for now, let's do it manually (and conservatively) with uglify-js when building for production.
const compiledSource =
process.env.NEXT_PUBLIC_VERCEL_ENV === "production"
? minify(source.compiledSource, {
toplevel: true,
parse: {
bare_returns: true,
},
}).code
: source.compiledSource;
return {
frontMatter,
source: {
compiledSource,
},
};
};
// returns the front matter of ALL notes, sorted reverse chronologically
export const getAllNotes = async (): Promise<NoteFrontMatter[]> => {
const slugs = await getNoteSlugs();

View File

@@ -41,7 +41,7 @@
"formik": "^2.2.9",
"gray-matter": "^4.0.3",
"hex-to-rgba": "^2.0.1",
"markdown-to-jsx": "^7.1.7",
"marked": "^4.0.16",
"next": "12.1.7-canary.35",
"next-compose-plugins": "^2.2.1",
"next-mdx-remote": "^4.0.3",
@@ -69,7 +69,6 @@
"remark-smartypants": "^2.0.0",
"remark-unwrap-images": "^3.0.1",
"remove-markdown": "^0.5.0",
"sanitize-html": "^2.7.0",
"simple-icons": "^7.0.0",
"sitemap": "^7.1.1",
"swr": "^1.3.0"
@@ -79,13 +78,13 @@
"@next/bundle-analyzer": "12.1.7-canary.35",
"@svgr/webpack": "^6.2.1",
"@types/comma-number": "^2.1.0",
"@types/marked": "^4.0.3",
"@types/node": "*",
"@types/prop-types": "^15.7.5",
"@types/react": "^18.0.12",
"@types/react-dom": "^18.0.5",
"@types/react-is": "^17.0.3",
"@types/remove-markdown": "^0.3.1",
"@types/sanitize-html": "^2.6.2",
"@types/uglify-js": "^3.16.0",
"@typescript-eslint/eslint-plugin": "^5.27.1",
"@typescript-eslint/parser": "^5.27.1",

View File

@@ -5,7 +5,8 @@ import Content from "../../components/Content";
import NoteMeta from "../../components/NoteMeta";
import Comments from "../../components/Comments";
import * as mdxComponents from "../../lib/helpers/mdx-components";
import { getNote, getNoteSlugs } from "../../lib/helpers/parse-notes";
import { getNoteSlugs } from "../../lib/helpers/parse-notes";
import { compileNote } from "../../lib/helpers/compile-note";
import * as config from "../../lib/config";
import { articleJsonLd } from "../../lib/config/seo";
import type { GetStaticProps, GetStaticPaths } from "next";
@@ -74,7 +75,7 @@ const Note = ({ frontMatter, source }: Note) => {
};
export const getStaticProps: GetStaticProps = async ({ params }: { params: Pick<NoteFrontMatter, "slug"> }) => {
const { frontMatter, source } = await getNote(params.slug);
const { frontMatter, source } = await compileNote(params.slug);
return {
props: {

View File

@@ -1638,6 +1638,11 @@
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
"@types/marked@^4.0.3":
version "4.0.3"
resolved "https://registry.yarnpkg.com/@types/marked/-/marked-4.0.3.tgz#2098f4a77adaba9ce881c9e0b6baf29116e5acc4"
integrity sha512-HnMWQkLJEf/PnxZIfbm0yGJRRZYYMhb++O9M36UCTA9z53uPvVoSlAwJr3XOpDEryb7Hwl1qAx/MV6YIW1RXxg==
"@types/mdast@^3.0.0":
version "3.0.10"
resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af"
@@ -1725,13 +1730,6 @@
resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.1.tgz#d8f1c0d0dc23afad6dc16a9e993a0865774b4065"
integrity sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==
"@types/sanitize-html@^2.6.2":
version "2.6.2"
resolved "https://registry.yarnpkg.com/@types/sanitize-html/-/sanitize-html-2.6.2.tgz#9c47960841b9def1e4c9dfebaaab010a3f6e97b9"
integrity sha512-7Lu2zMQnmHHQGKXVvCOhSziQMpa+R2hMHFefzbYoYMHeaXR0uXqNeOc3JeQQQ8/6Xa2Br/P1IQTLzV09xxAiUQ==
dependencies:
htmlparser2 "^6.0.0"
"@types/sax@^1.2.1":
version "1.2.4"
resolved "https://registry.yarnpkg.com/@types/sax/-/sax-1.2.4.tgz#8221affa7f4f3cb21abd22f244cfabfa63e6a69e"
@@ -2559,14 +2557,14 @@ domelementtype@^2.0.1, domelementtype@^2.2.0:
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d"
integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1:
domhandler@^4.2.0, domhandler@^4.3.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c"
integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==
dependencies:
domelementtype "^2.2.0"
domutils@^2.5.2, domutils@^2.8.0:
domutils@^2.8.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==
@@ -3449,16 +3447,6 @@ hoist-non-react-statics@^3.3.0:
dependencies:
react-is "^16.7.0"
htmlparser2@^6.0.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7"
integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==
dependencies:
domelementtype "^2.0.1"
domhandler "^4.0.0"
domutils "^2.5.2"
entities "^2.0.0"
https-proxy-agent@^5.0.0:
version "5.0.1"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6"
@@ -4022,10 +4010,10 @@ markdown-table@^3.0.0:
resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-3.0.2.tgz#9b59eb2c1b22fe71954a65ff512887065a7bb57c"
integrity sha512-y8j3a5/DkJCmS5x4dMCQL+OR0+2EAq3DOtio1COSHsmW2BGXnNCK3v12hJt1LrUz5iZH5g0LmuYOjDdI+czghA==
markdown-to-jsx@^7.1.7:
version "7.1.7"
resolved "https://registry.yarnpkg.com/markdown-to-jsx/-/markdown-to-jsx-7.1.7.tgz#a5f22102fb12241c8cea1ca6a4050bb76b23a25d"
integrity sha512-VI3TyyHlGkO8uFle0IOibzpO1c1iJDcXcS/zBrQrXQQvJ2tpdwVzVZ7XdKsyRz1NdRmre4dqQkMZzUHaKIG/1w==
marked@^4.0.16:
version "4.0.16"
resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.16.tgz#9ec18fc1a723032eb28666100344d9428cf7a264"
integrity sha512-wahonIQ5Jnyatt2fn8KqF/nIqZM8mh3oRu2+l5EANGMhu6RFjiSG52QNE2eWzFMI94HqYSgN184NurgNG6CztA==
mdast-util-compact@^2.0.0:
version "2.0.1"
@@ -4691,7 +4679,7 @@ nano-css@^5.3.1:
stacktrace-js "^2.0.2"
stylis "^4.0.6"
nanoid@^3.1.30, nanoid@^3.3.4:
nanoid@^3.1.30:
version "3.3.4"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
@@ -4999,11 +4987,6 @@ parse-numeric-range@^1.3.0:
resolved "https://registry.yarnpkg.com/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz#7c63b61190d61e4d53a1197f0c83c47bb670ffa3"
integrity sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==
parse-srcset@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/parse-srcset/-/parse-srcset-1.0.2.tgz#f2bd221f6cc970a938d88556abc589caaaa2bde1"
integrity sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==
parse5@^6.0.0:
version "6.0.1"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
@@ -5071,15 +5054,6 @@ postcss@8.4.5:
picocolors "^1.0.0"
source-map-js "^1.0.1"
postcss@^8.3.11:
version "8.4.14"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf"
integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==
dependencies:
nanoid "^3.3.4"
picocolors "^1.0.0"
source-map-js "^1.0.2"
prelude-ls@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
@@ -5603,18 +5577,6 @@ safe-buffer@~5.1.1:
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
sanitize-html@^2.7.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.7.0.tgz#e106205b468aca932e2f9baf241f24660d34e279"
integrity sha512-jfQelabOn5voO7FAfnQF7v+jsA6z9zC/O4ec0z3E35XPEtHYJT/OdUziVWlKW4irCr2kXaQAyXTXDHWAibg1tA==
dependencies:
deepmerge "^4.2.2"
escape-string-regexp "^4.0.0"
htmlparser2 "^6.0.0"
is-plain-object "^5.0.0"
parse-srcset "^1.0.2"
postcss "^8.3.11"
sax@^1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
@@ -5758,7 +5720,7 @@ slice-ansi@^5.0.0:
ansi-styles "^6.0.0"
is-fullwidth-code-point "^4.0.0"
source-map-js@^1.0.1, source-map-js@^1.0.2:
source-map-js@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==