Vuepress: Support PDF (hosted)

Created on 6 Aug 2018  路  12Comments  路  Source: vuejs/vuepress

Feature request

Currently we can add images to our documents. But would be great to also be able to add PDF documents.

What problem does this feature solve?

We could add a PDF to our documents - which are common when creating knowledgebase style websites

How should this be implemented in your opinion?

In createBaseConfig.js , change the rule so it transfers PDFs to the assets as well as images

(Not tested this, but think that that is the code that needs extending)

  config.module
    .rule('images')
      .test(/\.(png|jpe?g|gif)(\?.*)?$/)
      .use('url-loader')
        .loader('url-loader')
        .options({
          limit: inlineLimit,
          name: `assets/img/[name].[hash:8].[ext]`
        })

Are you willing to work on this yourself?

No

Most helpful comment

I encountered the same problem and have finally worked out a solution.

The solution

Add the following in .vuepress/config.js:

  chainWebpack: (config, isServer) => {
    config.module
      .rule('pdfs')
      .test(/\.pdf$/)
      .use('file-loader')
        .loader('file-loader')
      .options({
        name: `[path][name].[ext]`
      });

    config.module.rule('vue')
      .uses.store
      .get('vue-loader').store
      .get('options').transformAssetUrls = {
        video: ['src', 'poster'],
        source: 'src',
        img: 'src',
        image: ['xlink:href', 'href'],
        a: 'href'
      };
  },

How I found it

What I need is to have some pdf documents along side the markdown files, and can be linked from markdown files.

For example, say I have a xxx.md and I would like to link to a yyy.pdf just beside it like it's a natural part of the document, not to place it under assets or public.

I can't get this to work in plain vuepress. After some search, I found this issue and what vuepress did for images, fonts etc. in https://github.com/vuejs/vuepress/blob/master/packages/%40vuepress/core/lib/webpack/createBaseConfig.js :

  config.module
    .rule('images')
      .test(/\.(png|jpe?g|gif)(\?.*)?$/)
      .use('url-loader')
        .loader('url-loader')
        .options({
          limit: inlineLimit,
          name: `assets/img/[name].[hash:8].[ext]`
        })
// ...
  config.module
    .rule('svg')
      .test(/\.(svg)(\?.*)?$/)
      .use('file-loader')
        .loader('file-loader')
        .options({
          name: `assets/img/[name].[hash:8].[ext]`
        })

So I add the following in .vuepress/config.js:

  chainWebpack: (config, isServer) => {
    config.module
      .rule('pdfs')
      .test(/\.pdf$/)
      .use('file-loader')
        .loader('file-loader')
      .options({
        name: `[path][name].[ext]`
      });
  },

It should work like images but it didn't.

But if I link to the pdf as an image somewhere in a markdown file, then it works ( pdf is copied to the some directory structure due to the [path] in option name ).

I used this image hack for a while, until I found https://github.com/vuejs/vuepress/issues/826 and noticed https://github.com/vuejs/vue-loader/blob/master/docs/zh/guide/asset-url.md and realized what made images special, it's not something in vuepress but vueloader.

Combine these two options together, it worked. I don't know if there's any side effects yet, but it doesn't seem to affect how vuepress handles markdown file links.

Hope it helps.

All 12 comments

yeah. PDF-function would be great. I am trying to implement this via vue-pdf.

But I am very new to programming and learn JS basics right now.

I have installed this package vie yarn and I have it as a node-module right now. It is also entried in the package.json as a dependency. But I am struggeling with the "import" function :s

Nevertheless, isn麓t Vue-PDF a solution for this?

I didnt want to embed the PDF files, I only want to redirect, but I get the Error "not found". I used [Titel](/direction/document.pdf)

Hey @equaliser0 I am talking about being able to incorporate PDFs INTO a knowledgbase style website - i.e. PDFs handled the same as images - in that webpack transfers them to the right (new) location on build

I think you are talking something very different - generating PDFs out of markup files.....

Hey hey. No I dont mean generating PDF. I only want to redirect them. For example as a simple link.

[Titel](/direction/document.pdf)

So it opens the pdf in a new tab/window. This is all I need. But it doesnt work because of not found.

If I redirect to a pdf which is on a webserver (http) it works. But if I have a pdf inside of docs I cant redirect, because PDF cant get parsed inside of vuepress.

I encountered the same problem and have finally worked out a solution.

The solution

Add the following in .vuepress/config.js:

  chainWebpack: (config, isServer) => {
    config.module
      .rule('pdfs')
      .test(/\.pdf$/)
      .use('file-loader')
        .loader('file-loader')
      .options({
        name: `[path][name].[ext]`
      });

    config.module.rule('vue')
      .uses.store
      .get('vue-loader').store
      .get('options').transformAssetUrls = {
        video: ['src', 'poster'],
        source: 'src',
        img: 'src',
        image: ['xlink:href', 'href'],
        a: 'href'
      };
  },

How I found it

What I need is to have some pdf documents along side the markdown files, and can be linked from markdown files.

For example, say I have a xxx.md and I would like to link to a yyy.pdf just beside it like it's a natural part of the document, not to place it under assets or public.

I can't get this to work in plain vuepress. After some search, I found this issue and what vuepress did for images, fonts etc. in https://github.com/vuejs/vuepress/blob/master/packages/%40vuepress/core/lib/webpack/createBaseConfig.js :

  config.module
    .rule('images')
      .test(/\.(png|jpe?g|gif)(\?.*)?$/)
      .use('url-loader')
        .loader('url-loader')
        .options({
          limit: inlineLimit,
          name: `assets/img/[name].[hash:8].[ext]`
        })
// ...
  config.module
    .rule('svg')
      .test(/\.(svg)(\?.*)?$/)
      .use('file-loader')
        .loader('file-loader')
        .options({
          name: `assets/img/[name].[hash:8].[ext]`
        })

So I add the following in .vuepress/config.js:

  chainWebpack: (config, isServer) => {
    config.module
      .rule('pdfs')
      .test(/\.pdf$/)
      .use('file-loader')
        .loader('file-loader')
      .options({
        name: `[path][name].[ext]`
      });
  },

It should work like images but it didn't.

But if I link to the pdf as an image somewhere in a markdown file, then it works ( pdf is copied to the some directory structure due to the [path] in option name ).

I used this image hack for a while, until I found https://github.com/vuejs/vuepress/issues/826 and noticed https://github.com/vuejs/vue-loader/blob/master/docs/zh/guide/asset-url.md and realized what made images special, it's not something in vuepress but vueloader.

Combine these two options together, it worked. I don't know if there's any side effects yet, but it doesn't seem to affect how vuepress handles markdown file links.

Hope it helps.

Any updates on this? I'm looking for a way to include non-image assets for each markdown page. Some of our documentation pages need to have download links. I don't want to dump everything into the public folder or host them somewhere else. @utensil's solution looks promising, but it would be great if vuepress supports this feature (not just pdf, any file type).

Hi, @alexbainbridge . I found a pretty simple solution: use iframe tag. You can directly insert the following lines to your markdown file.

For online pdf:
<iframe src="http://tug.ctan.org/info/undergradmath/undergradmath.pdf" width="100%" height="600"></iframe>
Be sure the online pdf can be viewed in your browser.

For pdf in you vuepress project:
<iframe src="/images/linux/linux_tools/latex/latexsheet-a4.pdf" width="100%" height="600"></iframe>

We are trying to download assets different to PDF (i.e, YAML, bash scripts, zip files), and the solution suggested by @utensil seems to be working great!

It would be so cool if vuepress could detect automatically file types other than .vue, .md to copy into the right path for usage with relative paths.

We ended up mimicking the assets path in public folder manually. It's a bit extra work, but it doesn't require additional config. This way in the page markdown we can still refer to the assets in the same way as png/jpg/gif, etc.
image
image
image

It's still just a workaround. I wish VuePress had an config where we can select what files webpack should copy.

@chryw My solution here is generic: to "select what files webpack should copy", just change .test(/\.pdf$/) to any path regex.

