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

Support Relative Path #448

Closed
huchenme opened this issue Feb 13, 2018 · 38 comments
Closed

Support Relative Path #448

huchenme opened this issue Feb 13, 2018 · 38 comments
Labels
closed: wontfix A fix will bring significant overhead, or is out of scope (for feature requests) feature This is not a bug or issue with Docusausus, per se. It is a feature request for the future.

Comments

@huchenme
Copy link

Docusaurus expect baseUrl to be absolute path, to use relative path, I have tried to put baseUrl='' and it does not work for docs link and generated build.

It will be nice that Docusaurus support relative mode as well

@JoelMarcey JoelMarcey added feature This is not a bug or issue with Docusausus, per se. It is a feature request for the future. status: needs more information There is not enough information to take action on the issue. labels Feb 27, 2018
@JoelMarcey
Copy link
Contributor

@huchenme Hi. What error do you get when you use baseUrl = ''? Do you get the same thing if you use baseUrl='/'?

@huchenme
Copy link
Author

huchenme commented Feb 27, 2018

@JoelMarcey
After running npm start in develop mode, docs folder is not working, visiting http://localhost:3000/docs/abc.html will result in http://localhost:3000/docs/abc.html

After running build command, css path and docs path not working as well

@JoelMarcey
Copy link
Contributor

@huchenme Hi. Do you have a repo I can look at to see your siteConfig.js? Thanks!

@huchenme
Copy link
Author

huchenme commented Feb 28, 2018

Hi @JoelMarcey , I have just created this repo https://github.com/huchenme/docusaurus-demo

It is generated from docusaurus-init and changed the baseUrl to "", you could cd into website and try

yarn start

and click Docs header, you should able to see the error.

and then try run docusaurus build and open generated index.html, click the Docs header again, the css is not rendered correctly.

If you guys are busy, I can work on it and send a PR, is that ok with you?

@jacarma
Copy link

jacarma commented Apr 16, 2018

I think this is the same feature request: "Make the built site work without a web server"
Acceptance criteria:
yarn build
open file://{PATH}/website/build/{projectName}/index.html in a browser

Expected behaviour: You can navigate through pages and docs and links work

@stoffeastrom
Copy link

It would be really nice if this was supported. I just save my build artifacts on circle ci but the site will not work since it doesn't handle relative baseUrl e.g ./

Problems seem to be that in the generated html files css and images are referenced as

./css/main.css
./img/some-image.png

when it should have been

../css/main.css
../img/some-image.png

since they are relative to their html file.

Using the ./css/main.css will be relative to web server root

@kevinbarabash
Copy link

kevinbarabash commented Jul 29, 2018

The problem I ran into was I want to deploy to docs to both khan.github.io/KaTeX (for production) as well as katex.netlify.com (for testing). We can probably use an environment variable to handle these different base URLs, but it would be nice if we didn't have to.

@lwasylow
Copy link

lwasylow commented Aug 6, 2018

Would be great feature as its quite painful to review build on local machine

@JoelMarcey
Copy link
Contributor

@endiliey - you haven't done anything around this for the next version of Docusaurus, right? I know we had #864 for static asset.

If not, could we employ something similar to what was done in KaTeX/KaTeX#1525, but within the core instead of siteConfig?

@JoelMarcey JoelMarcey added bug An error in the Docusaurus core causing instability or issues with its execution and removed status: needs more information There is not enough information to take action on the issue. labels Aug 6, 2018
@olafurpg
Copy link
Contributor

olafurpg commented Sep 3, 2018

This would be a nice feature addition. It would enable users to download an offline zip of the website, open index.html and everything works without a server. Another use-case is that it becomes possible to serve the same generated site from different base URLs.

For example, I'm using docusaurus for documenting Scala projects https://olafurpg.github.io/sbt-docusaurus/ I also release the documentation as a zip file to Maven Central (similar to npm) and it's possible to browse those docs and download offline archives via https://www.javadoc.io/. Currently, the css/js/html artifact links return 404s when browsing sbt-docusaurus docs on https://static.javadoc.io/com.geirsson/sbt-docusaurus-docs_2.12/0.1.1/sbt-docusaurus/docs/installation.html I could work around this problem by generating the site with baseUrl com.geirsson/sbt-docusaurus-docs_2.12/0.1.1/sbt-docusaurus/ but then the site would not work anywhere else.

@olafurpg
Copy link
Contributor

olafurpg commented Sep 8, 2018

