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

Option to generate offline static HTML files usable without server #3825

Closed
tomchen opened this issue Nov 26, 2020 · 71 comments · Fixed by #9859
Closed

Option to generate offline static HTML files usable without server #3825

tomchen opened this issue Nov 26, 2020 · 71 comments · Fixed by #9859
Labels
apprentice Issues that are good candidates to be handled by a Docusaurus apprentice / trainee proposal This issue is a proposal, usually non-trivial change
Milestone

Comments

@tomchen
Copy link

tomchen commented Nov 26, 2020

🚀 Feature

docusaurus build will build a local production version that has to be docusaurus serve'd to be usable. Can we add an option to build an offline static HTML files that are usable completely without any server, so user can just open index.html with a browser to read the whole documentation.

It's about calculating relative (instead of absolute) URLs, and appending "index.html" at the end of the URLs. Algolia search will have to be removed, any online cloud assets will have to be put in local folders.

Have you read the Contributing Guidelines on issues?

Yes

Comment, Motivation, Pitch

What about other static site generators and libraries?

Gatsby, React, etc.'s build all do the similar thing, they all need a server.

Gatsby has this feature request for option to build such offline static HTML site: gatsbyjs/gatsby#4610, which is closed without the issue being solved. Users keep asking for the feature and for reopening the issue. According to one comment, in Gatsby v1 it actually can generate such static site, it is in v2 it doesn't work.

React serves general purpose and Gatsby is made for any website. But Docusaurus, is primarily made for documentation, it may need the feature of the offline version generation more than React and Gatsby do.

PDF and ebook formats

There is already a feature request, #969, that asks for option to create an offline version in PDF format. It is obviously brilliant to be able to make PDF and maybe also EPUB, MOBI, AZW. PDF and these ebook formats may have less security concern than HTML. But the downsides are, it may be a little time-consuming to achieve the PDF feature; those interactive navs and TOCs and colorful website design and layout will have to be removed in PDF and other ebook formats. Offline static HTML is easier to make. If PDF feature is in the long-term plan, then Offline static HTML could be in a shorter-term to-do list.

Compressed web file format

The offline static web files usable without server, could be simply compressed as a zip or in other common archive formats. User will need to uncompress the file and click index.html in the root folder to use it.

They can also be compiled in CHM (Microsoft Compiled HTML Help), problem is it is a bit old and it does not have native support in non-Windows OS. It's a little surprising there's no standard or universally accepted file format similar to CHM. Perhaps it's due to security concerns.

@tomchen tomchen added feature This is not a bug or issue with Docusausus, per se. It is a feature request for the future. status: needs triage This issue has not been triaged by maintainers labels Nov 26, 2020
@RDIL
Copy link
Contributor

RDIL commented Jan 6, 2021

You can use electron to freeze it I believe

@tomchen
Copy link
Author

tomchen commented Jan 6, 2021

You can use electron to freeze it I believe

That'd be a super overkill. Even you have just one webpage, Electron will make it 80-100 MB, putting the whole browser rendering and scripting engines in it.

@kinzlp

This comment was marked as duplicate.

1 similar comment
@vrabota

This comment was marked as duplicate.

@slorber
Copy link
Collaborator

slorber commented Aug 31, 2021

@ohkimur mentionned he built a postprocessing step to enable support of local browsing, using the file:// protocol.

#448 (comment)

That doesn't look like a bad idea to build this as a postprocessing step.

A Docusaurus plugin could be built in userland to solve this problem. Plugins have a postBuild lifecycle to use for that.

Note: such plugin should take into account the config.trailingSlash option because output files are not always /path/index.html anymore, and can also be /path.html

@slorber
Copy link
Collaborator

slorber commented Aug 31, 2021

Note: for some Docusaurus features (particularly SEO metas such as social image, i18n hreflang...), URLs in the HTML files MUST be fully qualified absolute URLs (domain + absolute path).

Building a site for local offline usage does not prevent you from setting site URL and baseUrl in the config file, otherwise, the build output would not be suitable for online hosting.

For these reasons, it's very unlikely we'll add support for using "relative baseUrl" in Docusaurus, such as baseUrl: '': it would lead to an output that would only be correct for local usage, it's likely users will deploy sites with broken metadata online without noticing the SEO problems.

@roguexz
Copy link

roguexz commented Sep 1, 2021

Moving my conversation from #448 to this thread

