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:
56
lib/helpers/compile-note.ts
Normal file
56
lib/helpers/compile-note.ts
Normal 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,
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -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();
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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: {
|
||||
|
||||
64
yarn.lock
64
yarn.lock
@@ -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==
|
||||
|
||||
Reference in New Issue
Block a user