bun icon indicating copy to clipboard operation
bun copied to clipboard

--watch and --hot doesn't work when using Bun in certain network environments

Open shelterit opened this issue 2 years ago • 28 comments

What is the problem this feature would solve?

The --watch and --hot options don't work when there's no file system support for directory events, like inside (Docker) containers or with Windows mounts. We use Bun containers with mounted dev file systems, and this is a problem especially for any developer with a Windows machine.

What is the feature you are proposing to solve the problem?

Either;

  1. Support polling in the --watch and --hot implementation, or
  2. Expose a simple API for Bun to do the watch triggering but from an external source, for example;
    • Bun.reload(path);
    • Bun.hotload(path);

(I did try to make a bridge between the node:fs.watch and Chokidar, but found no easy way to transfer triggering, or to de-duplicate events / listeners)

What alternatives have you considered?

I've made this solution (https://gist.github.com/shelterit/ab80a39bc28c86b52c48568ca50fa089) using Chokidar (as a watcher instead), the Bun Loader and require() which feels ... clunky. I'm sure there's a better way, and it would be great to tap into whatever smarts Bun uses for hotloading.

shelterit avatar Sep 21 '23 00:09 shelterit

--watch uses inotify which doesn't work with network mounts. The only option that works in this case is polling.

jumoog avatar Sep 22 '23 13:09 jumoog

This explains a lot i why was impossible to use --hot or --watch on Bun installed on Windows WSL. Thanks for sharing Chokidar alternative

medeiroshudson avatar Sep 23 '23 11:09 medeiroshudson

I guess from the user perspective doesn't matter that much how it works if it works but some comments:

  • Since this is dev time resource use, I'm not too concerned on optimization. If there's significant performance impact, separate --poll or something might be in order.
  • Reliability is probably more important, determining what needs reloading to correctly refresh things.
  • I would prefer it to be a built-in option whatever the solution is. Trying to troubleshoot/optimize parameters of an addon for this is the kind of side track that kills productivity.
  • Would be good to get an error/warning on this "trying to watch a wsl mount does not work, use -poll instead". Also maybe a guide, "if you use Bun over WSL and want edit code in Windows, this is the best way right now".
  • I guess it's also a question if WSL is a long term solution or a stopgap waiting for the native Windows build. Or if the need to support mounts that don't have inotify is actually a long term need also in Linux/Mac.

pragmatta avatar Sep 25 '23 18:09 pragmatta

I have to say that the time it took to figure out even the basics was exhausting; days went by looking for clues, and I think I found the connecting bits as a footnote in some node.js API documentation. And it's all the more important given there's no Bun Windows support (apart from a partial alpha), so a lot of us will run it in containers with mounted systems where --watch and --hot don't work.

I think exposing the reload / hotload as API endpoints is a fairly reasonable and trivial point, enabling developers to find fixes where the built-in support falls down. I'm still struggling to reload properly as the Chokidar paths are relative but the keys in the Bun's Loader.registry are absolute, and the Loader.resolve can't find them (unless I trigger from the right path, which isn't always easily done), and yes, looking into the other resolvers as well.

Bun solves some really huge issues, and I know there's a lot of focus on speed and performance, but for me the two main reasons for why the world needs Bun are 1) import/require working in harmony, and 2) natively speaks any JS dialect; it solves the MAIN issues in the JS world right now, just need to sort out this tiny little thing ... :)

shelterit avatar Sep 26 '23 22:09 shelterit

Has there been any progress here, is Chokidar still the current solution?

ThomasBurgess2000 avatar Nov 25 '23 10:11 ThomasBurgess2000

The bun --watch in my use case works with docker, it was just a question of setting the right volume binding in the docker-compose, this is repo structure:

  • apps
    • indexer
      • Dockerfile.dev
      • src
        • index.ts
    • other_apps
  • packages
  • tooling
  • package.json
  • bun.lockb
  • turbo.json
  • docker-compose.dev.yml

this is the Dockerfile.dev:

FROM oven/bun:1 as build

WORKDIR /usr/src/app

RUN apt-get update && apt-get install -y git

COPY package.json bun.lockb turbo.json ./

COPY apps ./apps
COPY packages ./packages
COPY tooling ./tooling
  
RUN bun install

WORKDIR /usr/src/app/apps/indexer

CMD ["bun", "--watch", "src/index.ts"]

and this is the docker-compose.dev.yml:

version: '3.8'
services:
  indexer:
    build:
      context: .
      dockerfile: apps/indexer/Dockerfile.dev
    volumes:
      - ./apps/indexer:/usr/src/app/apps/indexer
    env_file:
      - apps/indexer/.env.local  
    ports:
      - 8080:8080

when I run the command in the terminal docker-compose -f docker-compose.dev.yml up, and then I change the index.ts (that is the entry of my indexer app) it does hot reload correctly. Hope it helps!

vimercati-samir avatar Nov 30 '23 01:11 vimercati-samir

+1 --watch and --hot don't work on WSL

Moe03 avatar Dec 31 '23 23:12 Moe03

bun --watch --poll index.tsx
Is this supposed to be a solution to the problem? It doesn't work for me. How to do pooling?

KH93b avatar Mar 07 '24 19:03 KH93b

import { Elysia } from 'elysia'; import { watch } from 'chokidar';

const app = new Elysia().get('/', () => 'Hello Elysia').listen(3000);

const __appdir = import.meta.dir;

const __watcher = watch(__appdir, { ignored: /(^|[/\])../, // ignore dotfiles persistent: true, usePolling: true, interval: 800, depth: 5, binaryInterval: 1300, });

__watcher .on('add', path => console.log(File ${path} has been added)) .on('change', path => { console.log(File ${path} has been changed); const key: string = Loader.resolve(path, path); console.log('key', key); Loader.registry.delete(key); require(path); });

console.log( 🦊 Elysia is FFFFQff running at ${app.server?.hostname}:${app.server?.port} );

My code works correctly only once, if you make a change in the file a second time and then the server does not see the change. (bun in docker)

KH93b avatar Mar 07 '24 21:03 KH93b

Hey guys I think I have found solution to the docker --hot problem

instead of using the volumes to persist the files we have to use docker compose watch

here is my file tree

anime-recom-backend/
┣ data/
┃ ┣ anime_movies.csv
┃ ┗ anime_series.csv
┣ db-data/
┣ server/
┃ ┣ drizzle/
┃ ┃ ┣ meta/
┃ ┃ ┃ ┣ 0000_snapshot.json
┃ ┃ ┃ ┗ _journal.json
┃ ┃ ┗ 0000_zippy_mimic.sql
┃ ┣ src/
┃ ┃ ┣ db/
┃ ┃ ┃ ┣ connection.ts
┃ ┃ ┃ ┣ migration.ts
┃ ┃ ┃ ┣ populate.ts
┃ ┃ ┃ ┣ queries.ts
┃ ┃ ┃ ┗ schema.ts
┃ ┃ ┗ index.ts
┃ ┣ .dockerignore
┃ ┣ .gitignore
┃ ┣ bun.lockb
┃ ┣ Dockerfile
┃ ┣ package.json
┃ ┣ README.md
┃ ┗ tsconfig.json
┣ .env
┗ docker-compose.yaml

here is my docker compose file

version: '3.8'
services:
  bun-server:
    container_name: bun-server
    restart: always
    build: 
      context: ./server
      dockerfile: Dockerfile
    ports:
      - ${BUN_PORT}:${BUN_PORT}
    depends_on:
      - db
    environment:
      - DB_HOST=db
      - DB_PORT=${DB_PORT}
      - DB_USER=${DB_USER}
      - DB_PASSWORD=${DB_PASSWORD}
      - DB_NAME=${DB_NAME}
    volumes:
      - ./data:/usr/src/app/data
    develop:
      watch:
        - action: sync
          path: ./server/src
          target: /usr/src/app/server/src
        - action: sync
          path: ./server/drizzle
          target: /usr/src/app/server/drizzle
        - action: rebuild
          path: ./server/package.json
  db:
    image: postgres
    container_name: postgres-db
    ports:
      - '5433:${DB_PORT}'
    volumes:
      - ./db-data:/data/db
    environment:
      - POSTGRES_PASSWORD=${DB_PASSWORD}
      - POSTGRES_DB=${DB_NAME}

volumes: 
  db-data:

here is the docker file

FROM oven/bun:alpine

WORKDIR /usr/src/app/server

COPY package*.json ./
COPY bun.lockb ./

RUN bun install --frozen-lockfile

COPY ./src /usr/src/app/server/src

EXPOSE 5000

CMD [ "bun" , "run" , "dev"]

dev command is as follows

"dev": "bun run --hot src/index.ts",

so basically what this does is it watches for changes in your local env and persists it in the container instead of using volumes which will be mounted on to the container, watch command updates the files in the container hence bun will capture these changes and hot reload. I read that docker compose watch doesn't use polling so it will be a better option I don't have complete idea on how this works internally. But this method avoids the use of Chokidar or any other extra packages

I am new to writing such comments if there is some mistake correct me 😁😁

AdityaT-19 avatar Mar 08 '24 08:03 AdityaT-19

volumes:
  - ./data:/usr/src/app/data

I think this is not necessary

KH93b avatar Mar 08 '24 09:03 KH93b

docker compose watch - this command does not display the server console.

a few time.. )) docker compose up -> docker compose watch

EEEEEEEEEEESSSSSSSSSSSSSSSS hot reload WORKS!!!!!!!!!!!

KH93b avatar Mar 08 '24 09:03 KH93b

volumes:
  - ./data:/usr/src/app/data

I think this is not necessary

Ya this required because I have an ML app using the same data.

AdityaT-19 avatar Mar 08 '24 13:03 AdityaT-19

docker compose watch - this command does not display the server console.

a few time.. )) docker compose up -> docker compose watch

EEEEEEEEEEESSSSSSSSSSSSSSSS hot reload is WORK!!!!!!!!!!!

docker compose up is not needed and you can check the logs in docker desktop I am happy that it worked.

AdityaT-19 avatar Mar 08 '24 13:03 AdityaT-19

docker compose up is not needed and you can check the logs in docker desktop I am happy that it worked.

I also use shared data, but it works for me without volume. Moreover, with volume I received a warning that watch will not work.

... I understand that it will not be tracked if volume and watch refer to the same folder

KH93b avatar Mar 08 '24 14:03 KH93b

Anyone found a workaround for Minikube?

I have a host volume mounted to the containers, and when I can verify in the shells that files are updated in the pods, yet Bun doesn't detect it and reload.

Tried installing pm2 in the docker container, but it doesn't detect file changes from the host machine either.

Drejerdk avatar May 09 '24 20:05 Drejerdk

I found out that to reflect the changes you need to manually Control + S inside of your Docker then

https://github.com/user-attachments/assets/1296b0de-ad73-473d-98f7-bb8f6a5c28ee

I hope this data can help you sir @Jarred-Sumner

moshOntong-IT avatar Sep 11 '24 11:09 moshOntong-IT

This is how I use it for development and works.

Steps:

  1. Add a docker-compose.yaml file to the root of your project. Put this content.
services:
  server:
    container_name: bun-watch
    image: oven/bun:1.1.30-alpine
    command: bun run --bun --watch ./src/server.ts
    working_dir: /home/bun/app
    user: "${UID}:${GID}"
    volumes:
      - .:/home/bun/app
      - ~/.bun-docker:/home/bun/.bun
    env_file:
      - .env
  1. docker compose up -d

Notes: A new docker container called bun-watch has started and every change to project is being updated.

eduinlight avatar Oct 16 '24 10:10 eduinlight

This is how I use it for development and works.

services:
  server:
    container_name: replica-events-server
    image: oven/bun:1.1.30-alpine
    command: bun run --bun --watch ./src/server.ts
    working_dir: /home/bun/app
    user: "${UID}:${GID}"
    volumes:
      - .:/home/bun/app
      - ~/.bun-docker:/home/bun/.bun
    env_file:
      - .env

can you explain how does it work?

moshOntong-IT avatar Oct 16 '24 13:10 moshOntong-IT

This is how I use it for development and works.

services:
  server:
    container_name: replica-events-server
    image: oven/bun:1.1.30-alpine
    command: bun run --bun --watch ./src/server.ts
    working_dir: /home/bun/app
    user: "${UID}:${GID}"
    volumes:
      - .:/home/bun/app
      - ~/.bun-docker:/home/bun/.bun
    env_file:
      - .env

can you explain how does it work?

Check my updated comment

eduinlight avatar Oct 16 '24 14:10 eduinlight