@ohkimur - your suggestion works for the most part of it, but Webpack configurations are still being difficult to resolve

@slorber - my use case isn't for offline usage. I am trying to put together a simplistic developer workflow which involves publishing documentation to GitHub pages. At my workplace, we are using GitHub enterprise.

The use case is as follows,

  • Developer forks a repository and works on it
  • In the PR they are also contributing the generated site
  • Before merging the generated site, I would like to view the site on their fork

Given that baseUrl needs to be defined as a fixed path (e.g., /pages/_GH_ORG_/_GH_REPO_NAME_/), it becomes difficult to view the incoming changes till it has been merged.

I understand that this is not how most people work. This is part of an exercise where I am trying to encourage my team to get into the habit of documenting their software. The pandemic has made things worse because reviewing the UI / UX now requires a meeting instead of being able to just view the documentation against their repositories.

Any ideas that you might have to improve this workflow / process are most welcome.

I'm more of a Java/JVM guy .. which isn't helping and making the hacking process that much more challenging. Any help is greatly appreciated.

@ohkimur
Copy link
Contributor

ohkimur commented Sep 2, 2021

@slorber I created the docusaurus-plugin-relative-paths to solve the issue. I used the same post-processing approach using Docusaurus postBuild lifecycle. 🦖😎

@slorber
Copy link
Collaborator

slorber commented Sep 2, 2021

@roguexz , if you used a modern Jamstack tool like Netlify or Vercel (both much better than GH pages), you'd get a much better experience and all PRs would have a "deploy preview" link that includes the changes from the PR, ensuring they are valid (docusaurus can build and you can check the end result a merge would lead to before doing that merge).

See this Docusaurus PR, the Netlify bot added a link so that the PR can be reviewed more easily: #5462 (comment)

This is very easy to set up.


@ohkimur thanks! hope people will like this solution.

One interesting idea could be to have 2 mods:

  • modify build files
  • keep build unchanged, create a copy of build, modify it and generate a build/site.zip archive that users could download?

@ohkimur
Copy link
Contributor

ohkimur commented Sep 2, 2021

@roguexz , if you used a modern Jamstack tool like Netlify or Vercel (both much better than GH pages), you'd get a much better experience and all PRs would have a "deploy preview" link that includes the changes from the PR, ensuring they are valid (docusaurus can build and you can check the end result a merge would lead to before doing that merge).

See this Docusaurus PR, the Netlify bot added a link so that the PR can be reviewed more easily: #5462 (comment)

This is very easy to set up.

@ohkimur thanks! hope people will like this solution.

One interesting idea could be to have 2 mods:

  • modify build files
  • keep build unchanged, create a copy of build, modify it and generate a build/site.zip archive that users could download?

@slorber I think this is a great idea. If you want, you can open a issue here and I will work on it. 🐱‍👤

@Josh-Cena Josh-Cena added proposal This issue is a proposal, usually non-trivial change and removed feature This is not a bug or issue with Docusausus, per se. It is a feature request for the future. status: needs triage This issue has not been triaged by maintainers labels Oct 30, 2021
@larissa-n
Copy link

Picking up on @RDIL's comment: I added the build output files to an electron app and encountered a few issues. After specifying each of the files in package.json and with docusaurus-plugin-relative-paths (thank you, @ohkimur!), the HTML content is rendered fine with all images, but electron is still looking for scripts in file:///assets/ based on a reference in runtime~main.xxx.js. Any idea how this could be fixed?

@larissa-n
Copy link