A workaround for this issue is to post-process the anchor links in the html files generated by yarn run build. I wrote a simple transformation in Scala using Jsoup that does a few things (actual code and test suite)

  • convert /absolute/path/page.html links to ../relative/page.html links
  • process <a href, <img src and <link href (I'm probably missing some other cases, but this was enough on my small sample)
  • prefix //example.com with https: to prevent such links from resolving as file://example.com when browsing plain html files without a server
  • append /index.html to directory links

None of these transformations are Docusaurus-specific, they can be applied to any static site. I would not be surprised if there already exists a JavaScript library that can do this (more robustly than me 😅 ). The benefit of relative links is that

@noraj noraj mentioned this issue Nov 1, 2018
1 task
@tibdex
Copy link

tibdex commented Dec 7, 2018

Relative paths make deployments really simpler. It would be great to support them in a future release.

In the meantime, here's how you can transform absolute links to relative ones in a postbuild script:

// utils.js
const path = require('path');

const fs = require('fs-extra');
const recursiveReaddir = require('recursive-readdir');

const baseUrlPattern = '/_baseUrlPattern_/';
const baseUrlRegExp = new RegExp(baseUrlPattern, 'g');

const buildDirectory = path.join(__dirname, 'build');

const relativify = (content, filePath) =>
  content.replace(baseUrlRegExp, () => {
    const result = `${path.relative(`${path.dirname(filePath)}`, '')
      // Normalize Windows path separators to Unix ones
      .replace(/\\/g, '/')}/`;
    return result === '/' ? '' : result;
  });

const websiteTextualFileExtensions = ['.css', '.js', '.html', '.xml'];

const isNotWebsiteTextualFile = (filePath, stats) =>
  !(stats.isDirectory() || websiteFileTextualExtensions.includes(path.extname(filePath))));

const postProcess = async () => {
  const filePaths = await recursiveReaddir(buildDirectory, [isNotWebsiteTextualFile]);
  await Promise.all(
    filePaths.map(async filePath => {
      const content = await fs.readFile(filePath);
      const relativePath = path.relative(buildDirectory, filePath);
      await fs.writeFile(filePath, relativify(String(content), relativePath));
    })
  );
};

module.exports = {
  baseUrlPattern,
  postProcess,
};
// siteConfig.js
const {baseUrlPattern} = require('./utils');

const isBuilding = process.env.npm_lifecycle_script
  && process.env.npm_lifecycle_script === 'docusaurus-build'; 

const siteConfig = {
  // Keep `/` in watch mode.
  baseUrl: isBuilding ? baseUrlPattern : '/',
  // ...
};

module.exports = siteConfig;
// postprocess.js
'use strict';

require('loud-rejection/register');

const {postProcess} = require('./utils');

postProcess();
// package.json
{
  "devDependencies": {
    "docusaurus": "1.6.2"
  },
  "scripts": {
    "build": "docusaurus-build",
    "postbuild": "node postprocess"
  }
}

@amimas
Copy link

amimas commented Feb 11, 2019

Any update available on this item? This would allow me to have a review site deployed very easily. I can deploy the site in a different path other than what's mentioned in baseUrl but all the generated links are set to absolute path.

@amimas
Copy link

amimas commented Feb 11, 2019

@JoelMarcey @yangshun - Would you be able to provide some feedback? If I can I'd love to look into implementing this and submit a PR for it.

@yangshun
Copy link
Contributor

@amimas Sure, go ahead 😄

@amimas
Copy link

amimas commented Feb 12, 2019

Any guidance available? I'm new to this and not really sure where to begin.

@endiliey endiliey removed the bug An error in the Docusaurus core causing instability or issues with its execution label Mar 28, 2019
@endiliey
Copy link
Contributor

I think at this point our architecture relies a lot on baseUrl and supporting this will be quite a huge refactor. I personally feel the effort is better spent elsewhere

Sent with GitHawk

@endiliey endiliey added the closed: wontfix A fix will bring significant overhead, or is out of scope (for feature requests) label Jul 18, 2019
@jacarma
Copy link

jacarma commented Apr 16, 2020

I agree with you @endiliey, I wanted to provide an easy way to check the requirement is complete, it's not that I use it with file://

We generate the documentation site as an artifact on the CI and it stores and serves it for us. The builds have auto-generated ids so we don't know the final url in advance.
It's a nice feature for us to be able to check the docs in past versions and it would be great to publish them too for our users to check what's supported on each version.
We can do that by knowing the final url in advance and changing the baseurl as part of the build, but we can't make the built site to work both in the CI and the public site.

Of course you know where to put the effort, thanks a lot for the great work :D

@olafurpg
Copy link
Contributor

To echo @jacarma 's comment, our primary use-case is also to host Docusaurus sites at URLs we don't know in advance. For example, here is a 3rdparty service that is hosting our Docusaurus documentation for every published version of a library we maintain https://www.javadoc.io/doc/org.scalameta/munit-docs_2.12/0.4.3/index.html

@ghost
Copy link

ghost commented Apr 16, 2020

@endiliey That is your view based on 12 years old article and a couple of false information.

@tiptronic
Copy link

