ssssota / svelte-exmarkdown Goto Github PK
View Code? Open in Web Editor NEWSvelte component to render markdown.
Home Page: https://ssssota.github.io/svelte-exmarkdown
License: MIT License
Svelte component to render markdown.
Home Page: https://ssssota.github.io/svelte-exmarkdown
License: MIT License
If you try to add a vector or square root at https://ssssota.github.io/svelte-exmarkdown/docs/08-math-formula using \vec
or \sqrt
, the math is not typeset with an arrow or square root symbol.
Is there any way to add mermaid support?
Perhaps with this:
https://github.com/remcohaszing/rehype-mermaidjs
I'm trying to use the remark frontmatter with the svelte-exmarkdown, but it's not working.
How could we use this package as the highlighter for the code blocks?
https://github.com/shikijs/shiki
Thanks so much for your hard work & valuable time.
I am trying to add support of html tags inside markdown but haven't found any working solution yet.
And I also want to render the custom tags.
According to the original Markdown spec, the CommonMark spec and the GitHub Flavored Markdown spec, HTML blocks are specified as valid Markdown. However, attempting to use HTML in Markdown with svelte-exmarkdown, it will get rendered as text instead:
Input:
# Hello
<div>hello</div>
Output:
<h1>Hello</h1>
<div>hello</div>
I understand that this might the be intended output for some use cases – for example if the Markdown source is to be specified by the user, this approach is the absolutely safest way to avoid XSS. However, there are situations where one might want to allow a subset of HTML, or even all HTML, if the Markdown source is trusted.
Logging the AST in each stage reveals that the parsed Markdown tree:
{
type: "root",
children: [
{
type: "heading",
depth: 1,
children: [{ type: "text", value: "Hello" }],
},
{
type: "html",
value: "<div>hello</div>",
},
],
}
... gets turned to the following HTML AST:
{
type: "root",
children: [
{
type: "element",
tagName: "h1",
children: [{ type: "text", value: "Hello" }],
},
{
type: "raw",
value: "<div>hello</div>",
},
],
}
I don't understand how exactly the renderer decides to render type: "raw"
as a text node, but somehow it does.
Note, however, that this can't be solved by adding a rendering rule that would output {@html value}
, because the raw HTML may contain unmatched tags. For example, consider this Markdown snippet:
<div>
# Hello
</div>
In the unified pipeline, it will get turned to the following HAST:
{
type: "root",
children: [
{ type: "raw", value: "<div>" },
{
type: "element",
tagName: "h1",
children: [{ type: "text", value: "Hello" }],
},
{ type: "raw", value: "</div>" },
],
}
Attempting to render this HAST using the {@html ...}
directive would output the following result:
<div></div>
<h1>Hello</h1>
<div></div>
(see for example this demonstration), rather than the intended tree:
<div>
<h1>Hello</h1>
</div>
Since the AST can contain effectively unparsed tokens, the most straightforward and robust solution seems to be to stringify and re-parse it. This is an example of a svelte-exmarkdown plugin that does just that:
import type { Plugin } from 'svelte-exmarkdown';
import { unified } from 'unified';
import { toHtml } from 'hast-util-to-html';
import rehypeParse from 'rehype-parse';
export const rawHtml: Plugin = {
rehypePlugin: () => (node) => {
const str = toHtml(node, { allowDangerousHtml: true });
console.log(str);
return unified().use(rehypeParse, { fragment: true }).parse(str);
},
};
A serious problem with this approach is that it cannot distinguish harmless HTML from a XSS attempt, so it's only ever useful if one has absolute control over the Markdown source. A somewhat less serious problem is the loss of the AST's metadata (eg. the position
props).
First up: thanks for a wonderful library! It looks exactly like what I needed.
When starting to use it I do immediately notice an issue (running v1.1.7
). It seems to be a follow-up to #17 where related warnings showed up in the browser console.
That issue was resolved and I indeed don't see the warnings in my browser. However, they've been replaced by new warnings when building a SvelteKit (TypeScript based) project now. In fact they are the same warnings that were also present in the GitHub Actions output for the commit that fixed the browser warnings.
Run npm create svelte@latest .
in your test folder and choose these options:
Welcome to SvelteKit!
√ Where should we create your project?
(leave blank to use current directory) ...
√ Which Svelte app template? » Skeleton project
√ Add type checking with TypeScript? » Yes, using TypeScript syntax
√ Add ESLint for code linting? ... No / Yes
√ Add Prettier for code formatting? ... No / Yes
√ Add Playwright for browser testing? ... No / Yes
√ Add Vitest for unit testing? ... No / Yes
Then run npm i -D svelte-exmarkdown
(it gave me 1.1.7
), and change the +page.svelte
that was generated into:
<script>
import Markdown from 'svelte-exmarkdown';
let md = '# Hello world!';
</script>
<h1>Welcome to SvelteKit</h1>
<p>Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation</p>
<textarea bind:value={md} />
<Markdown {md} />
And run npm run dev -- --open
.
The actual resulting output on the console includes:
18:13:31 [vite-plugin-svelte] ssr compile in progress ...
18:13:31 [vite-plugin-svelte] ssr compile done.
package files time avg
svelte-exmarkdown-issue-repro 9 80.3ms 8.9ms
18:13:33 [vite-plugin-svelte] prebundle libraries done.
package files time avg
svelte-exmarkdown-issue-repro 5 80.9ms 16.2ms
18:13:33 [vite] ✨ new dependencies optimized: svelte-exmarkdown
18:13:33 [vite] ✨ optimized dependencies changed. reloading
18:13:34 [vite-plugin-svelte] /node_modules/svelte-exmarkdown/renderer/Renderer.svelte:5:11 Renderer has unused export property 'type'. If it is for external reference only, please consider using `export const type`
18:13:34 [vite-plugin-svelte] /node_modules/svelte-exmarkdown/renderer/Renderer.svelte:6:11 Renderer has unused export property 'position'. If it is for external reference only, please consider using `export const position`
18:13:34 [vite-plugin-svelte] /node_modules/svelte-exmarkdown/renderer/Text.svelte:2:11 Text has unused export property 'type'. If it is for external reference only, please consider using `export const type`
18:13:34 [vite-plugin-svelte] /node_modules/svelte-exmarkdown/renderer/Text.svelte:3:11 Text has unused export property 'position'. If it is for external reference only, please consider using `export const position`
18:13:34 [vite-plugin-svelte] /node_modules/svelte-exmarkdown/renderer/Text.svelte:4:11 Text has unused export property '__index'. If it is for external reference only, please consider using `export const __index`
18:13:34 [vite-plugin-svelte] /node_modules/svelte-exmarkdown/renderer/Children.svelte:3:11 Children has unused export property 'type'. If it is for external reference only, please consider using `export const type`
18:13:34 [vite-plugin-svelte] /node_modules/svelte-exmarkdown/renderer/Children.svelte:4:11 Children has unused export property 'position'. If it is for external reference only, please consider using `export const position`
18:13:34 [vite-plugin-svelte] /node_modules/svelte-exmarkdown/renderer/Children.svelte:5:11 Children has unused export property '__index'. If it is for external reference only, please consider using `export const __index`
18:13:34 [vite-plugin-svelte] /node_modules/svelte-exmarkdown/renderer/html/Default.svelte:5:11 Default has unused export property 'type'. If it is for external reference only, please consider using `export const type`
18:13:34 [vite-plugin-svelte] /node_modules/svelte-exmarkdown/renderer/html/Default.svelte:6:11 Default has unused export property 'position'. If it is for external reference only, please consider using `export const position`
18:13:34 [vite-plugin-svelte] /node_modules/svelte-exmarkdown/renderer/html/Default.svelte:7:11 Default has unused export property '__index'. If it is for external reference only, please consider using `export const __index`
18:13:34 [vite-plugin-svelte] ssr compile done.
package files time avg
svelte-exmarkdown-issue-repro 8 32.6ms 4.1ms
The expected output would not include the warnings.
For the moment I've added this to my svelte.config.js
export default config
object:
// Workaround for: https://github.com/ssssota/svelte-exmarkdown/issues/23
onwarn: (warning, handler) => {
if (warning?.filename?.includes('svelte-exmarkdown') && warning?.code === 'unused-export-let') {
return;
}
handler(warning);
},
Just to suppress the warning for the time being.
The library otherwise seems to work just fine, at first glance. They're just warnings, after all.
Thank you for considering. If I can assist any further: let me know!
[vite-plugin-svelte] WARNING: The following packages have a svelte field in their package.json but no exports condition for svelte.
[email protected]
How can I fix it ?
Thanks
Note: preview works fine but npm run build generate errors (but I dont know if this is related)
I think I'm going to give this package a try and am looking at the source code. Could you point out to me how it sanitizes the output?
How do you pass options to plugins ?
I tried to add remark-behead. But I need to give it some options like {depth:2}
. How is it acheived ?
import behead from 'remark-behead';
const beheadPlugin = { remarkPlugin: behead };
<Markdown plugins={[beheadPlugin]} md={...} />
Hi, I notice this error during server side rendering, with version 3.0.1:
Cannot `parse` without `parser`
Which seems to be an error throw by unified, and I can find their test case here:
And this is how I am using the markdown component. I created a wrapper like this:
<script
context="module"
lang="ts">
// @ts-expect-error no type available for this package yet, it is possible this will break in the future
import removeComments from "remark-remove-comments";
import Markdown from "svelte-exmarkdown";
import { gfmPlugin } from "svelte-exmarkdown/gfm";
</script>
<script lang="ts">
export let md: string;
</script>
<Markdown
{md}
plugins={[
gfmPlugin(),
{
remarkPlugin: [removeComments]
},
{
renderer: {
strong: "b"
}
}
]}
/>
And then use it like this:
<Markdown md={"Hello world"} />
For now I have mitigated the issue using app/environment
, and only render this component in client side. This avoided the issue, but this is not ideal for SEO
import { browser } from '$app/environment'
// …
{#if typeof data.product.description === "string" && browser}
<Markdown md={data.product.description} />
{/if}
Also downgrading to 3.0.0 does not have this error
e.g. CI
Hi, @ssssota
Great work on svelte-exmarkdown
. Thank you.
As I was trying to use it for my use case, I ran into some challenges, some highlighted in #113, but so far, the most pressing is the fact that when using this package in the Cloudflare Pages environment, they break, for reasons, more or less, related to how CF doesn't support a true node runtime - or so I hear.
These are the errors output in the console.
20:14:27.378 | ✘ [ERROR] Could not resolve "node:process"
-- | --
20:14:27.379 |
20:14:27.379 | .svelte-kit/output/server/entries/pages/_page.svelte.js:3:17:
20:14:27.380 | 3 │ import proc from "node:process";
20:14:27.380 | ╵ ~~~~~~~~~~~~~~
20:14:27.381 |
20:14:27.381 | The package "node:process" wasn't found on the file system but is built into node. Are you trying to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.
20:14:27.381 |
20:14:27.381 | ✘ [ERROR] Could not resolve "node:path"
20:14:27.381 |
20:14:27.382 | .svelte-kit/output/server/entries/pages/_page.svelte.js:4:17:
20:14:27.382 | 4 │ import path from "node:path";
20:14:27.382 | ╵ ~~~~~~~~~~~
20:14:27.382 |
20:14:27.382 | The package "node:path" wasn't found on the file system but is built into node. Are you trying to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.
20:14:27.382 |
20:14:27.382 | ✘ [ERROR] Could not resolve "node:url"
20:14:27.383 |
20:14:27.383 | .svelte-kit/output/server/entries/pages/_page.svelte.js:5:30:
20:14:27.383 | 5 │ import { fileURLToPath } from "node:url";
20:14:27.383 | ╵ ~~~~~~~~~~
20:14:27.383 |
20:14:27.383 | The package "node:url" wasn't found on the file system but is built into node. Are you trying to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.
20:14:27.383 |
20:14:27.384 | error during build:
20:14:27.384 | Error: Build failed with 3 errors:
20:14:27.384 | .svelte-kit/output/server/entries/pages/_page.svelte.js:3:17: ERROR: Could not resolve "node:process"
20:14:27.384 | .svelte-kit/output/server/entries/pages/_page.svelte.js:4:17: ERROR: Could not resolve "node:path"
20:14:27.385 | .svelte-kit/output/server/entries/pages/_page.svelte.js:5:30: ERROR: Could not resolve "node:url"
Are you aware of a project that used this package running on Cloudflare?
If not, is there a fix for people who use Cloudflare for hosting/deployments?
Thank you for the consideration.
Hi! This package works great but I'm having trouble figuring out how to customise the rendering when a special character is detected, eg. If "%%%" is detected in the markdown string, I would like to swap that part of the string with a custom svelte component. 🤞Is that possible?
By chance is there an example? I was unable to find more info online about this especially with this package..
I'm on Sveltkit 1.22, with Typescript and Tailwind CSS.
Hey, I have a question, because I tried to implement it, but I can't figure it out. Is there any way, to add custom components to the svelte-exmarkdown?
Lets imagine we have h1 text called "Test". You would type it normally as
# Test
But is there a way to f.e add a button below, that acts like a svelte component, from the text itself?
For example
# Test
<CustomButton/>
(So the user can type this and server can import these components if necessary)
In the code block, I want to add a copy action, how can I implement it?
![alt](url)
does not seem to work.
For some reason, svelte-exmarkdown is not parsing my tags, it only renders their content
<script>
import Markdown from 'svelte-exmarkdown'
async function fetchTerms() {
const termsMarkdown = await fetch(`privacy_policy.md`)
const text = await termsMarkdown.text()
return text
}
</script>
{#await fetchTerms()}
<p>Caricamento privacy policy in corso...</p>
{:then source}
<h1 class="mb-9 whitespace-nowrap text-blue-400">Informativa Privacy</h1>
<div class="prose pb-9">
<Markdown md={source} />
</div>
{/await}
現時点で最新のsveltekitのバージョンで本サンプルを作成してnetlifyにデプロイすると下記エラーになってしまいます。
500
require() of ES Module /var/task/node_modules/remark-parse/index.js from /var/task/.netlify/server/entries/pages/index.svelte.js not supported.
Instead change the require of index.js in /var/task/.netlify/server/entries/pages/index.svelte.js to a dynamic import() which is available in all CommonJS modules.
Error [ERR_REQUIRE_ESM]: require() of ES Module /var/task/node_modules/remark-parse/index.js from /var/task/.netlify/server/entries/pages/index.svelte.js not supported.
Instead change the require of index.js in /var/task/.netlify/server/entries/pages/index.svelte.js to a dynamic import() which is available in all CommonJS modules.
Firstly I want to say thank you for making this!
I've been building a small interface for your renderer using skeleton for fun.
markdown
The trouble I've been having is adding in more complicated remark/rehype plugins like Mermaid and Math. Is there an example of how to accomplish this or is it not currently possible?
Thank you for your time.
Hi! I would like to support a subset of markdown syntax: Only bold, cursive, strikethrough and automatic links (so https://google.com
becomes https://google.com). I don't understand how I can do that with this package.
I found the documentation for writing custom elements here: https://ssssota.github.io/svelte-exmarkdown/docs/03-override-component.
However it is not clear how to override links. I mean both links like [Duck Duck Go](https://duckduckgo.com)
and also automatically convert URL in normal text to link. There is also no list of the default renderers which would be useful to see. Perhaps something like that could be added to the documentation? 🙏
Lastly, I would like to know how to configure bundle splitting in an efficient way, as I would like to not bundle all the default renderers in my application as they are not used.
Thank you!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.