A very rough way to fix script references is baseUrl: './'. However, this also messes with routes, so a somewhat more correct approach is to change only o.p= in the compiled runtime~main.xxx.js (not sure if there's a more elegant way, but unless there is, one idea might be to make this part of the docusaurus-plugin-relative-paths postprocess script). There are also references in main.xxx.js that point to an absolute directory as well. Now most scripts load, but they re-render all pages as the 404 page / NotFound component. Of course, getting rid of parts.push('exact: true'); in @docusaurus/core/lib/server/routes.js doesn't exactly fix the problem, since sub-routes won't load. Why does it have to check the route match, is that just for the prefetching? It seems odd that content is switched to NotFound once scripts load, since the static content looks fine and everything is in the right place while scripts fail to load.

Also, not sure if this is documented anywhere but to dev with npm run start, I had to deactivate docusaurus-plugin-relative-paths plugin.

Docusaurus creates quite a few js files to keep track of if you work in an environment that requires you to list every single file. I'm used to react-static, and its builds consist of far fewer files.

@ohkimur
Copy link
Contributor

ohkimur commented Jan 6, 2022

@larissa-n Thank you for your observations. I know about the issue you mentioned, but I didn't fix it since I didn't find an elegant approach to do it. If you already have a potential solution (even though it's messy) I invite you to make a pull request in the plugin's repo. I can extend it later if necessary.

Also, can you describe the problem you had when you tried npm start? Isn't the plugin called only when a build is triggered? If not, then this is a bug and it might be a good idea to fix it.

@sigwinch28
Copy link
Contributor

Note: for some Docusaurus features (particularly SEO metas such as social image, i18n hreflang...), URLs in the HTML files MUST be fully qualified absolute URLs (domain + absolute path).

Why must they be fully qualified, @slorber?

I've just started to use docusaurus and I find the baseUrl rather limiting, because I kind of expected a copy-the-html-files-anywhere exeprience for deployment anywhere, without extra configuration. I don't understand why there's a tight coupling to baseUrl. Your comment hints at why it exists.

Is this necessity documented?

@Josh-Cena
Copy link
Collaborator

@sigwinch28 Yes, see https://docusaurus.io/docs/advanced/routing#routes-become-html-files

@slorber
Copy link
Collaborator

slorber commented Jun 24, 2022

Note: for some Docusaurus features (particularly SEO metas such as social image, i18n hreflang...), URLs in the HTML files MUST be fully qualified absolute URLs (domain + absolute path).

Why must they be fully qualified, @slorber?

I've just started to use docusaurus and I find the baseUrl rather limiting, because I kind of expected a copy-the-html-files-anywhere exeprience for deployment anywhere, without extra configuration. I don't understand why there's a tight coupling to baseUrl. Your comment hints at why it exists.

Is this necessity documented?

It's not just coupling to a /baseUrl/, it is coupling to your domain as well.

There are multiple things in Docusauurs relying on that, in particular SEO metadata like canonical URL

<link data-rh="true" rel="canonical" href="https://docusaurus.io/docs/myDoc">

What Google says: https://developers.google.com/search/docs/advanced/crawling/consolidate-duplicate-urls

CleanShot 2022-06-24 at 15 14 29@2x

Although relative URLs seem supported (maybe only by Google?), it's not recommended.

Similarly, meta hreflang headers for i18n sites:

CleanShot 2022-06-24 at 15 21 18@2x

https://developers.google.com/search/docs/advanced/crawling/localized-versions

CleanShot 2022-06-24 at 15 16 56@2x

(including the transport method means you also can't switch from HTTP to HTTPS without a Docusaurus config change)

Similarly for og:image metadata responsible for providing the social card preview on your site on social network

<meta property="og:image" content="https://docusaurus.io/img/socialcard.png"/>

Using a relative URL can lead to failures to display the card and does not respect the spec: https://ogp.me/#data_types

CleanShot 2022-06-24 at 15 20 04@2x


It's not a Docusaurus-side constraint, it's a constraint that comes from outside.

You really have to build your site for a specific protocol/domain/baseUrl.

Now I understand in some cases you don't care about the features above and prefer to have more "deployment flexibility", but for now we don't support that.

@sigwinch28
Copy link
Contributor

Fantastic answers. Thank you.

@jeacott1
Copy link

@ohkimur it looks like your completely deleted your docusaurus-plugin-relative-paths project?
what happened?

@ohkimur
Copy link
Contributor

ohkimur commented Nov 18, 2022

@jeacott1 Yeah. I did. I want to invest my time into something different.

@justsml
Copy link

justsml commented Nov 19, 2022

@ohkimur I appreciate your OSS work!

Could you please put your docusaurus repos up as 'Archived'? Even temporarily?
Maybe even email me? 😅

(I'm trying to help a former student make sense of some README notes left by a previous dev. It has permalinks to your docusaurus-plugin-relative-paths, and all I see is 404s. 💔And the mystery deepens...)

If you'd rather not deal with it at all, I do understand. I hope your new focus is rewarding.

Best wishes, Dan.

@GarlicHiker
Copy link

+1 for this feature! We would appreciate it a lot!
The lack of this feature support is actually a reason why we turned away from Docusaurus to MkDocs alternative.

@andrigamerita
Copy link

andrigamerita commented Jan 28, 2024

Hello people,
I've been experimenting with Docusaurus for some personal projects in the last few days, since it seemed to me to be overall pretty solid, more than the most famous alternatives, because of how it automatically handles all the content. Unfortunately, the lack of the kind of feature we're discussing here is a bit of an inconvenience to me, I consider it a pretty basic feature for an SSG.

I decided to try my hand at quickly implementing an unofficial proof-of-concept of this thing, and thought I'd share it, could be useful. It's just a post-processing script (derived from the one posted in #448) and some static CSS+JS.

Right now, this solution allows for both a standard collection of server-independent HTML files, and also an unified HTML file that contains all the pages and requires no external dependencies. Navigation is fully working on both desktop and mobile.

I too really hope that this idea gets picked up by Meta and officially integrated in Docusaurus, but, in the meantime, I've found my solution. If there's actual interest in this, I could probably write some documentation, try to add some needed features like content search; maybe also some nices-to-have, like working navigation in mobile view without JavaScript. 🙂️

@ColinLondon
Copy link

Hello people, I've been experimenting with Docusaurus for some personal projects in the last few days, since it seemed to me to be overall pretty solid, more than the most famous alternatives, because of how it automatically handles all the content. Unfortunately, the lack of the kind of feature we're discussing here is a bit of an inconvenience to me, I consider it a pretty basic feature for an SSG.

I decided to try my hand at quickly implementing an unofficial proof-of-concept of this thing, and thought I'd share it, could be useful. It's just a post-processing script (derived from the one posted in #448) and some static CSS+JS.

Right now, this solution allows for both a standard collection of server-independent HTML files, and also an unified HTML file that contains all the pages and requires no external dependencies. Navigation is fully working on both desktop and mobile.

I too really hope that this idea gets picked up by Meta and officially integrated in Docusaurus, but, in the meantime, I've found my solution. If there's actual interest in this, I could probably write some documentation, try to add some needed features like content search; maybe also some nices-to-have, like working navigation in mobile view without JavaScript. 🙂️


Is there a walkthrough on how to do this? I am a tech writer, not a developer. Docusaurus looks like a really good solution on the surface, but I absolutely need it to work offline, and haven't a clue how to do it.

@andrigamerita
Copy link

Is there a walkthrough on how to do this? I am a tech writer, not a developer. Docusaurus looks like a really good solution on the surface, but I absolutely need it to work offline, and haven't a clue how to do it.

Hello @ColinLondon, I don't know if you noticed but the demo site also hosts some documentation. If you have noticed, well, I know it's extremely poor right now, I plan to improve it a bit. I just added a new page that explains things just a little better, I hope it's good enough for a new user like you: https://editocttrialtools-octospacc-7b2d9ca9cd24bce25d929d67488fd8f33dc.gitlab.io/docusaurus-static/docs/docusaurus-static/setup-immediate/index.html.
Let me know if this helps you get started. This explains how to start totally fresh with my Docusaurus-Static, assuming you don't already have a Docusaurus site. I will also finish writing ASAP the page on how to add Docusaurus-Static to an existing normal Docusaurus site, for people who would like that instead.

@ColinLondon

This comment was marked as off-topic.

@ColinLondon

This comment was marked as off-topic.

@slorber
Copy link
Collaborator

slorber commented Feb 16, 2024

@ColinLondon if you want to get support from the author of Docusaurus Static, please go to the project repository discussions directly:
https://gitlab.com/octospacc/editocttrialTools/-/tree/main/docusaurus-static

This issue is about supporting this feature in core directly.
It is not the place to ask for personal support for a tool we do not maintain.

Please keep in mind many people receive notifications whenever you ask a question here.

@slorber
Copy link
Collaborator

slorber commented Feb 16, 2024

I'm not sure how Docusaurus offline support should work

So I'd like to ask the community for help.


SSG or not?

Is it really important to emit one static file per page?

Or is it fine if we emit just one index.html and render content with React locally?

Do you expect users to navigate subfolders and click on a file such as ./local_site/docs/category/myDoc/index.html ?

Do you expect users to always start from ./local_site/index.html ?

Isn't it confusing if the root folder contains thousands of subfolders and html files, that it is even hard to locate the index.html (homepage) of the site?


Routing

How do you expect routing to work?

Do you expect to be able to bookmark a page or something?

What is the URL of the file you click on?
file:///.../local_site/index.html ?

What is the URL after you click on a link to another page?

  • file:///.../local_site/docs/myDoc/index.html ?
  • file:///.../local_site/index.html#!/docs/myDoc/ ?
  • something else?
  • do you even care?

Any remark on how routing should work?


Other systems supporting offline deployments

It would greatly help if you could show me actual static site deployments that can work offline without a server.

Please provide a zip file with such a static deployment, so that others can download it and try it locally.

The more we see examples of things that work offline, the more we can understand what should be implemented.

I'll start with Material for MkDocs,:

Config:

site_name: MkLorum
site_url: https://example.com/
nav:
  - Home: index.md
  - About: about.md

theme:
  name: material

plugins:
  - offline

Unlike Docusaurus, it is not a single page application hydrating a front-end framework, and links are navigated through the regular navigation (not history.pushState()):

  • file:///.../local_site/index.html
  • file:///.../local_site/about.html

I'm interested to see other similar examples.

With regular HTML navigations, we can probably find a few ones, notably the Javadoc:
https://docs.oracle.com/javase/8/docs/api/

But is there any SPA framework that supports such an offline mode, and using history.pushState() based soft navigations, without fully reloading the HTML page when navigating?

I could not find any SPA / client-side navigation example, so maybe we are the first to attempt this and are in uncharted territory.

As far as I know, none of those frameworks support it (or it's not documented): Docusaurus, VitePress, VuePress, Nextra, Astro/Starlight, Gatsby, Dokz, Docsify, Rspress, Fumadocs, Vocs...

If you know any client-side frontend framework supporting an offline mode, I'm super interested to hear about it and get a .zip file with such a deployment so that I can study it.


We need your help

I know many of you want this issue solved, and we'll give it a try.

But so far the discussions have remained quite abstract: we still don't really know what it means for Docusaurus to support such offline mode.

As you can see, this feature you all take for granted isn't so commonly supported 😅 .

Now it's your time to help us.

Please help us figure out how this should work:

  • provide concrete examples of other frameworks to take inspiration from (in particular based on SPA/React/Vue/Svelte...)
  • specify the precise behavior you think Docusaurus should adopt

@ilg-ul

This comment was marked as off-topic.

@ColinLondon

This comment was marked as off-topic.

@ilg-ul

This comment was marked as off-topic.

@ColinLondon

This comment was marked as off-topic.

@ilg-ul

This comment was marked as off-topic.

@slorber
Copy link
Collaborator

slorber commented Feb 16, 2024

Hey, I'm sorry but all these discussions are off-topic and I'm hiding them. This is not the place to ask about what Docusaurus is.

I'm still going to answer briefly.


Docusaurus is a React-based static site generator. It generates static HTML pages using React, and then hydrates React client-side. When navigating, we don't navigate to another HTML document, but we render the next page with client-side JavaScript using soft navigations and the history.pushState() API to update the URL.

This kind of navigation is what permits Docusaurus to feel fast when clicking on a link, and also preserves the state of UI elements on the current page (for example the collapsible state of sidebar categories).

This is a very different model from Jekyll, Hugo, Eleventy, MkDocs, Sphynx, and many other SSG tools that do not use client-side navigation and use a more traditional/old-school approach, but are usually less "interactive". Docusaurus v1 also worked that way, using React only during the build process and not loading React on the client side.

If you open your Chrome DevTools network tab on v1.docusaurus.io VS docusaurus.io, you will notice a big difference when navigating. v1 will request a new HTML page, while now v2+ will request JS to render locally the new page.


If you don't understand what Docusaurus, React, hydration, SPA, history API, and all these things are, then it is unlikely that you will be able to help us solve this issue.

@slorber
Copy link
Collaborator

slorber commented Feb 17, 2024

Investigations

I've investigated 2 approaches so far:

I have also investigated using external tooling such as wget to crawl the site and download it for offline usage:

mkdir wget-test
cd wget-test
cp -R ../projects/docusaurus/website/build/ .
wget -mpEknH http://localhost:3000/

This kind of works, but it is somehow the same solution as the first one (SSG) where each page has a dedicated static html file.


SSG

#9857

To me, the SSG approach is quite challenging. Notably, I'm not even sure dependencies such as React-Router can do routing using the file:// protocol. That remains to be investigated.

However, it could work decently if you are ok with opting out of the SPA mode of Docusaurus and are ok with not hydrating React on the client. This means that things we implement with interactive React code will not work (tabs, theme switch, category collapse button, mobile drawer...). We try to make things work without any JS (#3030) but there are still a few things that require JS and/or React. This also makes it impossible for you to include React interactive inside docs (through MDX) however non-interactive React elements (such as admonitions) are perfectly fine.

If you want to give this mode a try, I'd suggest to run this command on your computer. This is kind-of the equivalent of the HTML post-processing scripts that people shared earlier, the links and assets will use relative paths.

wget -mpEk https://tutorial.docusaurus.io/

(there are JS loading console errors, but that's kind of on purpose: if JS succeeds in loading, then you'll get a 404 page being rendered after React hydration because React-Router does not know what to render for file://. However this mode might be a decent fallback if you want a good-enough/almost working experience)


Hash Router

#9859

The Hash Router solution looks easier to implement, and I'm almost able to make it work on our website, apart from a few linking edge cases to investigate.

However, I'm not sure if it's the solution the community is looking for considering there would be a single HTML file emitted, and that file would initially be empty.

Here's the deploy preview online demo of the Hash Router based app:
https://deploy-preview-9859--docusaurus-2.netlify.app/#/

The local app using file:// would behave the same, and you'll always open it through the index.html entry point. Even though there's a single entry point file, you can still have deep linking and bookmark URLs.

You will notice that we have a "loading..." screen before the content appears. This is because the initial html file is empty and all the app is rendered with JS.

@lebalz
Copy link
Contributor

lebalz commented Feb 18, 2024

+1 for the Hash Router.

We use Docusaurus for interactive teaching-websites in a highschool and we'd like to give our students the ability to get a snapshot of the website when they completed their grade and leave the school.

Important points for our usecase:

  • an easy way to start - a single index.html file inside the .zip-folder would just be perfect
  • react on the client-side - support for all interactive parts and common state management libraries
  • optional: local search
  • optional: bookmarks

Thanks a lot - this really would be a huge thing for our school-department :)

@jeacott1
Copy link

@slorber hashrouter sounds like an excellent solution to me. Definitely preferable to SSG imo, and leaves more features available over the long term.

@slorber
Copy link
Collaborator

slorber commented Feb 19, 2024

Thanks for your feedback.

I'll focus on implementing proper support for the Hash Router then.

It doesn't mean that we won't eventually support other "modes" later, but at least this one is a good starting point.


Other alternatives to be considered:

  • Wrapping the static deployment inside an Electron/Tauri WebView
  • Package the web server as an executable (see vercel/pkg)

Of course, I'm not a fan of those approaches (using a bazooka to kill a fly), but afaik you could implement them in userland today if you really need to solve this problem right now and be able to package/distribute your docs for offline usage.

@ilg-ul
Copy link
Contributor

ilg-ul commented Feb 19, 2024

I'll focus on implementing proper support for the Hash Router then.

Could you confirm that plain static html files for each page will continue to be supported for the foreseeable future?

@slorber
Copy link
Collaborator

slorber commented Feb 19, 2024

I'll focus on implementing proper support for the Hash Router then.

Could you confirm that plain static html files for each page will continue to be supported for the foreseeable future?

This would be a new build mode you enable through a CLI option.

So yes everything else will remain retrocompatible and Docusaurus will remain a static site generator

@tonyeggers
Copy link

tonyeggers commented Mar 27, 2024

Thanks for your feedback.

I'll focus on implementing proper support for the Hash Router then.

It doesn't mean that we won't eventually support other "modes" later, but at least this one is a good starting point.

Other alternatives to be considered:

  • Wrapping the static deployment inside an Electron/Tauri WebView
  • Package the web server as an executable (see vercel/pkg)

Of course, I'm not a fan of those approaches (using a bazooka to kill a fly), but afaik you could implement them in userland today if you really need to solve this problem right now and be able to package/distribute your docs for offline usage.

@slorber ... thank you for working on this. Just to confirm another use case, I'm hosting documentation in this fashion within an ERP platform (which I won't mention) due to abysmal support for doing anything remotely useful or flexible for this purpose. It's basically a static resource defined within the ERP environment, which gives me authentication by default for users already authenticated into the ERP. So now I can have a flexible git-controlled documentation process and keep my docs private and secure. I could even build a CI/CD process to load updates into the ERP if I wanted. Right now, I'm using the post-process solution created by @andrigamerita. I have to wrap it using a supported technique, but as long it works completely offline it works. Thanks!

@lebalz
Copy link
Contributor

lebalz commented May 20, 2024

Wow, looking forward to try it! Thanks for implementing this option 😍🥳

@slorber
Copy link
Collaborator

slorber commented May 20, 2024

Hey 👋

The Hash Router PR has been merged: #9859

The hash router is useful in rare cases, and will:

  • use browser URLs starting with a /#/ prefix
  • opt-out of static site generation
  • only emit a single index.html file
  • only do client-side routing and rendering
  • can be browsed offline without a web server with the file:// protocol

You can try this new experimental site option:

export default {
  future: {
    experimental_router: 'hash', // default to "browser"
  }
}

If you need to switch conditionally between normal/browser router and hash router, you can use a Node env variable. We don't provide any --router CLI option but you can easily do ROUTER=hash docusaurus build instead, and read process.env.ROUTER in your config file.

To dogfood this feature, make it easier to review and ensure it keeps working over time, we build our own website with the hash router and:

An example artifact you can download is available here: https://github.com/facebook/docusaurus/actions/runs/9159577535

CleanShot 2024-05-20 at 15 41 14

This will download a website-hash-router-archive.zip file.

Unzipping it gives you a static deployment. You can open it and browse locally without a web server by simply clicking the index.html file.

CleanShot 2024-05-20 at 15 43 45@2x

CleanShot 2024-05-20 at 15 46 08

CleanShot 2024-05-20 at 15 46 39


EXPERIMENTAL FEATURE:

The hash router is experimental.

It will be released in Docusaurus v3.4, but can already be tried in canary releases.

We strongly discourage you from using a baseUrl with it. If you have a use-case for a hash baseUrl, please share it, because we might forbid that in the future. It is likely that the useBaseUrl and useBaseUrlUtils have some edge cases with hash routing because these abstractions were not meant to handle a hash router in the first place.

Otherwise, there may be unhandled edge cases that we missed, so please report here any issue you have by providing a repro. Remember that third-party plugin authors may also need to adjust their code to support this new router. Although it should work out-of-the-box for most plugins, we can't guarantee that it will.

Thanks and please let us know if this feature works well for you.

@pfdgithub
Copy link

pfdgithub commented May 30, 2024

In my case, I use the browser route, and docs.routeBasePath: "/" configuration.
The docs is deployed behind traefik and nginx multiple gateways, and the customer network is is a private network.

Traefik uses the stripprefix middleware to strip the xxx prefix.
Nginx uses the try_files $uri $uri/ /index.html directive to find files.
When the url path triggers the gateway fallback, it will respond with the incorrect redirect path.

# url with filename
browser (/xxx/category/index.html) -> traefik (/category/index.html) -> nginx(/category/index.html) -> nginx status 200 -> traefik -> browser

# url with trailing slash
browser (/xxx/category/) -> traefik(/category/) -> nginx(/category/) -> nginx status 200 (rewrite to `/category/index.html`) -> traefik -> browser

# url without trailing slash
browser (/xxx/category) -> traefik(/category) -> nginx(/category) -> nginx status 301 (redirect to `/category/`) -> traefik -> browser (/category/) -> traefik status 404 -> browser

Due to the /category directory exists, nginx attempts to redirect to that directory.
However, nginx is unaware of the xxx prefix, so it responds with the incorrect redirect to /category/.
If the /category directory doesn't exist, nginx can respond with the correct rewrite to /index.html.

# url without trailing slash (`/category` directory doesn't exist)
browser (/xxx/category) -> traefik(/category) -> nginx(/category) -> nginx status 200 (rewrite to `/index.html`) -> traefik -> browser

I can't modify the configurations of traefik and nginx, and trailingSlash: true is not a perfect solution, so I can only clean up redundant directories after building.
Is it possible to allow disabling the Static Site Generation (SSG) functionality, as well as useless SEO metadata under a private network, such as allowing url: "/"?

@slorber
Copy link
Collaborator

slorber commented May 30, 2024

@pfdgithub your comment is quite hard for me to understand. So far I am not even sure if it is even related to the current issue because none of the URLs you share have a hash, and the hash part of the URL shouldn't affect routing and redirects in any way. If you want help, make sure it's relevant to the current issue,create a smaller repro, and try to explain better including fully qualified urls because the way you share urls right now does not even make it clear which router config you use.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
apprentice Issues that are good candidates to be handled by a Docusaurus apprentice / trainee proposal This issue is a proposal, usually non-trivial change
Projects
None yet
Development

Successfully merging a pull request may close this issue.