I actually prefer @cnck1387’s method of just letting node handle the watching, but this is my setup from a project without webpack and with elixir watchers:
zombie.sh
is from Port — Elixir v1.12.3 which fixes the hanging process issues. If you use it, you must run the binaries directly, as shown, npx tailwindcss
won’t work, you’ll end up with zombies still.
# dev.exs
anti_zombie = Path.expand("../assets/zombie.sh", __DIR__)
config :project, ProjectWeb.Endpoint,
http: [port: 4000],
debug_errors: true,
code_reloader: true,
check_origin: false,
watchers: [
"#{anti_zombie}": [
"./node_modules/.bin/tailwindcss",
"--input",
"css/app.css",
"--postcss",
"--output",
"../priv/static/css/app.css",
"--watch",
cd: Path.expand("../assets", __DIR__)
],
"#{anti_zombie}": [
"./node_modules/.bin/esbuild",
"./js/app.js",
"--target=es2015",
"--bundle",
"--outdir=../priv/static/js",
"--sourcemap",
"--watch",
cd: Path.expand("../assets", __DIR__)
],
"#{anti_zombie}": [
"./node_modules/.bin/cpx-fixed", # replace with entr?
"static/**/*",
"../priv/static",
"--watch",
cd: Path.expand("../assets", __DIR__)
]
]
// package.json
"scripts": {
"prod:css": "tailwindcss --input css/app.css --postcss --output ../priv/static/css/app.css",
"prod:js": "esbuild js/app.js --target=es2015 --bundle --outdir=../priv/static/js",
// depending on how you build, you may need to clear the dest
// my docker build process starts with a clean dest naturally so I don't worry
"prod:static": "cp -R static/** ../priv/static",
"prod:build": "npm run prod:static && npm run prod:js && npm run prod:css"
},
What I don’t like about this, is having to maintain both separately.
Since zombie.sh npm run dev:css
will leave you with hanging processes, you must make sure to keep any options in sync between both files (hence why letting node do it all can feel nicer).
The hanging process stuff can be particularly painful with tailwind’s jit since it writes incrementally and things tend to get clobbered.