@chryw My solution here is generic: to "select what files webpack should copy", just change .test(/\.pdf$/) to any path regex.

Works perfectly for my needs. Thanks for this. Hopefully they can integrate into the core module.

@utensil I'm trying your solution but I ran into some issues. I'm not really adding more image formats, but I need to include files for download.

If I add a: 'href' to transformAssetUrls, the assets will be copied when I serve the site with docs:dev. However, building the site with docs:build will throw errors. It looks like all the normal links are broken because of this new rule. Am I missing something?

image

Error: Failed to compile with errors.
    at /Users/cherwan/Documents/repos/D3Studio-Playbook/node_modules/@vuepress/core/lib/node/build/index.js:180:16
    at finalCallback (/Users/cherwan/Documents/repos/D3Studio-Playbook/node_modules/webpack/lib/MultiCompiler.js:254:12)
    at /Users/cherwan/Documents/repos/D3Studio-Playbook/node_modules/webpack/lib/MultiCompiler.js:277:6
    at done (/Users/cherwan/Documents/repos/D3Studio-Playbook/node_modules/neo-async/async.js:2931:13)
    at runCompilers (/Users/cherwan/Documents/repos/D3Studio-Playbook/node_modules/webpack/lib/MultiCompiler.js:181:48)
    at /Users/cherwan/Documents/repos/D3Studio-Playbook/node_modules/webpack/lib/MultiCompiler.js:188:7
    at /Users/cherwan/Documents/repos/D3Studio-Playbook/node_modules/webpack/lib/MultiCompiler.js:270:7
    at finalCallback (/Users/cherwan/Documents/repos/D3Studio-Playbook/node_modules/webpack/lib/Compiler.js:257:39)
    at /Users/cherwan/Documents/repos/D3Studio-Playbook/node_modules/webpack/lib/Compiler.js:273:13
    at AsyncSeriesHook.eval [as callAsync] (eval at create (/Users/cherwan/Documents/repos/D3Studio-Playbook/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:31:1)
    at AsyncSeriesHook.lazyCompileHook (/Users/cherwan/Documents/repos/D3Studio-Playbook/node_modules/tapable/lib/Hook.js:154:20)
    at onCompiled (/Users/cherwan/Documents/repos/D3Studio-Playbook/node_modules/webpack/lib/Compiler.js:271:21)
    at /Users/cherwan/Documents/repos/D3Studio-Playbook/node_modules/webpack/lib/Compiler.js:681:15
    at AsyncSeriesHook.eval [as callAsync] (eval at create (/Users/cherwan/Documents/repos/D3Studio-Playbook/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:4:1)
    at AsyncSeriesHook.lazyCompileHook (/Users/cherwan/Documents/repos/D3Studio-Playbook/node_modules/tapable/lib/Hook.js:154:20)
    at /Users/cherwan/Documents/repos/D3Studio-Playbook/node_modules/webpack/lib/Compiler.js:678:31
error Command failed with exit code 1.

Thanks!

Answering my own question again :-)

So I followed @utensil and @alexbainbridge 's idea (thank you! 馃憤) and just had to add esModule: false so that our usual images and links still work. Not sure if this is also a problem for other folks so just sharing our code here:

chainWebpack: config => {
    /** Webpack rule to handle some non-image assets that we'll use */
    config.module
      .rule('files')
      .test(/\.(pdf|zip|ait|log|txt)$/)
      .use('file-loader')
      .loader('file-loader')
      .options({
        name: `[path][name].[ext]`,
        limit: 10000,
        esModule: false,
      });
    /** Explicitly setting esModule:false
     * to avoid this issue https://github.com/vuejs/vue-loader/issues/1612
     */
    config.module
      .rule('images')
      .use('url-loader')
      .options({
        limit: 10000,
        esModule: false,
      });
  }
Was this page helpful?
0 / 5 - 0 ratings

Related issues

kid1412621 picture kid1412621  路  3Comments

AleksejDix picture AleksejDix  路  3Comments

ynnelson picture ynnelson  路  3Comments

alinnert picture alinnert  路  3Comments

herrbischoff picture herrbischoff  路  3Comments