From 27b5fa5b3f8837f0a60d49ad3bda4b5a605d1f28 Mon Sep 17 00:00:00 2001 From: mat <27899617+mat-1@users.noreply.github.com> Date: Tue, 28 Jun 2022 03:37:20 +0000 Subject: [PATCH] mdsvx (#1) Use mdsvex for rendering blog posts instead of marked. --- .vscode/settings.json | 3 +- package.json | 7 +- .../[slug].svelte => lib/PostLayout.svelte} | 44 ++----- src/lib/PostPreview.svelte | 6 +- src/lib/blog.ts | 107 ++++++++++++++---- src/lib/components/img.svelte | 14 +++ src/lib/utils.ts | 30 ----- src/routes/blog/[slug].json.ts | 3 +- src/routes/blog/[slug]/[asset].ts | 1 - src/routes/blog/index.json.ts | 21 ++-- .../blog/matdoes-dev-markdown/index.svx} | 10 -- .../the-story-of-reportscammers/index.svx} | 2 +- ...thats-crazy-but-i-dont-remember-asking.png | Bin .../index.svx} | 2 +- .../domain-hack-example.png | Bin .../domain-hack-generator.png | Bin .../blog/what-are-domain-hacks/index.svx} | 0 .../blog}/who-is-mat/favicon.png | Bin .../blog/who-is-mat/index.svx} | 1 + svelte.config.js | 13 ++- yarn.lock | 55 ++++++--- 21 files changed, 185 insertions(+), 134 deletions(-) rename src/{routes/blog/[slug].svelte => lib/PostLayout.svelte} (56%) create mode 100644 src/lib/components/img.svelte delete mode 100644 src/lib/utils.ts rename src/{posts/matdoes-dev-markdown/index.md => routes/blog/matdoes-dev-markdown/index.svx} (94%) rename src/{posts/the-story-of-reportscammers/index.md => routes/blog/the-story-of-reportscammers/index.svx} (98%) rename src/{posts => routes/blog}/the-story-of-reportscammers/thats-crazy-but-i-dont-remember-asking.png (100%) rename src/{posts/uncovering-the-discord-twitch-bots/index.md => routes/blog/uncovering-the-discord-twitch-bots/index.svx} (99%) rename src/{posts => routes/blog}/what-are-domain-hacks/domain-hack-example.png (100%) rename src/{posts => routes/blog}/what-are-domain-hacks/domain-hack-generator.png (100%) rename src/{posts/what-are-domain-hacks/index.md => routes/blog/what-are-domain-hacks/index.svx} (100%) rename src/{posts => routes/blog}/who-is-mat/favicon.png (100%) rename src/{posts/who-is-mat/index.md => routes/blog/who-is-mat/index.svx} (99%) diff --git a/.vscode/settings.json b/.vscode/settings.json index 9489af1..256edb4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,5 +3,6 @@ "editor.formatOnSave": true, "[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" - } + }, + "files.associations": { "*.svx": "markdown" } } diff --git a/package.json b/package.json index 097eb39..668089a 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-svelte3": "^3.2.1", + "mdsvex": "^0.10.6", "prettier": "^2.4.1", "prettier-plugin-svelte": "^2.4.0", "svelte": "^3.48.0", @@ -37,11 +38,9 @@ "@sveltejs/adapter-static": "^1.0.0-next.21", "@types/js-yaml": "^4.0.4", "cookie": "^0.4.1", - "html-minifier": "^4.0.0", - "js-yaml": "^4.1.0", - "marked": "^4.0.3" + "html-minifier": "^4.0.0" }, "engines": { "node": ">=16" } -} +} \ No newline at end of file diff --git a/src/routes/blog/[slug].svelte b/src/lib/PostLayout.svelte similarity index 56% rename from src/routes/blog/[slug].svelte rename to src/lib/PostLayout.svelte index 839fa40..cc6588d 100644 --- a/src/routes/blog/[slug].svelte +++ b/src/lib/PostLayout.svelte @@ -1,36 +1,14 @@ - - - + +
@@ -40,10 +18,10 @@

{title}

- +
- {@html html} +
diff --git a/src/lib/PostPreview.svelte b/src/lib/PostPreview.svelte index 485176b..816906a 100644 --- a/src/lib/PostPreview.svelte +++ b/src/lib/PostPreview.svelte @@ -2,6 +2,8 @@ import type { BlogPostPreview } from 'src/routes/blog/index.json' export let post: BlogPostPreview + // HACK: we have to do this otherwise sveltekit does a dumb + const postHtml = `${post.html}${post.css}` @@ -12,7 +14,9 @@
-
{@html post.html}
+
+ {@html postHtml} +
diff --git a/src/lib/blog.ts b/src/lib/blog.ts index 451f518..faf3dad 100644 --- a/src/lib/blog.ts +++ b/src/lib/blog.ts @@ -1,21 +1,42 @@ -import yaml from 'js-yaml' import path from 'path' import fs from 'fs' -export const postsDir = 'src/posts' as const +export const postsDir = 'src/routes/blog' as const + +export async function listBlogPostSlugs(): Promise { + await fs.promises.readdir(postsDir) + + const existingPosts: string[] = await fs.promises.readdir(postsDir) + + // https://stackoverflow.com/a/46842181 + async function filter(arr: T[], callback: (item: T) => Promise): Promise { + const fail = Symbol() + return ( + await Promise.all(arr.map(async (item) => ((await callback(item)) ? item : fail))) + ).filter((i) => i !== fail) as any + } + + return await filter(existingPosts, (slug) => + fs.promises + .stat(path.join(postsDir, slug, 'index.svx')) + .then(() => true) + .catch(() => false) + ) +} interface BlogPost { title: string published: string - body: string + html: string + css: string slug: string } /** Checks whether a slug is valid or not */ async function doesBlogPostExist(slug: string) { const existingPosts: string[] = await fs.promises.readdir(postsDir) - - return existingPosts.includes(slug) + if (!existingPosts.includes(slug)) return false + return true } /** Checks whether an asset exists in a blog post */ @@ -32,29 +53,77 @@ export async function doesAssetExist(postSlug: string, assetName: string): Promi export async function getPost(slug: string): Promise { if (!doesBlogPostExist(slug)) return null + const url = new URL(`protocol://-/blog/${slug}`) + + const { default: post, metadata } = await import(`../routes/blog/${slug}/index.svx`) + // ok the post exists, so we can safely read the md file - const postMarkdown = ( - await fs.promises.readFile(path.join(postsDir, slug, 'index.md'), 'utf8') - ).replace(/\r\n/g, '\n') + // const postMarkdown = ( + // await fs.promises.readFile(path.join(postsDir, slug, 'index.md'), 'utf8') + // ).replace(/\r\n/g, '\n') - const [_, yamlMetadata = null, markdownContent = null] = - postMarkdown.match(/^---\n([\w\W]+?)\n---\n([\w\W]+)$/) ?? [] + // const [_, yamlMetadata = null, markdownContent = null] = + // postMarkdown.match(/^---\n([\w\W]+?)\n---\n([\w\W]+)$/) ?? [] - if (yamlMetadata === null) throw new Error(`Blog post "${slug}" has no metadata.`) - if (markdownContent === null) throw new Error(`Blog post "${slug}" has no content.`) + // if (yamlMetadata === null) throw new Error(`Blog post "${slug}" has no metadata.`) + // if (markdownContent === null) throw new Error(`Blog post "${slug}" has no content.`) - const metadata: NonNullable = yaml.load(yamlMetadata) + // const metadata: NonNullable = yaml.load(yamlMetadata) - // make sure the post has all the required metadata - const requiredFields = ['title', 'published'] - for (const requiredField of requiredFields) - if (!(requiredField in metadata)) - throw new Error(`Blog post "${slug}" is missing metadata field "${requiredField}"`) + // // make sure the post has all the required metadata + // const requiredFields = ['title', 'published'] + // for (const requiredField of requiredFields) + // if (!(requiredField in metadata)) + // throw new Error(`Blog post "${slug}" is missing metadata field "${requiredField}"`) + + const result: { + title: string + head: string + css: Set<{ + map: null + code: string + }> + } = { title: '', head: '', css: new Set() } + + const renderHtml = post.$$render( + result, + {}, + {}, + {}, + new Map([ + [ + '__svelte__', + { + page: { + // HACK: this is necessary so the hack with images works + // probably a war crime :) + subscribe: (r: any) => { + r({ url }) + }, + }, + navigating: { + subscribe: () => { + return + }, + }, + }, + ], + ]) + ) + + // HACK: i'm probably comitting a felony by putting this here + // but i couldn't come up with a better solution + const html = /^[\w\W]*?<\/div>\s*([\w\W]+)<\/article>[\w\W]*?$/.exec(renderHtml)?.[1] ?? '' + + const css = Array.from(result.css) + .map((css) => css.code) + .join('') return { title: metadata.title, published: new Date(metadata.published).toString(), - body: markdownContent.trim(), + html, + css, slug, } } diff --git a/src/lib/components/img.svelte b/src/lib/components/img.svelte new file mode 100644 index 0000000..c69eda3 --- /dev/null +++ b/src/lib/components/img.svelte @@ -0,0 +1,14 @@ + + + diff --git a/src/lib/utils.ts b/src/lib/utils.ts deleted file mode 100644 index 640b452..0000000 --- a/src/lib/utils.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { marked } from 'marked' - -export function markdownToHtml(md: string, baseUrl?: string): string { - const renderer: Partial = { - image(href: string, title: string, text: string) { - // href = cleanUrl(this.options.sanitize, this.options.baseUrl, href) - href = baseUrl ? resolveUrl(baseUrl, href) : href - if (href === null) return text - let out = `${text} { body: { title: post.title, published: post.published, - html: markdownToHtml(post.body, `/blog/${post.slug}/index.md`), + html: post.html, } as APIBlogPost, } } diff --git a/src/routes/blog/[slug]/[asset].ts b/src/routes/blog/[slug]/[asset].ts index e528343..55b8cfb 100644 --- a/src/routes/blog/[slug]/[asset].ts +++ b/src/routes/blog/[slug]/[asset].ts @@ -1,5 +1,4 @@ import { doesAssetExist, getPost, postsDir } from '$lib/blog' -import { markdownToHtml } from '$lib/utils' import type { RequestHandler } from '@sveltejs/kit' import path from 'path' import fs from 'fs' diff --git a/src/routes/blog/index.json.ts b/src/routes/blog/index.json.ts index 0df77ad..922d8b2 100644 --- a/src/routes/blog/index.json.ts +++ b/src/routes/blog/index.json.ts @@ -1,19 +1,16 @@ -import { getPost } from '$lib/blog' -import { markdownToHtml } from '$lib/utils' +import { getPost, listBlogPostSlugs } from '$lib/blog' import type { RequestHandler } from '@sveltejs/kit' -import fs from 'fs' - -const postsDir = 'src/posts' export interface BlogPostPreview { title: string published: string html: string + css: string slug: string } export const get: RequestHandler = async () => { - const existingPosts: string[] = await fs.promises.readdir(postsDir) + const existingPosts: string[] = await listBlogPostSlugs() const posts = ( await Promise.all( @@ -26,14 +23,10 @@ export const get: RequestHandler = async () => { return { title: blogPost.title, published: blogPost.published, - // cut it off after 255 characters because that's a nice number - html: markdownToHtml( - blogPost.body - .slice(0, 512) - .replace(/!\[[^\]]+?\]\([^)]+?\)/g, '') - .replace(/\[([^\]]+?)\]\([^)]+?\)/g, '$1'), - `/blog/${blogPost.slug}/index.md` - ), + // HACK: remove images, i WILL parse html with regex and you won't stop me + // TODO: cut off the html so it's not sending a bunch of unnecessary data over the network + html: blogPost.html.replace(//g, ''), + css: blogPost.css, slug: blogPost.slug, } }) diff --git a/src/posts/matdoes-dev-markdown/index.md b/src/routes/blog/matdoes-dev-markdown/index.svx similarity index 94% rename from src/posts/matdoes-dev-markdown/index.md rename to src/routes/blog/matdoes-dev-markdown/index.svx index 5886e86..3e797e6 100644 --- a/src/posts/matdoes-dev-markdown/index.md +++ b/src/routes/blog/matdoes-dev-markdown/index.svx @@ -64,13 +64,3 @@ Titles: Image: !\[description](https://image) - -<- -**Float left** -`<- text <-` -<- - --> -**Float right** -`-> text ->` --> diff --git a/src/posts/the-story-of-reportscammers/index.md b/src/routes/blog/the-story-of-reportscammers/index.svx similarity index 98% rename from src/posts/the-story-of-reportscammers/index.md rename to src/routes/blog/the-story-of-reportscammers/index.svx index b1137cd..28ba17f 100644 --- a/src/posts/the-story-of-reportscammers/index.md +++ b/src/routes/blog/the-story-of-reportscammers/index.svx @@ -13,7 +13,7 @@ It all started on April 27th, 2020. I was bored and wanted to make a Hypixel For # madcausebad11 I didn’t do anything with this idea until a couple weeks later on May 14th, when I remembered it, and was actually motivated to create it. I asked around on the SkyBlock Community Discord for what it should be called and what it should do, and I decided on calling it madcausebad11 (name chosen by @TatorCheese), and making it say “thats crazy but I dont remember asking” (@Bliziq chose that one) to all posts that mentioned being scammed. -![Screenshot of a post on the Hypixel Forums where a user named madcausebad11 says "thats crazy but i dont remember asking"](thats-crazy-but-i-dont-remember-asking.png) +![Screenshot of a post on the Hypixel Forums where a user named madcausebad11 says 'thats crazy but i dont remember asking'](thats-crazy-but-i-dont-remember-asking.png) When that had been decided, I started working on the code. It was written in Python, using BeautifulSoup to scrape the web pages and aiohttp to make the requests. After an hour of writing code, madcausebad11 was working. Less than an hour after the bot started working, it got banned for the reason “spam”. diff --git a/src/posts/the-story-of-reportscammers/thats-crazy-but-i-dont-remember-asking.png b/src/routes/blog/the-story-of-reportscammers/thats-crazy-but-i-dont-remember-asking.png similarity index 100% rename from src/posts/the-story-of-reportscammers/thats-crazy-but-i-dont-remember-asking.png rename to src/routes/blog/the-story-of-reportscammers/thats-crazy-but-i-dont-remember-asking.png diff --git a/src/posts/uncovering-the-discord-twitch-bots/index.md b/src/routes/blog/uncovering-the-discord-twitch-bots/index.svx similarity index 99% rename from src/posts/uncovering-the-discord-twitch-bots/index.md rename to src/routes/blog/uncovering-the-discord-twitch-bots/index.svx index 12cd40a..0e84331 100644 --- a/src/posts/uncovering-the-discord-twitch-bots/index.md +++ b/src/routes/blog/uncovering-the-discord-twitch-bots/index.svx @@ -67,7 +67,7 @@ We also found out that they had deleted their webhook, which meant we couldn't s The first two quickly left, but one sent us a message before leaving. -!["wtf are you"](https://i.matdoes.dev/VJMW9) +!['wtf are you'](https://i.matdoes.dev/VJMW9) We asked kzh to join back again. diff --git a/src/posts/what-are-domain-hacks/domain-hack-example.png b/src/routes/blog/what-are-domain-hacks/domain-hack-example.png similarity index 100% rename from src/posts/what-are-domain-hacks/domain-hack-example.png rename to src/routes/blog/what-are-domain-hacks/domain-hack-example.png diff --git a/src/posts/what-are-domain-hacks/domain-hack-generator.png b/src/routes/blog/what-are-domain-hacks/domain-hack-generator.png similarity index 100% rename from src/posts/what-are-domain-hacks/domain-hack-generator.png rename to src/routes/blog/what-are-domain-hacks/domain-hack-generator.png diff --git a/src/posts/what-are-domain-hacks/index.md b/src/routes/blog/what-are-domain-hacks/index.svx similarity index 100% rename from src/posts/what-are-domain-hacks/index.md rename to src/routes/blog/what-are-domain-hacks/index.svx diff --git a/src/posts/who-is-mat/favicon.png b/src/routes/blog/who-is-mat/favicon.png similarity index 100% rename from src/posts/who-is-mat/favicon.png rename to src/routes/blog/who-is-mat/favicon.png diff --git a/src/posts/who-is-mat/index.md b/src/routes/blog/who-is-mat/index.svx similarity index 99% rename from src/posts/who-is-mat/index.md rename to src/routes/blog/who-is-mat/index.svx index 289f72f..cfe5d0d 100644 --- a/src/posts/who-is-mat/index.md +++ b/src/routes/blog/who-is-mat/index.svx @@ -4,6 +4,7 @@ published: 2019-04-25T01:08:27.057+00:00 --- Welcome to mat does dev. You might have some questions, so I'm here to answer them. + ![mat does dev](favicon.png) --- diff --git a/svelte.config.js b/svelte.config.js index 4a36752..4c0851e 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -1,11 +1,19 @@ import staticAdapter from '@sveltejs/adapter-static' import preprocess from 'svelte-preprocess' +import { mdsvex } from 'mdsvex' /** @type {import('@sveltejs/kit').Config} */ const config = { // Consult https://github.com/sveltejs/svelte-preprocess // for more information about preprocessors - preprocess: preprocess(), + preprocess: [ + preprocess(), + mdsvex({ + layout: './src/lib/PostLayout.svelte' + }), + ], + + extensions: ['.svelte', '.svx'], kit: { adapter: staticAdapter({}), @@ -25,7 +33,10 @@ const config = { // } // : {}, }, + }, + + } export default config diff --git a/yarn.lock b/yarn.lock index 02ed81f..8aec374 100644 --- a/yarn.lock +++ b/yarn.lock @@ -202,6 +202,11 @@ dependencies: source-map "^0.6.1" +"@types/unist@^2.0.0", "@types/unist@^2.0.2", "@types/unist@^2.0.3": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" + integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== + "@typescript-eslint/eslint-plugin@^4.31.1": version "4.33.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" @@ -341,11 +346,6 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" @@ -1069,13 +1069,6 @@ js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" -js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -1138,10 +1131,15 @@ magic-string@^0.26.2: dependencies: sourcemap-codec "^1.4.8" -marked@^4.0.3: - version "4.0.13" - resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.13.tgz#4fd46ca93da46448f3d83f054d938c4f905a258d" - integrity sha512-lS/ZCa4X0gsRcfWs1eoh6dLnHr9kVH3K1t2X4M/tTtNouhZ7anS1Csb6464VGLQHv8b2Tw1cLeZQs58Jav8Rzw== +mdsvex@^0.10.6: + version "0.10.6" + resolved "https://registry.yarnpkg.com/mdsvex/-/mdsvex-0.10.6.tgz#5ba975f4616e5255ca31cd93d33e2c2a22845631" + integrity sha512-aGRDY0r5jx9+OOgFdyB9Xm3EBr9OUmcrTDPWLB7a7g8VPRxzPy4MOBmcVYgz7ErhAJ7bZ/coUoj6aHio3x/2mA== + dependencies: + "@types/unist" "^2.0.3" + prism-svelte "^0.4.7" + prismjs "^1.17.1" + vfile-message "^2.0.4" merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" @@ -1304,6 +1302,16 @@ prettier@^2.4.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.2.tgz#e26d71a18a74c3d0f0597f55f01fb6c06c206032" integrity sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew== +prism-svelte@^0.4.7: + version "0.4.7" + resolved "https://registry.yarnpkg.com/prism-svelte/-/prism-svelte-0.4.7.tgz#fbc6709450b4e2ed660ddb82c3718817fc584cbe" + integrity sha512-yABh19CYbM24V7aS7TuPYRNMqthxwbvx6FF/Rw920YbyBWO3tnyPIqRMgHuSVsLmuHkkBS1Akyof463FVdkeDQ== + +prismjs@^1.17.1: + version "1.28.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.28.0.tgz#0d8f561fa0f7cf6ebca901747828b149147044b6" + integrity sha512-8aaXdYvl1F7iC7Xm1spqSaY/OJBpYW3v+KJ+F17iYxvdc8sfjW194COK5wVhMZX45tGteiBQgdvD/nhxcRwylw== + progress@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" @@ -1626,6 +1634,13 @@ uglify-js@^3.5.1: resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.15.3.tgz#9aa82ca22419ba4c0137642ba0df800cb06e0471" integrity sha512-6iCVm2omGJbsu3JWac+p6kUiOpg3wFO2f8lIXjfEb8RrmLjzog1wTPMmwKB7swfzzqxj9YM+sGUM++u1qN4qJg== +unist-util-stringify-position@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz#cce3bfa1cdf85ba7375d1d5b17bdc4cada9bd9da" + integrity sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g== + dependencies: + "@types/unist" "^2.0.2" + upper-case@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" @@ -1643,6 +1658,14 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== +vfile-message@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a" + integrity sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ== + dependencies: + "@types/unist" "^2.0.0" + unist-util-stringify-position "^2.0.0" + vite@^2.9.10: version "2.9.12" resolved "https://registry.yarnpkg.com/vite/-/vite-2.9.12.tgz#b1d636b0a8ac636afe9d83e3792d4895509a941b"