bun
bun copied to clipboard
--watch and --hot doesn't work when using Bun in certain network environments
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;
- Support polling in the --watch and --hot implementation, or
- 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.
--watch uses inotify which doesn't work with network mounts. The only option that works in this case is polling.
This explains a lot i why was impossible to use --hot or --watch on Bun installed on Windows WSL.
Thanks for sharing Chokidar alternative
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.
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 ... :)
Has there been any progress here, is Chokidar still the current solution?
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
- indexer
- 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!
+1 --watch and --hot don't work on WSL
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?
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)
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 😁😁
volumes:
- ./data:/usr/src/app/data
I think this is not necessary
docker compose watch - this command does not display the server console.
a few time.. )) docker compose up -> docker compose watch
EEEEEEEEEEESSSSSSSSSSSSSSSS hot reload WORKS!!!!!!!!!!!
volumes: - ./data:/usr/src/app/dataI think this is not necessary
Ya this required because I have an ML app using the same data.
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.
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
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.
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
This is how I use it for development and works.
Steps:
- Add a
docker-compose.yamlfile 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
docker compose up -d
Notes: A new docker container called bun-watch has started and every change to project is being updated.
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?
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: - .envcan you explain how does it work?
Check my updated comment