@endiliey Sorry - the whole security in a browser is about running a browser safely on a local machine AND on the web. This is how browsers worked since they were invented.
And since Flash is dead, there's no risk at all to run under the file:// protocol... that's why browser-security is there.
For the link, I agree with @atilkan

@JoelMarcey
Copy link
Contributor

JoelMarcey commented Apr 17, 2020

All - I find it surreal that I was looking at this closed issue less than 24 hours ago and all of a sudden it started gaining traction with comments again.

That said, I just want you to be aware, in case you didn't know, that @endiliey passed away earlier this year after a long battle with cancer. https://docusaurus.io/blog/2020/01/07/tribute-to-endi

He really gave maximum effort to this project, and I want him to be remembered for that.

@tiptronic
Copy link

@JoelMarcey That's really, really sad to read... :(

@ghost
Copy link

ghost commented Apr 17, 2020

RIP.

@jacarma
Copy link

jacarma commented Apr 23, 2020

My most sincere condolences

@roguexz
Copy link

roguexz commented Jun 15, 2021

My condolences to Endi's family and friends.

Given that this is still a very valuable feature, do the new maintainers have any plans for it?

@roguexz
Copy link

roguexz commented Jun 15, 2021

@tibdex - Your solution is quite elegant and works for the most part of it. However the webpack script in runtime~main goes for a toss. Any ideas?

@ohkimur
Copy link
Contributor

ohkimur commented Aug 30, 2021

I improved @tibdex approach by resolving all nested paths in a single postprocess script. Also, this approach is more generic, so it captures the majority of cases (tested in production 😎).

@roguexz I think this approach should also work fine with Webpack too, but I didn't manage to test it yet. ✌️

// postprocess.js

'use strict';

const fs = require('fs-extra');
const path = require('path');
const recursiveReaddir = require('recursive-readdir');

const buildDirectory = path.join(__dirname, 'build');
const absoluteUrlRegExp = /(href|src)="(?!http[s]|ftp?:\/\/)([^"|#]+)"/g;

const isDirectory = dirPath => path.extname(dirPath) === '';

const convertAbsolutePathsToRelative = (content, filePath) =>
  content.replace(absoluteUrlRegExp, (_absoluteUrl, $1, $2) => {
    const currentDirPath = path.dirname(filePath);
    const relativeDirPath = currentDirPath === '.' ? '.' : path.relative(currentDirPath, '');

    let relativePath = path.join(relativeDirPath, $2);
    if (isDirectory(relativePath)) {
      relativePath = path.join(relativePath, 'index.html');
    }

    return `${$1}="${relativePath}"`;
  });

const websiteTextualFileExtensions = ['.css', '.js', '.html', '.xml'];
const isNotWebsiteTextualFile = (filePath, stats) =>
  !(stats.isDirectory() || websiteTextualFileExtensions.includes(path.extname(filePath)));

const postProcess = async () => {
  const filePaths = await recursiveReaddir(buildDirectory, [isNotWebsiteTextualFile]);
  await Promise.all(
    filePaths.map(async filePath => {
      const content = await fs.readFile(filePath);
      const relativePath = path.relative(buildDirectory, filePath);
      await fs.writeFile(filePath, convertAbsolutePathsToRelative(String(content), relativePath));
    })
  );
};

postProcess();
// package.json
{
  "scripts": {
    "build": "docusaurus build",
    "postbuild": "node postprocess"
  },
  "devDependencies": {
    "@docusaurus/core": "^2.0.0-beta.5"
  }
}

@slorber
Copy link
Collaborator

slorber commented Aug 31, 2021

Everyone, this is a quite old issue that was first opened for Docusaurus v1.

For deploying Docusaurus v2 site to multiple environments with different baseUrls, please use baseUrl: process.env.BASE_URL and provide the appropriate baseUrl as an explicit environment variable.

For deploying a Docusaurus v2 site without a server, using the file:// protocol, let's track this here: #3825

@pavelloz
Copy link

pavelloz commented Nov 1, 2021

Since we are slowly approaching the holy grail of handling the assets without hardcoding URLs in some envs... which is terrible for maintenance, I will add 2 cents.

It would be great to have possibility of setting baseUrl (the part that is used in javascript) during runtime just like webpack does it.
It helps a lot people that use CDNs (ie. website is https://example.com and stores assets on CF @ sha.cloudfront.net)

Its possible that it would require splitting it into two variables (one for site url, one for assets url), but from my experience with static site generators, cdns, documentations, it is a great feature that makes docs developers life easier.

@larissa-n
Copy link

larissa-n commented Jan 5, 2022

@ohkimur: Thanks for the plugin! Script references stilll need adjusted, those may require ./ vs. / for relative paths (script references remain absolute with the plugin as it is; likely the same issue @roguexz ran into).

@slorber: Where would you enter process.env.BASE_URL? If you tried in docusaurus.config.js, build fails with Error: "baseUrl" is required.

@slorber
Copy link
Collaborator

slorber commented Jan 5, 2022

You have to set it as an env variable outside of docusaurus, in your CI/CD config, in your bashrc or when running CLI commands like BASE_URL=xyz yarn start

@larissa-n
Copy link

Thank you, that makes sense. So this approach would not fill in the final filesystem location once the build is deployed, but it can be used if the final destination is known in advance.

When a build needs to be deployed locally, I could see the compiled files reference a location variable like window.location (or, in the case of electron, a process variable) that's unique to each machine and fill in baseUrl that way. But those won't be defined during the compilation step, so they would somewhat have to be added (and tested) separately.

@ohkimur
Copy link
Contributor

ohkimur commented Jan 6, 2022

@larissa-n @slorber I know about this issue. Isn't quite clear for me at the moment how to replace the paths in scrips in an elegant way, that's why I didn't fix this problem yet. If you have any suggestions I am open.

@anthonyborell
Copy link

@ohkimur Thank you for posting your example code, helped me out greatly. Real shame docusaurus isn't focused on issues like this one. Seems to be a really common feature people are after.

@ColinLondon
Copy link

I improved @tibdex approach by resolving all nested paths in a single postprocess script. Also, this approach is more generic, so it captures the majority of cases (tested in production 😎).

@roguexz I think this approach should also work fine with Webpack too, but I didn't manage to test it yet. ✌️

// postprocess.js

'use strict';

const fs = require('fs-extra');
const path = require('path');
const recursiveReaddir = require('recursive-readdir');

const buildDirectory = path.join(__dirname, 'build');
const absoluteUrlRegExp = /(href|src)="(?!http[s]|ftp?:\/\/)([^"|#]+)"/g;

const isDirectory = dirPath => path.extname(dirPath) === '';

const convertAbsolutePathsToRelative = (content, filePath) =>
  content.replace(absoluteUrlRegExp, (_absoluteUrl, $1, $2) => {
    const currentDirPath = path.dirname(filePath);
    const relativeDirPath = currentDirPath === '.' ? '.' : path.relative(currentDirPath, '');

    let relativePath = path.join(relativeDirPath, $2);
    if (isDirectory(relativePath)) {
      relativePath = path.join(relativePath, 'index.html');
    }

    return `${$1}="${relativePath}"`;
  });

const websiteTextualFileExtensions = ['.css', '.js', '.html', '.xml'];
const isNotWebsiteTextualFile = (filePath, stats) =>
  !(stats.isDirectory() || websiteTextualFileExtensions.includes(path.extname(filePath)));

const postProcess = async () => {
  const filePaths = await recursiveReaddir(buildDirectory, [isNotWebsiteTextualFile]);
  await Promise.all(
    filePaths.map(async filePath => {
      const content = await fs.readFile(filePath);
      const relativePath = path.relative(buildDirectory, filePath);
      await fs.writeFile(filePath, convertAbsolutePathsToRelative(String(content), relativePath));
    })
  );
};

postProcess();
// package.json
{
  "scripts": {
    "build": "docusaurus build",
    "postbuild": "node postprocess"
  },
  "devDependencies": {
    "@docusaurus/core": "^2.0.0-beta.5"
  }
}

This works superbly, but for one thing. It doesn't support mode switching (I get the disabled icon). But if I copy the build to a test server, mode switching works.

Cheers.

@slorber
Copy link
Collaborator

slorber commented Feb 19, 2024

Please note this issue was initilly opened for Docusaurus v1 in 2018. Since then, Docusaurus v2 has been released. It's a full rewrite and has nothing to do with the v1 codebase.

Mixing comments for Docusauru v1 and Docusaurus v2 here is confusing so I'm going to lock this issue.

There are other Docusaurus v2+ issues to comment on now, like this one: #3825

If being able to browser a Docusaurus v2 site offline with the file:// protocol is not related to your use case, please open a brand new issue explaining your use case.


This works superbly, but for one thing. It doesn't support mode switching (I get the disabled icon). But if I copy the build to a test server, mode switching works.

@ColinLondon this probably doesn't work as well as you think.

If the theme switch is disabled it likely means React couldn't hydrate on your page, and thus all interactive elements will not work.

These things are all likely to be broken:

  • Mobile drawer button
  • Category collapsible button
  • Search
  • Theme switch
  • Tabs
  • All the interactive React components you embed in your MDX docs

So... no this is not a good solution, unless you are ok with the tradeoffs of having all these elements not working...

@facebook facebook locked and limited conversation to collaborators Feb 19, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
closed: wontfix A fix will bring significant overhead, or is out of scope (for feature requests) feature This is not a bug or issue with Docusausus, per se. It is a feature request for the future.
Projects
None yet
Development

No branches or pull requests