content
content copied to clipboard
Resolve assets in markdown content
I would like to know if it's possible to have the webpack assets resolution inside of markdown content ? To display webpack handeled's images.
Reproduction link: https://codesandbox.io/s/dawn-snowflake-fv7l4?file=/content/post.md
- I have an image in the assets folder
- I link the image in the md file
(or<img src="~/assets/photo.jpg">in html) the same way I would have in a component template
I'm not interested in putting files in the static folder since there is no compression and no hash for cache-busting.
As far as I know, this is currently not supported out of the box.
Maybe you can solve this with a component that dynamically loads the image for you, something like this? https://codesandbox.io/s/nuxt-content-106-hwhbv?file=/content/post.md
Yeah I thought about a solution like that, but not really compliant with content management tools :/
Hi there,
The main issue here is that @nuxt/content is independent of Webpack, meaning that if you change anything in content/ you can directly run nuxt export (Nuxt 2.13) without having to wait for Webpack to build.
We are thinking of a way to support assets/images/ with Webpack dynamic import so it can still support nuxt export without having to build again (expect if you add an image in assets/images/)
I see it was removed from the todo list. Any update on the situation of this feature request?
Bumping, would love an update seeing as it has been removed from the To do?
Don't pay too much attention to the todo list, we use it internally to plan the next release.
We have considered this issue and will be working on it soon.
The tricky part is to not involve Webpack for it when using images since it would force a rebuild and loose te speed of content update. This is why it is not an such easy task 😁
@Atinux might overwriting the html img tag by a custom component with the same attributes work for this case? Maybe even as an opt in? 🤔
Indeed your solution was quite good actually, if you can open a PR so we can work on it it would be great :)
The tricky part is to not involve Webpack
@Atinux Maybe I'm missing something but why wouldn't I want webpack involved doing it's thing? Wouldn't I want webpack to rerun if content involving a webpack asset gets updated?
The idea behing content is that you can change your Markdown without rebuilding your entire Nuxt app, making it faster redeployment.
Tracking assets is a bit more tricky in that case since Content does not depend of Webpack at all.
I fiddled around with it today and think I understood the way in which it could be implemented.
I would be really interested in your thoughts about the API design. Should we support both, markdown images and HTML tags?

<img src="~/assets/localimage.jpg" alt="image alt text>
I have a few doubts about using the default tags and attributes because in this case, we would've to check if the developer is trying to load a local asset or remote image.
Maybe we could avoid this check by adding a custom attribute:
<img local-src="~/assets/localimage.jpg" alt="image alt text>
Yeah both should be supported, this will give more control since you can't do basic things like center an image with markdown
Is it possible to store the images under the content directory itself instead of in the assets directory? Then you could create a structure like:
content/articles/my-new-article/index.md content/articles/my-new-article/img/pic1.jpg content/articles/my-new-article/img/pic2.jpg content/articles/my-new-article/img/pic3.jpg
which would keep all the content together.
Yes but this should not be the only solution.. again to have more control pointing to a specific folder is useful in case someone wants to use a CDN/reverse proxy to serve the images.
@davydnorris suggestion was helpful to me
I created a global Image component to work around with that and stored my images inside the /content/blog/my-blog-slug/images/
<template>
<img :src="imgSrc()" :alt="alt" />
</template>
<script>
export default {
props: {
src: {
type: String,
required: true
},
alt: {
type: String,
required: true
}
},
methods: {
imgSrc() {
try {
return require(`~/content${this.src}`)
} catch (error) {
return null
}
}
}
}
</script>
Make sure to register this component globally.
Inside components/global/Image.vue and set the components:true in nuxt.config.js
<image
v-if="blog.Featured_Image"
:src="blog.dir + '/images/' + blog.Featured_Image"
:alt="blog.Title"
>
</image>
Inside Markdown:
<image src="/blog/my-blog-slug/images/Scripts.png" alt="Scripts"></image>
I hope this will be helpful to someone. 🙌
I did the same thing but I am getting warnings when I compile the files of the form:
WARNING in ./content/blog/2020-02-15-blog-number-3/index.md 1:2
Module parse failed: Assigning to rvalue (1:2)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> ---
| title: 'Blog #3 Headline'
| description: Lorem Ipsum type stuff
@ . sync ^\.\/content.*$ ./content/blog/2020-02-15-blog-number-3/index.md
@ ./node_modules/babel-loader/lib??ref--2-0!./node_modules/vue-loader/lib??vue-loader-options!./components/BlogImage.vue?vue&type=script&lang=js&
@ ./components/BlogImage.vue?vue&type=script&lang=js&
@ ./components/BlogImage.vue
@ ./node_modules/babel-loader/lib??ref--2-0!./node_modules/vue-loader/lib??vue-loader-options!./pages/blog/_slug.vue?vue&type=script&lang=js&
@ ./pages/blog/_slug.vue?vue&type=script&lang=js&
@ ./pages/blog/_slug.vue
@ ./.nuxt/router.js
@ ./.nuxt/index.js
@ ./.nuxt/client.js
@ multi ./.nuxt/client.js
I thought I could ignore the warning, however when I then try to run export or dev, the process hangs and never completes, and I see the above warning in the generated javascript instead of the actual content.
I'm not a webpack/babel config file expert, but it looks like the error is from webpack when it goes looking for the image files. I assume you could write a rule to exclude the md files somehow? But then would that mess up the content generation?
Any help would be greatly appreciated
Unfortunately, this is the only solution worked for me. I have the same warnings. However, it doesn't affect the build process.
OK so I have made progress...
I couldn't work out why my images were being converted during the build but their paths weren't - then I realised that the images I happened to be using were IMG_xxxx.JPG and I had them in the code as IMG_xxxx.jpg. As soon as I made them exactly the same they all got picked up.
Still trying to get the custom image component inside the .md to work - @MuhaddiMu did you register yours as a global?
@davydnorris My Image component is registered globally. I have a working example, you can check that too by cloning https://github.com/MuhaddiMu/Portfolio
Many thanks - I have now got it working 🥇
The components directive doesn't seem to do exactly what it says in the guide. I had set up a subdirectory specifically for blog components, called 'content', and had registered that in my nuxt config with:
components: [
'~/components/content'
]
but it didn't seem to work. I then moved the components into the top level and set components:true, but still no luck.
It finally worked when I copied your example exactly and added a 'global' subdirectory with components:true.
Thank you for all your assistance!!
Besides images used in HTML and markdown, what about images referenced in frontmatter? I've had to add these to static/images in order for this to work instead of assets.
img: /images/journey-ux.jpg
alt: Rocket soaring through space
This were actually the first ones I got to work. I used the same approach as above but could use a normal component in my _slug.vue and preview components:
<template>
<div>
<v-img
:src="require(`@/content${post.dir}/img/${post.image}`)"
:alt="post.title"
height="400"
/>
<h1>{{ post.title }}</h1>
<p>
{{ post.description }}
</p>
<nuxt-content
:document="post"
/>
</div>
</template>
<script>
export default {
async asyncData ({ params, error, $content }) {
try {
const postPath = `/blog/${params.slug}`;
const [post] = await $content('blog', { deep: true })
.where({ dir: postPath })
.fetch();
return { post };
} catch (err) {
error({
statusCode: 404,
message: 'Page could not be found'
});
}
}
};
</script>
in your case you've already included the image subdirectory so just adjust the template accordingly
@davydnorris Regarding the Module parse failed: Assigning to rvalue (1:2) error. Using ignore-loader solved this for me:
// nuxt.config.js
// ...
build: {
extend(config, { isDev, isClient }) {
config.module.rules.push({
test: /\.md$/i,
loader: 'ignore-loader'
})
}
}
// ...
Many thanks @lucien144 - that's exactly what I was hoping someone would know! Will try that tomorrow
My original point was to be able using the webpack asset management for images (compression, cache-busting), while writing posts on content management tools. For that, it's needs to work with vanilla , and not some custom vuejs elements.
Hi there,
The main issue here is that @nuxt/content is independent of Webpack, meaning that if you change anything in
content/you can directly runnuxt export(Nuxt 2.13) without having to wait for Webpack to build.We are thinking of a way to support
assets/images/with Webpack dynamic import so it can still supportnuxt exportwithout having to build again (expect if you add an image inassets/images/)
What about linking to assets that are not images? For example, linking to a local pdf file with [A file](/assets/sample.pdf) in the markdown? It's not mentioned on this thread but I presume it's essentially the same issue?
Yes. Assets from Markdown written with fully qualified URL ~/images/ to be resolvable either from Vue pages/ or components/ components as equal to from a Markdown file. I'm assuming we could have the place where to store those as configurable. Either from static, or from content, or assets. So we avoid having more than one notation for the same resource and the resource resolver in its context (remark's toTHML, or WebPack, or vite) to pick which ever its running.
So many ugly crutches just to render image from Markdown, oh God. Nuxt is so 'intuitive' that I had less time to do it by myself with 11ty or at my self made ssg on Python.
extend(config, { isDev, isClient }) { config.module.rules.push({ test: /\.md$/i, loader: 'ignore-loader' }) }
now page with image doesn't render at all, thank you very much!