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

docker / serve / WebSocket connection to 'ws://0.0.0.0:3000/__livereload' failed: bad URL #1698

Closed
aheissenberger opened this issue Dec 1, 2021 · 3 comments · Fixed by #1771
Labels
Command-serve Command: serve

Comments

@aheissenberger
Copy link

problem:
The web socket connection fails if the IP of the website is not equal to the IP used to start mdbook serve which is different when started in a docker container.

setup:

  • docker compose with the ports 0.0.0.0:3000 (docker container) => 127.0.0.1:3000 (host) and 3001:3001 mapped.
  • page is visible but refresh fails after change

The problem is, that mdbook server has to listen on all external ports in the container:
mdbook server --hostname '0.0.0.0'

The page preview is viewed under http://127.0.0.1:3000

Dockerfile

FROM rust as builder

RUN cargo install mdbook ; \
    cargo install mdbook-toc; \
    cargo install mdbook-mermaid;

FROM debian:buster-slim
RUN apt-get update && rm -rf /var/lib/apt/lists/*
COPY --from=builder \
    /usr/local/cargo/bin/mdbook \
    /usr/local/bin/
COPY --from=builder \
    /usr/local/cargo/bin/mdbook-toc \
    /usr/local/bin/
COPY --from=builder \
    /usr/local/cargo/bin/mdbook-mermaid \
    /usr/local/bin/

WORKDIR /mdbook

docker-compose.yml

version: "3"
services:
  mdbook:
    build: ./.docker
    volumes:
      - "${PWD}:/mdbook"
    stdin_open: true
    tty: true
    ports:
      - "3000:3000"
      - "3001:3001"
    entrypoint: "/usr/local/bin/mdbook"
    command:
      - serve
      - --hostname
      - '0.0.0.0'
@aheissenberger
Copy link
Author

Could it be a solution to replace "{{{livereload}}}" with window.location.hostname+':'+(window.location.port? window.location.port:'80')?

mdBook/src/theme/index.hbs

Lines 224 to 236 in a72d600

<script type="text/javascript">
var socket = new WebSocket("{{{livereload}}}");
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload();
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>

@ehuss ehuss added the Command-serve Command: serve label Dec 30, 2021
@clement2026
Copy link
Contributor

clement2026 commented Mar 18, 2022

I'm looking into this issue. I've made some changes to my branch(PR #1771) :

            const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
            const wsAddress = wsProtocol + "//" + location.host + "/" + "{{{live_reload_endpoint}}}";
            const socket = new WebSocket(wsAddress);

WebSocket of livereload now uses host and port of the current page, and it works with HTTPS site.

I'v started mdbook inside a Docker container on my Linux server, which can be accessed at https://mdbook-1698.issue.fuyongxing.com, using the following Dockerfile:

FROM rust

WORKDIR /app
COPY . /app

WORKDIR /app/code

RUN  cargo install --path .

WORKDIR /app

RUN  rm -rf code ~/.cargo/git ~/.cargo/registry

CMD ["mdbook","serve" ,"--hostname", "0.0.0.0"]

The '__livereload' endpoint is successfully connected:
image

For developers who use a system network proxy:
WebSocket may not work on Safari and Firefox behind a proxy, which it is not a problem on Chrome and Edge.
On Safari, turn off Develop->Experimental Features->NSURLSession WebSocket to get the WebSocket to work behind a proxy.

@clement2026
Copy link
Contributor

clement2026 commented Mar 18, 2022

In the current version of mdbook, output.html.livereload-url option is used to set the livereload url. In fact, this option has no effect since it is always overridden by the following code:

    let address = format!("{}:{}", hostname, port);

    let livereload_url = format!("ws://{}/{}", address, LIVE_RELOAD_ENDPOINT);
    let update_config = |book: &mut MDBook| {
        book.config
            .set("output.html.livereload-url", &livereload_url)
            .expect("livereload-url update failed");

Since the WebSocket could use the host and port of current page, there seems no reason to keep the output.html.livereload-url option. To avoid breaking changes, I didn't remove this option. I change it to output.html.live-reload-endpoint instead.

From my perspective, an output.html.use-live-reload = true / false option may be a better solution. What do you think? @ehuss

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Command-serve Command: serve
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants