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

Build with Relative URLs #796

Open
ghost opened this issue Sep 4, 2018 · 47 comments
Open

Build with Relative URLs #796

ghost opened this issue Sep 4, 2018 · 47 comments
Labels
has workaround Has a workaround type: enhancement Request to enhance an existing feature

Comments

@ghost
Copy link

ghost commented Sep 4, 2018

Feature request

If there was a feature to build with relative urls, we could run the files without opening a server. Might be something like:
vuepress build --relative

And urls would be like:
assets/js/5.3ca37a5b.js
instead of:
/assets/js/5.3ca37a5b.js

What problem does this feature solve?

Run static files without a server.

Are you willing to work on this yourself?**

Sure.

@ulivz
Copy link
Member

ulivz commented Sep 5, 2018

Change you base to ""

@ulivz ulivz closed this as completed Sep 5, 2018
@ghost
Copy link
Author

ghost commented Sep 5, 2018

@ulivz
I've already tried couple of base configs. And i tried again like yours. It doesn't work.
Paths are still start with /.
Can you open the issue again?
screen shot 2018-09-05 at 16 07 32

@petzerhub
Copy link

@atilkan
Probably related to #387 (see #387 (comment)), also #575 and #667
As i understand vuepress just cannot be used without a static server (see #667 (comment)).

@ghost
Copy link
Author

ghost commented Sep 5, 2018

@petzerhub
I changed paths manually and some of it worked.

@ulivz
Copy link
Member

ulivz commented Sep 6, 2018

Since "" is negative, so "" truly doesn't work for now (it will fallback to "/") ...

We need to enhance it.

@ulivz ulivz reopened this Sep 6, 2018
@ulivz ulivz added the type: enhancement Request to enhance an existing feature label Sep 6, 2018
@tiptronic
Copy link

What timeframe do you expect for this enhancement? I am about starting a new project and this is really required. (Manually changing the paths later is simply pita - but I'm sure, you guessed that already ;))

@rebz
Copy link

rebz commented Jan 21, 2019

Any updates on this? Working on a project that would be perfect for VuePress, but need to build out with relative URLs as the deliverable will live on a Windows Filesystem.

@benmccann
Copy link

benmccann commented Feb 1, 2019

It looks to me like this may be supported in html-webpack-plugin 4.0.0 jantimon/html-webpack-plugin#1114

However, vuepress uses a fork 4816bef of that plugin (#1303), so we'd need to update the fork or switch back to html-webpack-plugin

@BernardZhao
Copy link

Any more updates on this?

@shigma
Copy link
Collaborator

shigma commented Mar 13, 2019

@BernardZhao @atilkan

I wrote a plugin which may satisfy your needs.

vuepress serve docs

And vuepress will build with absolute URLs and then serve them.

@shigma shigma added the has workaround Has a workaround label Mar 13, 2019
@Waterstraal
Copy link

@BernardZhao @atilkan

I wrote a plugin which may satisfy your needs.

vuepress serve docs

And vuepress will build with absolute URLs and then serve them.

You would still need a server that serves the files though... OP wants to open the generated files straight from disk without any server. This can only be done when the urls are relative.

@simonbrunel
Copy link

I agree with @Waterstraal, it's not a workaround in many cases, for example when using GitHub pages.

@shigma
Copy link
Collaborator

shigma commented Mar 15, 2019

I agree with @Waterstraal, it's not a workaround in many cases, for example when using GitHub pages.

Since you are using GitHub pages, why do you need a relative URL? Can you provide a use case for me? I really would like to help but I am not so sure I understand your needs.

@simonbrunel
Copy link

@shigma we are deploying our docs in subfolders, per version. For example, v2.8.0 is located at https://www.chartjs.org/docs/2.8.0/, with a latest symbolic link alias (https://www.chartjs.org/docs/latest/). Note that we are currently using GitBook but are considering to switch to VuePress.

@tiptronic
Copy link

Simple use-case: collect your pages on localhost without external ip... or in a subfolder on a shared space

@shigma
Copy link
Collaborator

shigma commented Mar 16, 2019

@shigma we are deploying our docs in subfolders, per version. For example, v2.8.0 is located at https://www.chartjs.org/docs/2.8.0/, with a latest symbolic link alias (https://www.chartjs.org/docs/latest/). Note that we are currently using GitBook but are considering to switch to VuePress.

And setting base to /docs/2.8.0/ doesn't work?

@simonbrunel
Copy link

I'm sure it works setting base (though maybe not with the latest alias), but base can't be hard-coded in the repository since it depends of the current branch / tag (master, 2.7.0, 2.8.0, etc...) and would break testing the docs locally. It can't be set at build time either, because the target sub-path is unknown at that time, the build process being different from the deploy one (and it would also break local builds).

@tiptronic
Copy link

@shigma I don't understand what your problem with relative path is. Hardcoding something to get something else to work is always possible, but I can't imagine VuePress general aim is to hardcode simple things like that.

@alko89
Copy link

alko89 commented Apr 29, 2019

Posting to show interest in this enhancement.

Besides being useful for opening the site without a server it is also required to properly display websites on IPFS.

@lenowng
Copy link

lenowng commented May 22, 2019

Interested in this enhancement as well, emphasizing on generating static files with relative paths for non-server file serving purpose.

Migrating out of gitbook (which is currently hosted in AWS S3) and would minimize the complexity/effort of the migration (e.g. effort on redoing the deployment pipeline)

@TGreifenberg
Copy link

I'm also highly interested in this enhancement.
Are there any concrete plans for its implementation?

@NanChen6
Copy link

Any updates? This is also a strong need for our team because we want to host on our build server.

@bitwisecook
Copy link

My usecase for this is Dash/Zeal/Velocity offline docs. It just renders from file URLs, but has a per-install random string at the start of the URI to separate each docset. It's per install so you can't predict it between systems. Using a base of ./ doesn't work. Using a base of / doesn't work. Serving up the docs doesn't fix the offline portion of the usecase.

I hacked on this for a while, you can certainly get a decent amount of the docs working without JS enabled, but obviously any embedded Vue component won't render in that case.

@mcamiano
Copy link

We ran into the absolute base path as well. In our case, our needs in development can be partially satisfied by injecting the basename of the repo directory via a shell environment variable on the package.json script command line, and reading that via process.env to set the dest and base settings in the .vuepress/config.js module. This assumes that the access path matches the path it is built under, which is just a little nuisance of re-building for each of a few different target locations. (This works for one fixed path per content build, but inhibits moving the static content elsewhere or accessing it through concurrent alternative paths.)

@renepardon
Copy link

Same problem here. Why the heck you need a server to run simple HTML files with a bit of Javascript and Styles? I wrote a documentation for a project which should be shipped with the project and not being hosted somewhere, so the customer must be able to open the documentation without development skills.

@mcamiano
Copy link

mcamiano commented Dec 4, 2019

https://github.com/vuejs/vuepress/blob/master/packages/%40vuepress/markdown/lib/link.js#L20
seems to suggest that the presence or absence of an absolute path (starting with the http protocol), is being used to infer whether or not the link is intended to be an internal (via vue router) or external link.
This may not be the only place this assumption was made, and there may be other slightly tenuous inferences made about the absolute URL pattern - it could be somewhat difficult to allow for a relative URL base unless such inferences are removed. Seems also like that would come with some risk of breaking things elsewhere, but I don't know much about this codebase.

@benmccann
Copy link

I sent yyx990803/html-webpack-plugin#1, which I believe is necessary for fixing this issue

@benmccann
Copy link

I took a look at using Docusaurus instead of Vuepress, but they don't support it either. They provided a much better explanation of why they don't support it though: facebook/docusaurus#448 (comment)

@ghost
Copy link
Author

ghost commented Apr 16, 2020

@benmccann That is a poor view rather than explanation. It is more like opening a pdf from your local machine. There are security holes in web too. Do you stop using it?

@tiptronic
Copy link

@benmccann I agree with @atilkan - that's not an explanation, but (very, very, outdated) paranoia ;)

@0az
Copy link

0az commented Jun 2, 2020

@ulivz Would it be possible to re-fork html-webpack-plugin under the NPM @vuepress and the GH @vuepressjs namespaces?

@thorny-thorny
Copy link

Somewhat a solution vuepress-offlinify

@Poikilos
Copy link

Poikilos commented Dec 3, 2020

@simonbrunel said:

@shigma we are deploying our docs in subfolders, per version. For example, v2.8.0 is located at https://www.chartjs.org/docs/2.8.0/, with a latest symbolic link alias (https://www.chartjs.org/docs/latest/). Note that we are currently using GitBook but are considering to switch to VuePress.

I found this thread because I seem to have that problem, but I suggest changing the title of the issue to include "offline" and/or "no slash at beginning" so people aren't confused between the issue I solve there which is slashes after address (assets "relative" to .com) and "offline" (this issue--wanting to avoid the automatic the initial slash at the beginning of asset paths).

I think there is some confusion on this thread about "offline" (technically relative) and "subdirectory" (relative to .com). If I understand @simonbrunel, you are serving it online so having a "/" at the beginning is fine.

@simonbrunel Please let me know if this solves your issue without a plugin or patch: #1935 (comment)

@Artefact-Team
Copy link

@Poikilos your suggestion don't solve the problem:
What problem does this feature solve?
Run static files without a server.

Plese have some one found a trick to do that?

@thorny-thorny
Copy link

@Poikilos your suggestion don't solve the problem:
What problem does this feature solve?
Run static files without a server.

Plese have some one found a trick to do that?

I've discovered that it's possible to run static vuepress files without a server by overwriting links to scripts, styles and pages inside html, and routing-related js code. I poked around vuepress output and did it, check out my project #796 (comment) It overwrites minified js code and this is bad, there should be more elegant solution by changing source files, but that sounds like much more effort to me.

@Poikilos
Copy link

Poikilos commented Jan 5, 2021

@Poikilos your suggestion don't solve the problem:
What problem does this feature solve?
Run static files without a server.

Plese have some one found a trick to do that?

My instructions allow you to save static html files. I have an article on doing it from a subdirectory and another article for doing it from the root of the domain. I'm not sure what you're asking--what did you think I meant? Don't be confused by the "Fix the nonworking..." issue, that has little to do with this one other than that my fix shows that issue is invalid and you can fix that with proper settings. :edit: You must mean without the leading slash for online use. My problem was that those were wrong even when running on a server and I solved that by not running via yarn/npm, which both change the current working directory and confuse vuepress so it doesn't find .vuepress and instead reverts to defaults including the site root setting. I remember now that I mentioned it because others may find this issue like I did when having that incorrect relative path for static html even though my fix doesn't solve the problem of the leading slash breaking offline use. That's why I said specifically that I had a different issue than the title, that the title of this issue is misleading, and suggested how to change or add to the issue title.

@alko89
Copy link

alko89 commented Jan 24, 2021

Tried with vuepress-next, now it throws an error when trying to build with base: ''

@JanBN
Copy link

JanBN commented May 26, 2021

this all vuepress is just shit. I spent too much time struggling with it (making sidebar correct, changing favicon, etc.) and now it can not run without server.

@soulshined
Copy link

@atilkan although they are rude by most people's standard, banning someone for a 'bad word' when voicing an opinion is a bit extreme; bad words are subjective and they didn't direct it towards any particular individual. But that's my 2 cents.

I think their comments come out of a sensible frustration. For what it's worth, vuepress team, I had the same issue as them, spent a bunch of personal time learning, configuring and exploring to only find out it does not create a usable local file out-of-box. Perhaps 'static site generator' is too loose of a term our industry is adopting? It sort of has multiple implicit meanings now apparently.

I think there are really 3 solutions to this problem

  1. Don't fix it, for whatever reason the vuepress development team finds, but be decisive about it and just announce your decision.
  2. Enhance vuepress to support this
  3. At least update the documentation to predominately display a disclaimer about this so it doesn't get lost in translation.

At minimum, I would encourage the team to at least continue explore this, as there clearly is a need for it. Whether you find it useful, or logical, or not as the core team developing of this, is irrelevant in my opinion - the fact is people want this feature, and if you don't find a reason to support it, consumers will move on to something that does support it. I have already done that and moved on to Hugo, which supports in natively, without plugin intervention, though I truly sincerely wish I didn't have to because I really like vuepress

@qiuyuhang
Copy link

Highly interested in this enhancement, here is why:

  1. I need to archive vuepress build result in jenkins, and I'd like to view it on jenkins. But jenkins already hosts a web server, so index.html is not in web root.
  2. I'd like to ship our vuepress doc to my users.
  3. I'd like a built-in solution.

@seletz
Copy link

seletz commented Nov 25, 2022

Any news on this? It seems multiple people have valid use cases, @simonbrunel explained one of them which is IMHO very reasonable when trying to actually ship versioned docs and make them available to whatever audience one needs, i.e. serving multiple versions of the same documentation and have a symbolic link to the "latest" version.

Sure, we can build the documentation multiple times, every time just changing the base. But that seems very silly, it's 2022 after all ...

I'd be very much interested in an actual explanation as of why relative paths cannot be used and VuePress actively enforces absolute paths in "base".

@Poikilos
Copy link

Poikilos commented Nov 25, 2022

Any news on this? It seems multiple people have valid use cases, @simonbrunel explained one of them which is IMHO very reasonable when trying to actually ship versioned docs and make them available to whatever audience one needs, i.e. serving multiple versions of the same documentation and have a symbolic link to the "latest" version.

Sure, we can build the documentation multiple times, every time just changing the base. But that seems very silly, it's 2022 after all ...

I'd be very much interested in an actual explanation as of why relative paths cannot be used and VuePress actively enforces absolute paths in "base".

Probably, no one wanted to write this boring function for 2hrs :)

I wrote it today. The project can consider it a PR. If you commit this, please use (if making a commit with the git command or another program without a co-author feature, put two completely blank lines then): Co-authored-by: Poikilos <7557867+poikilos@users.noreply.github.com>):

/**
 * Convert a full path to a relative path.
 * @param {string} fromPath - The absolute href of the current directory
 *   or file starting "/". If the leaf (part after last slash) has a "." it is
 *   assumed to be a file unless there is a slash after it (so if the
 *   leaf is a directory but contains a ".", put a slash after it).
 * @param {string} toPath - The absolute href of the destination
 *   file or directory starting with "/".
 */
function getRelativePath(fromPath, toPath) {
  if (!fromPath.startsWith('/')) {
    console.log('Error: The fromPath "' + fromPath + '" given to getRelativePath is relative, preventing changing toPath.')
    return toPath
  }
  if (!toPath.startsWith('/')) {
    console.log('Error: The toPath "' + toPath + '" given to getRelativePath already appears relative, so it will not be changed.')
    return toPath
  }

  var toLeafI = toPath.lastIndexOf('/')
  var toLeaf = ''
  var toDir = toPath
  //if (toLeafI >= 0) {  // always true since required to be absolute
  toLeaf = toPath.substring(toLeafI + 1)
  // ^ +1 to exclude the leading slash
  toDir = toPath.substring(0, toLeafI + 1)
  // ^ include the slash so there is always
  //   a slash (for easier calculation of return)
  //}
  var removeCount = 0
  if (!toLeaf.includes(".")) {
    // It is apparently not a file, so
    // move the segment from the leaf
    // to the dir.
    if (toLeaf.length > 0) {
      toDir += toLeaf + "/"
      toLeaf = ""
      removeCount = 1
      // ^ The original didn't end in slash,
      //   so should be changed back (1
      //   character should be removed)
      //   before returning.
    }
  }

  var fromLeafI = fromPath.lastIndexOf('/')
  var fromLeaf = ''

  if (fromLeafI >= 0) {
    fromLeaf = fromPath.substring(fromLeafI+1)
  }


  var fromDir = fromPath
  if (fromLeaf.includes(".")) {
    // It is apparently a file.
    fromDir = fromPath.substring(0, fromLeafI)
  }
  if (!fromDir.endsWith('/')) {
    // It must be a directory at this point
    // so add the '/' so all directories have
    // / (for easier calculation of return).
    fromDir += '/'
  }

  // console.log('  fromDir='+fromDir)
  // console.log('  fromLeaf='+fromLeaf)
  // console.log('  toDir='+toDir)
  // console.log('  toLeaf='+toLeaf)
  // console.log('  removeCount='+removeCount)
  // Both fromDir and toDir end with '/' at this point.

  if (toDir.startsWith(fromDir)) {
    toPath = toDir.substring(fromDir.length) + toLeaf;
    // The deeper path is now relative.
    // This will also remove the leading slash because
    // fromDir always has a slash by now.
  }
  else if (fromDir.startsWith(toDir)) {
    // It is a shallower path, so repeat .. as necessary.
    var uncommonSide = fromDir.substring(0, fromDir.length-toDir.length)
    var uncommonSlashCount = uncommonSide.split("/").length
    // console.log('  uncommonSide='+uncommonSide)
    // console.log('  uncommonSlashCount='+uncommonSlashCount)
    var trail = "../".repeat(uncommonSlashCount-1)
    // trail.substring(0, trail.length-1)
    toPath = trail + toLeaf
  }
  toPath = toPath.substring(0, toPath.length-removeCount)
  return toPath
}
Tests (all work as expected in jsfiddle)

console.log('Test shallower dir (next 3 should be: ".."):')
console.log(getRelativePath("/services/design/", "/services"))
console.log(getRelativePath("/services/design/index.html", "/services"))
console.log(getRelativePath("/services/design", "/services"))

console.log()
console.log('Test shallower file (next 3 should be: "../index.html"):')
console.log(getRelativePath("/services/design/", "/services/index.html"))
console.log(getRelativePath("/services/design/index.html", "/services/index.html"))
console.log(getRelativePath("/services/design", "/services/index.html"))

console.log()
console.log('Test shallower root (should be "../../"):')
console.log(getRelativePath("/services/design/index.html", "/"))
console.log('Test file in shallower root (should be "../../index.html"):')
console.log(getRelativePath("/services/design/index.html", "/index.html"))
console.log('Test shallower directory (should be "../"):')
console.log(getRelativePath("/services/design/index.html", "/services/"))

console.log('Test deeper directory without slash (next 3 should be "design"):')
console.log(getRelativePath("/services/", "/services/design"))
console.log(getRelativePath("/services/index.php", "/services/design"))
console.log(getRelativePath("/services", "/services/design"))
// ^ expected output is: 'design'

console.log()
console.log('Test to ensure errors happen on incorrect input (next 2 should be "services"):')
// Incorrect input tests:
console.log(getRelativePath("/services/design", "services"))
// ^ should have an error since not absolute
console.log(getRelativePath("services/design", "services"))
// ^ should have an error since not absolute

I don't know all of the places in the code to use the function because I've never looked at the code of vuepress itself, or not enough to recall. Therefore, please take a look at this issue again and maybe you can make the change far more quickly than I can. If you use my function to do so please use the co-author information I supplied.

Caveats:

  • If you have a way of checking whether the resource is a file (as opposed to a directory), do that instead of .includes('.') for both toPath and fromPath. However, that would make the function slightly less versatile. You would either have to say isdirectory or isfile, else error. If neither exists, it wouldn't be known!

@stephane888
Copy link

Highly interested in this enhancement, I'd like to ship our vuepress doc to my users.

@Waterstraal
Copy link

I just tried the vuepress successor vitepress. Sadly, it has this exact same issue.
It's not possible to build with an empty base url.
Setting base in config.ts to '' will prepend paths with /, resulting in this:

  <link rel="preload stylesheet" href="/assets/style.0e94836e.css" as="style">
  <script type="module" src="/assets/app.6a80f313.js"></script>
  <link rel="preload" href="/assets/inter-roman-latin.2ed14f66.woff2" as="font" type="font/woff2" crossorigin="">
  <link rel="modulepreload" href="/assets/chunks/framework.e3082fbd.js">
  <link rel="modulepreload" href="/assets/chunks/theme.ba0b17c6.js">
  <link rel="modulepreload" href="/assets/index.md.d37213a0.lean.js">

@Shuunen
Copy link

Shuunen commented Nov 25, 2023

Jeez 6 years after and still not possible to use relative urls 😅

@eward957
Copy link

eward957 commented Mar 20, 2024

vuepress 1, edit your .vuepress/config.js:

class ReplaceHistoryToHashWebpackPlugin {
  apply(compiler) {
    compiler.hooks.emit.tap("ReplaceHistoryToHash", (compilation) => {
      Object.keys(compilation.assets)
        .filter((c) => c.endsWith(".js"))
        .forEach((key) => {
          if (compilation.assets[key] && compilation.assets[key]._value) {
            const start =
              compilation.assets[key]._value.indexOf('mode:"history"');
            if (start > -1) {
              compilation.assets[key]._value =
                compilation.assets[key]._value.slice(0, start + 6) +
                "hash" +
                compilation.assets[key]._value.slice(start + 13);
            }
          }
        });
    });
  }
}

module.exports = {
  base: process.env.NODE_ENV === "production" ? __dirname + "/dist/" : "/",
  configureWebpack: (config, isServer) => {
    config.plugins.push(new ReplaceHistoryToHashWebpackPlugin());
  },
};

#1935

@seletz
Copy link

seletz commented Mar 20, 2024

Well, we have since moved to JetBrains WriterSide.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
has workaround Has a workaround type: enhancement Request to enhance an existing feature
Projects
None yet
Development

No branches or pull requests