-
-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
"[WARN] Cannot stringify a function render" after upgrade to 3.x #83
Comments
That seems not this loader's problem. Since Not sure why I'd like to think about supporting "stringify-ed exports" as well as previous versions if there is a reasonable use-case, but I'm not convinced by the approach of |
btw component mode might be easier to use. Here's my recent dynamic-markdown-ish implement with Nuxt. (And I'm planning to remove <client-only>
<component :is="episodeContent" />
</client-only> episodeContent: Function | null = null;
attributes: any = {};
@Prop({ type: String, required: true }) slug!: string;
@Prop({ type: Boolean, default: false }) expand!: boolean;
created () {
this.episodeContent = () => import(`~/static/episodes/${this.slug}.md`).then((c) => {
this.attributes = c.attributes;
return {
extends: c.vue.component
};
});
} |
Thank you for the quick response! I like the Sounds good. I'm a bit unclear about this code block:
Where does that need to go? I'm afraid I've not used Vue dynamic components before. 😬 Thanks for your help! |
@hmsk A couple of questions:
|
@joshukraine thanks for waiting for my late second reply 🙃 The code block is just pasted from my project (TypeScript + property-decorator), so that might confuse you. Below is the minimum code of SFC to render markdown and attributes. <template>
<div>
<h1>{{ attributes.title }}</h1>
<component :is="markdownContent" />
</div>
</template>
<script>
export {
props: {
slug: String
},
data () {
return {
markdownContent: null,
attributes: null
}
},
created () {
this.markdownContent = () => import(`~/static/episodes/${this.slug}.md`).then((md) => {
this.attributes = md.attributes;
return {
extends: md.vue.component
};
}
}
</script> Ref (The repo is the original use-case of frontmatter-markdown-loader before I founded): |
Basically, should work for SSR without Originally, I mentioned about If you have any trouble, provide a reproducible repository. I'm happy to look into.
Interesting. Could you give actual codes to manipulate resulting node tree...? {
extends: md.vue.component,
created () {
// find words and give style
}
} |
Of course. Here's the
Where would I search for the highlighted text with |
* Thank you, @hmsk! * Reference: hmsk/frontmatter-markdown-loader#83 (comment)
@hmsk Thank you so much for your reply and the example code! That helped tremendously. I've implemented your solution in my blog and for the most part it works as you demonstrate in your code sample. (FWIW, you have a couple of typos in that code.) Anyway, the one thing that does not seem to work as intended is the frontmatter. The But if I reference it anywhere in the view template, the whole page crashes with a TypeError: <!-- components/DynamicMarkdown.vue -->
<template>
<div>
<p>Post title: {{ attributes.title }}</p>
<component :is="markdownContent" />
</div>
</template> For my use case it's actually not a big deal since I am loading the frontmatter in a different way. But I think for many people it would be an issue. If it helps, my Nuxt blog is now complete and I've open sourced the repo. The FML 3.x upgrade is in this PR: joshukraine/ofreport.com#44 Thank you again for your help! 😃 |
@Strahinja Let me move our discussion into the another issue #86 to avoid running multiple discussions on the single thread 😉 |
Haha, that might be. I didn't run that code actually 🙈
I guess the title requires null-check since the attributes are provided asynchronously 🤔 <p v-if="attributes">Post title: {{ attributes.title }}</p> And thanks for giving me coffees on https://www.buymeacoffee.com/hmsk 🙏 I really appreciate and am honored. |
Aha, of course! That worked. 🙂 As far as I'm concerned, that resolves this issue, so I'll go ahead and close. Thanks again, and have an awesome day! 😎🙌🏻 |
This might be a lot to ask, however it would be amazing if we could actually load the vue component inside of nuxt asyncData. Loading the component in asyncData makes it load server side, which slightly increases the performance, but most importantly it allows the page to be loaded without javascript. Not quite sure how that could be implemented though, perhaps a custom serializer? |
That's a good point I hadn't thought of earlier. This worked in 2.x by passing the function as a string. @hmsk Perhaps it would be possible to provide this as an option? I think you had mentioned something to that effect in a previous comment above:
Seems like pre-rendering the content with asyncData (or at least making it possible as an option) would have benefits not only for performance but for SEO. Would love to hear your thoughts! 🙂 |
Hmmm, I don't think we need to persist in using
Eventually, I prefer to remove exporting Even so, you love to use |
Thanks for the clarification. I was thinking that when importing the markdown inside |
@hmsk I'm not sure if I misunderstand something or Nuxt treats SSR process differently from native Vue. However I tested it on my Nuxt server and the contents are not rendered before running JS (tried cURL-ing it as well with same result). I can put together an example repository if you want.
That is an interesting idea, but I could not get it to work. However, while tinkering with it I stumbled upon something that sort of works: <template>
<component :is="{...markdownComponent}" />
</template>
<script>
export default {
async asyncData ({ params }) {
const file = await import(`~/content/${params.category}/${params.slug}.md`)
return {
markdownComponent: {
data: file.vue.component.data,
render: file.vue.component.render,
created: file.vue.component.created
}
}
}
}
</script> This still throws the "Cannot stringify a function" warning (3 of them now, since we're stringifying 3 functions), but renders everything successfully. EDIT: This seems to only work before running JS now (client JS throws a lot of errors), obviously not a solution. |
Go for it. I will see later.
I couldn't see any serialization on your code 👀
Yeah, server side processing of |
Here it is, running it in SSR mode and cURL-ing it returns an empty page. It loads after client JS has been run. Pre-rendering it also returns an empty page.
Haha, should've clarified more I guess. Yes that code doesn't contain any serialization since I wasn't successful with it, but that code was something I stumbled upon while tinkering. The reason I could not get serialization to work was because |
You're not using Async Components correctly. diff --git a/pages/index.vue b/pages/index.vue
index 7637a37..7baa8ad 100644
--- a/pages/index.vue
+++ b/pages/index.vue
@@ -8,8 +8,10 @@
export default {
data: () => ({component: null}),
async created() {
- const file = await import('~/README.md');
- this.component = file.vue.component
+ this.component = async () => {
+ const file = await import('~/README.md');
+ return file.vue.component;
+ }
}
}
</script> The original code seems to work for the client side in coincidence unfortunately 🙃 |
Thanks, that solves my use case. Never used async components, learn something new about Vue everyday 😃 If you don't mind I've submitted a PR #89 with a few Nuxt examples that you helped me figure out. I have one more question but I feel it's more appropriate to be discussed in the PR. |
@joshukraine , From your example, I think you're using Nuxt Markdown Blog starter from @marinaaisa. I've created PR to solve this issue and it already merged as well, marinaaisa/nuxt-markdown-blog-starter#9 |
@jefrydco Thanks for the heads-up! I'm not using Nuxt Markdown Blog per se, although I did reference it heavily while developing my own blog. I actually did see your PR, and I'd like to look through it a little more thoroughly when I get time. Thanks again! 🙂 |
When trying to load the contents in asyncData, I came across these errors. The stack size and cannot stringify plagued me for a couple of days. So, just a late reply to this. I wanted to SSR the content and the attributes which seemed to be loading late, not being available with JS disabled. I achieved it with this slightly wet but no-doubt effective solution: async asyncData ({ params }) {
const post = await import(`~/content/blog/${params.slug}.md`)
return {
attributes: post.attributes,
}
},
created () {
this.markdownContent = () => import(`~/content/blog/${this.$route.params.slug}.md`).then((md) => {
return {
extends: md.vue.component
}
})
}, |
@lukeocodes Right. Unfortunately, Vue's async component feature only handles component importing for SSR. so, created () {
this.selectedArticle = () => {
return import(`~/articles/${this.$route.query.name}.md`).then(({ vue, attributes }) => {
this.attributes = attributes
return vue.component
})
}
} doesn't work for created () {
const markdown = require(`~/articles/${this.$route.params.slug}.md`)
this.attributes = markdown.attributes
this.markdownContent = markdown.vue.component
} Nuxt team recently released "content module", that may solve all markdown handling in Nuxt without this loader 😉 |
I've been building a static blog with Nuxt.js, and I'm using
frontmatter-markdown-loader
with[Mode.VUE_RENDER_FUNCTIONS]
to render Markdown pages and posts which contain Vue components. This was working great on v2.3.0, but after upgrading to v3.1.0, I cannot properly render Markdown files which are loaded dynamically using Nuxt'sasyncData
function.Here's my dynamic render component:
And here is the page component for individual blog posts:
This works if I link to a blog post from somewhere else in the app (ie, the post is rendered client-side). However, if I reload the page, or if I visit the permalink directly, the page crashes and I see several errors. In the browser console, I get
TypeError: this.templateRender is not a function
.And in the terminal I see two warnings:
WARN Cannot stringify a function render
andWARN Cannot stringify a function
.With FML version 2.3.0, this approach worked fine, both with client-side and server-side rendering.
Another releveant bit of information is that if I first load a Markdown file at the top of my
<script>
section using regular ES6 module syntax, everything works fine.The following code allows the page to be loaded either client-side or server-side:
Obviously, the previous code example is not practical since blog posts must be loaded dynamically by extracting the file name from params. Hence the need for
asyncData
imports.In summary, if I import a Markdown file using ES6 module syntax, everything works. But if I import it inside
asyncData
it breaks.If it helps to see a complete app that demonstrates this issue, please have a look at nuxt-markdown-blog-starter by @marinaaisa. I referenced her code a lot when building my own blog (thank you, @marinaaisa!), and after she recently upgraded FML to v3.0.0, her app manifests the exact problem I have described above.
I am aware that FML v3.0.0 introduced breaking changes, and as best I can tell the root issue is that
vue.render
andvue.staticRenderFns
now return functions instead of strings. I've looked at your source code to try and find a workaround, but I'm afraid my understanding of Vue render functions is too rudimentary.Thank you for all your work on
frontmatter-markdown-loader
. I really love this project since it enables Vue components to be embedded in Markdown files. This is a huge win for blogging, and I really hope a solution can be found to allow forasyncData
file imports. I would appreciate any help or advice you can offer on this issue!The text was updated successfully, but these errors were encountered: