I'm using a babel plugin to load environment variables from a .env
file into a React Native project, but changes to the .env
file are not loaded until the javascript file importing them changes. I'd like a way to tell the react-native packager to recompile in the event that this file changes. I would accept an answer that:
- Simply re-transpiles the entire project when a specific file (
.env
) changes. - Re-transpiles only those files containing a specific string, say
foo
Is there a simple way to do this by writing a plugin/middleware? Maybe a separate background script that fires events to watchman that the react-native packager is listening for?
[EDIT in reply to a comment]
My current .babelrc
is the following, where babel-plugin-react-native-config
is a plugin I wrote to do hot variable swapping in conjunction with the react-native-config
package.
{ "presets": [ "react-native" ], "plugins": [ ["babel-plugin-espower", { "sourceRoot": "./App" }], "transform-flow-strip-types" ], "env": { "production": { "plugins": [ "babel-plugin-unassert", ] }, "development": { "plugins": [ ["babel-plugin-react-native-config", { envfile: ".env" }] ] } } }
The problem is that the react-native packager only watches javascript files. I don't think changing my babel configuration will help, unless babel can somehow speak upwards to react-native or watchman to inform it that some file needs recompiling...
[EDIT 2]
I determined that the react-native packager uses watchman to watch files. E.g., when I do watchman watch-list
after starting the packager (and after doing a watchman watch-del-all
), I get
{ "version": "4.6.0", "roots": [ "/path/to/my/project" ] }
Moreover, when I delete this watch while the packager is running, nothing happens (from its perspective, the js isn't changing because it doesn't receive any updates), but then when I restart the packager it recreates this watch and transpiles everything.
So it seems that, unless there's a better way, I have to create a watchman trigger to both (1) kill the react-packager (2) kill the watch on my app directory (3) restart the node packager. This seems slow and hacky, but I would like to see if it can even work.
I haven't quite gotten this to work in a generic way, but I'm experimenting with various things.
1 Answers
Answers 1
Since it's been two weeks since I've asked this question, I'm going to post the (kind of terrible) workaround I was able to cobble together. I will leave this question unanswered, and accept any new answer that is better (less hacky) than this one.
The react native packager uses watchman
to watch for filesystem changes, and upon getting an event that some JS file has changed, it looks to see if the file has actually changed, and then retranspiles if so. This prevents me from doing something simple like a watchman trigger that touch
es the relevant JS file, because the react packager thinks it's so smart that it can ignore updates with no diff. Whatever.
So my solution is to create a watchman trigger on .env
changing which calls make clear_env_cache
, where clear_env_cache
is the following (phony) target in a Makefile
.
# get the PID of the react packager pid := $(shell lsof -i:8081 | grep node | awk '{print $$2;}' | head -n 1) # Kill files that the packager uses to determine whether it needs to # re-transpile a js file, then restart the packager clear_env_cache: find ${TMPDIR}/react-native-packager-cache-* -name "my_pattern" | xargs rm kill -9 $(pid) || echo "no packager running" nohup node node_modules/react-native/local-cli/cli.js start > /dev/null 2>&1 &
Note that my_pattern
will change depending on your project layout. For me there's one file importing all the envvars called Settings.js
, so the pattern is "*Settings*"
. Note this target also basically kills and reboots the packager every time the file changes, and it nohup
s the node packager so you won't be able to see the process anymore. Not a big deal unless you need to view the output of the packager.
The watchman-cli command to trigger this is watchman-make --root . -p .env -t clear_env_cache
and for convenience I set up a make target that nohups
this command:
# Run `make hotswap_env` to allow envvar changes to show up in the react-native packager. hotswap_env: nohup watchman-make --root . -p .env -t clear_env_cache > /dev/null 2>&1 &
Now I can (once per system boot) run make hotswap_env
and it will trigger whenever .env
changes and ensure the packager server is continuously running.
Disclaimer: This script is probably not portable, and is definitely brittle. Caveat emptor and YMMV and IANAL and all that. Suggested improvements for portability are welcome.
0 comments:
Post a Comment