Skip to content
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

feat(markdown): support relative image link without ./ #1103

Merged
merged 2 commits into from May 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 10 additions & 2 deletions docs/guide/assets.md
Expand Up @@ -8,6 +8,12 @@ You can reference any assets using relative URLs in your Markdown content:
![An image](./image.png)
```

or

```md
![An image](image.png)
```
meteorlxy marked this conversation as resolved.
Show resolved Hide resolved

This is generally the suggested way to import images, as users usually place images near the Markdown file that references them.

## Public Files
Expand Down Expand Up @@ -86,8 +92,10 @@ Although it is not a common usage, you can reference images from dependent packa
npm install -D package-name
```

Since markdown image syntax regards image links as relative paths by default, you need to use `<img>` tag:

```md
![Image from dependency](package-name/image.png)
<img src="package-name/image.png" alt="Image from dependency">
```

The path aliases that set in config file are also supported:
Expand All @@ -105,7 +113,7 @@ export default {
```

```md
![Image from path alias](@alias/image.png)
<img src="@alias/image.png" alt="Image from path alias">
```

::: tip
Expand Down
12 changes: 10 additions & 2 deletions docs/zh/guide/assets.md
Expand Up @@ -8,6 +8,12 @@
![图片](./image.png)
```


```md
![图片](image.png)
```

一般情况下,我们推荐你使用这种方式来引用图片,因为人们通常会把图片放在引用它的 Markdown 文件附近。

## Public 文件
Expand Down Expand Up @@ -86,8 +92,10 @@ const logoPath = ref('/images/hero.png')
npm install -D package-name
```

由于 Markdown 会默认将图片链接视为相对链接,你需要使用 `<img>` 标签:

```md
![来自依赖包的图片](package-name/image.png)
<img src="package-name/image.png" alt="来自依赖包的图片">
```

在配置文件中设置的路径别名也同样支持:
Expand All @@ -105,7 +113,7 @@ export default {
```

```md
![来自路径别名的图片](@alias/image.png)
<img src="@alias/image.png" alt="来自路径别名的图片">
```

::: tip
Expand Down
6 changes: 4 additions & 2 deletions packages/markdown/src/plugins/assetsPlugin/assetsPlugin.ts
Expand Up @@ -46,7 +46,8 @@ export const assetsPlugin: PluginWithOptions<AssetsPluginOptions> = (
`${prefix}${quote}${resolveLink(
src.trim(),
relativePathPrefix,
env
env,
true
)}${quote}`
)
// handle srcset
Expand All @@ -64,7 +65,8 @@ export const assetsPlugin: PluginWithOptions<AssetsPluginOptions> = (
`${resolveLink(
url.trim(),
relativePathPrefix,
env
env,
true
)}${descriptor.replace(/[ \n]+/g, ' ').trimEnd()}`
)
)
Expand Down
12 changes: 10 additions & 2 deletions packages/markdown/src/plugins/assetsPlugin/resolveLink.ts
Expand Up @@ -5,14 +5,22 @@ import type { MarkdownEnv } from '../../types.js'
export const resolveLink = (
link: string,
relativePathPrefix: string,
env: MarkdownEnv
env: MarkdownEnv,
strict = false
): string => {
// decode link to ensure bundler can find the file correctly
let resolvedLink = decode(link)

// check if the link is relative path
const isRelativePath = strict
? // in strict mode, only link that starts with `./` or `../` is considered as relative path
/^\.{1,2}\//.test(link)
: // in non-strict mode, link that does not start with `/` and does not have protocol is considered as relative path
!link.startsWith('/') && !/[A-z]+:\/\//.test(link)

// if the link is relative path, and the `env.filePathRelative` exists
// add `@source` alias to the link
if (/^\.{1,2}\//.test(link) && env.filePathRelative) {
if (isRelativePath && env.filePathRelative) {
resolvedLink = `${relativePathPrefix}/${path.join(
path.dirname(env.filePathRelative),
resolvedLink
Expand Down
76 changes: 34 additions & 42 deletions packages/markdown/tests/plugins/assetsPlugin.spec.ts
Expand Up @@ -15,20 +15,18 @@ describe('@vuepress/markdown > plugins > assetsPlugin', () => {
'![out](../../out.png)',
'![汉字](./汉字.png)',
'![100%](./100%.png)',
// aliases
'![alias](@alias/foo.png)',
'![汉字](@alias/汉字.png)',
'![100%](@alias/100%.png)',
// webpack legacy aliases
'![~alias](~@alias/foo.png)',
'![~汉字](~@alias/汉字.png)',
'![~100%](~@alias/100%.png)',
meteorlxy marked this conversation as resolved.
Show resolved Hide resolved
// absolute paths
'![absolute](/absolute.png)',
'![absolute-foo](/foo/absolute.png)',
// no-prefix paths
'![no-prefix](no-prefix.png)',
'![no-prefix-foo](foo/no-prefix.png)',
'![alias](@alias/foo.png)',
'![汉字](@alias/汉字.png)',
'![100%](@alias/100%.png)',
'![~alias](~@alias/foo.png)',
'![~汉字](~@alias/汉字.png)',
'![~100%](~@alias/100%.png)',
// keep as is
'![url](http://foobar.com/icon.png)',
'![empty]()',
Expand Down Expand Up @@ -60,27 +58,25 @@ describe('@vuepress/markdown > plugins > assetsPlugin', () => {
'<img src="@source/../out.png" alt="out">',
'<img src="@source/sub/汉字.png" alt="汉字">',
'<img src="@source/sub/100%.png" alt="100%">',
// aliases
'<img src="@alias/foo.png" alt="alias">',
'<img src="@alias/汉字.png" alt="汉字">',
'<img src="@alias/100%.png" alt="100%">',
// webpack legacy aliases
'<img src="~@alias/foo.png" alt="~alias">',
'<img src="~@alias/汉字.png" alt="~汉字">',
'<img src="~@alias/100%.png" alt="~100%">',
// absolute paths
'<img src="/absolute.png" alt="absolute">',
'<img src="/foo/absolute.png" alt="absolute-foo">',
// no-prefix paths
'<img src="no-prefix.png" alt="no-prefix">',
'<img src="foo/no-prefix.png" alt="no-prefix-foo">',
'<img src="@source/sub/no-prefix.png" alt="no-prefix">',
'<img src="@source/sub/foo/no-prefix.png" alt="no-prefix-foo">',
'<img src="@source/sub/@alias/foo.png" alt="alias">',
'<img src="@source/sub/@alias/汉字.png" alt="汉字">',
'<img src="@source/sub/@alias/100%.png" alt="100%">',
'<img src="@source/sub/~@alias/foo.png" alt="~alias">',
'<img src="@source/sub/~@alias/汉字.png" alt="~汉字">',
'<img src="@source/sub/~@alias/100%.png" alt="~100%">',
// keep as is
'<img src="http://foobar.com/icon.png" alt="url">',
'<img src="" alt="empty">',
// invalid paths
'<img src=".../invalid.png" alt="invalid">',
'<img src=".../汉字.png" alt="汉字">',
'<img src=".../100%.png" alt="100%">',
'<img src="@source/sub/.../invalid.png" alt="invalid">',
'<img src="@source/sub/.../汉字.png" alt="汉字">',
'<img src="@source/sub/.../100%.png" alt="100%">',
],
},
{
Expand All @@ -101,27 +97,25 @@ describe('@vuepress/markdown > plugins > assetsPlugin', () => {
'<img src="@foo/../out.png" alt="out">',
'<img src="@foo/sub/汉字.png" alt="汉字">',
'<img src="@foo/sub/100%.png" alt="100%">',
// aliases
'<img src="@alias/foo.png" alt="alias">',
'<img src="@alias/汉字.png" alt="汉字">',
'<img src="@alias/100%.png" alt="100%">',
// webpack legacy aliases
'<img src="~@alias/foo.png" alt="~alias">',
'<img src="~@alias/汉字.png" alt="~汉字">',
'<img src="~@alias/100%.png" alt="~100%">',
// absolute paths
'<img src="/absolute.png" alt="absolute">',
'<img src="/foo/absolute.png" alt="absolute-foo">',
// no-prefix paths
'<img src="no-prefix.png" alt="no-prefix">',
'<img src="foo/no-prefix.png" alt="no-prefix-foo">',
'<img src="@foo/sub/no-prefix.png" alt="no-prefix">',
'<img src="@foo/sub/foo/no-prefix.png" alt="no-prefix-foo">',
'<img src="@foo/sub/@alias/foo.png" alt="alias">',
'<img src="@foo/sub/@alias/汉字.png" alt="汉字">',
'<img src="@foo/sub/@alias/100%.png" alt="100%">',
'<img src="@foo/sub/~@alias/foo.png" alt="~alias">',
'<img src="@foo/sub/~@alias/汉字.png" alt="~汉字">',
'<img src="@foo/sub/~@alias/100%.png" alt="~100%">',
// keep as is
'<img src="http://foobar.com/icon.png" alt="url">',
'<img src="" alt="empty">',
// invalid paths
'<img src=".../invalid.png" alt="invalid">',
'<img src=".../汉字.png" alt="汉字">',
'<img src=".../100%.png" alt="100%">',
'<img src="@foo/sub/.../invalid.png" alt="invalid">',
'<img src="@foo/sub/.../汉字.png" alt="汉字">',
'<img src="@foo/sub/.../100%.png" alt="100%">',
],
},
{
Expand All @@ -139,20 +133,18 @@ describe('@vuepress/markdown > plugins > assetsPlugin', () => {
'<img src="../../out.png" alt="out">',
'<img src="./汉字.png" alt="汉字">',
'<img src="./100%.png" alt="100%">',
// aliases
'<img src="@alias/foo.png" alt="alias">',
'<img src="@alias/汉字.png" alt="汉字">',
'<img src="@alias/100%.png" alt="100%">',
// webpack legacy aliases
'<img src="~@alias/foo.png" alt="~alias">',
'<img src="~@alias/汉字.png" alt="~汉字">',
'<img src="~@alias/100%.png" alt="~100%">',
// absolute paths
'<img src="/absolute.png" alt="absolute">',
'<img src="/foo/absolute.png" alt="absolute-foo">',
// no-prefix paths
'<img src="no-prefix.png" alt="no-prefix">',
'<img src="foo/no-prefix.png" alt="no-prefix-foo">',
'<img src="@alias/foo.png" alt="alias">',
'<img src="@alias/汉字.png" alt="汉字">',
'<img src="@alias/100%.png" alt="100%">',
'<img src="~@alias/foo.png" alt="~alias">',
'<img src="~@alias/汉字.png" alt="~汉字">',
'<img src="~@alias/100%.png" alt="~100%">',
// keep as is
'<img src="http://foobar.com/icon.png" alt="url">',
'<img src="" alt="empty">',
Expand Down