polypush135

polypush135

I’m really liking the way this example app does assent building and watching
https://github.com/wittyprogramming/tailwindcss-alpinejs-starter/blob/master/package.json

At the surface, you will notice that it does not delegate the building or watching of the style sheets to esbuild and instead just defaults to postcss. The more I look at this the more it makes sense.

I know that phoenix needs to have a trigger to tell live reload that something changed.
What issues could I run into if I had multiple watches running simultaneously?

I really want to mimic this asset pipline in my phoenix app. ESbuild is just too fast to ignore for webpack.

Showing Posts 1 to 10

kokolegorille

kokolegorille

Isn’t it something that can replace webpack?

You might not need both…

I have used multiple watchers without problem. I have one for wasm-pack for example. When I change rust code, it compiles to wasm and reloads the page.

    cargo: [
      "watch",
      "-i",
      ".gitignore",
      "-i",
      "pkg/*",
      "-s",
      "wasm-pack build",
      cd: Path.expand("../assets/wasm/rustyapp", __DIR__)
    ]

But I could not make it work for multiple instances of the same watcher. I had too many files open error.

I have used 2 bundlers sequentially too, without problem, maybe not really useful.

It was bucklescript, and then webpack :slight_smile:

I don’t think it’s a problem to use ESBuild and Webpack, but have never tried.

polypush135

polypush135 OP

Esbuild can replace webpack.

It would be EsBuild + PostCss
EsBuild for all the JS
And Postcss for the CSS.

My only real concern at the moment for EsBuild is around wasm

mhanberg

mhanberg

Expert LSP Core Team

I’ve written about this in case you want to take a look: How I Handle Static Assets in my Phoenix apps | Mitchell Hanberg

polypush135

polypush135 OP

Thank you! I’m gonna read this right now

postcss-cli processes my CSS and can run the
TailwindCSS JIT
mode without any problems.

Noice! the JIT mode + ESBuild. The build times must be so much faster.

polypush135

polypush135 OP

Question about your post:

Why did you not put your commands in the package.json file and use npm run ?

Edit: never mind I forgot there is a legit reason why phoenix does not already do this too.

mhanberg

mhanberg

Expert LSP Core Team

I will note that since writing this article, I have noticed that cpx has a problem with leaving zombie processes.

I also noticed that there is a fork, cpx2, that is more actively maintained. I opened a pull request on that fork to fix the zombie process issue Exit when stdin closes by mhanberg · Pull Request #23 · bcomnes/cpx2 · GitHub, but I am not sure if or when it will be merged.

mhanberg

mhanberg

Expert LSP Core Team

I have also looked into just using the new tailwind cli, but it also has the zombie process issue.

polypush135

polypush135 OP

Have you seen GitHub - AvianFlu/ncp: Asynchronous recursive file copying with Node.js. · GitHub before? Thinking about giving it a try my self in place of cpx

Edit: ah missed the lacking the watch feature. Prob not the better option

sntran

sntran

I’m not sure why we would reinvent cp -r with a Node.js version. If a simple cp -r will do the job, why writing something in another language?

As for watching and copying changed files over, a simple Makefile will do the job nicely.

I have pretty much using the combination of Makefile, tailwind CLI with JIT, and ESBuild.

  
#!/usr/bin/make -f

# Recursive wildcard function to find a pattern inside a folder.
# Example: $(call rwildcard,css,*.scss)
rwildcard = $(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d))

# Uses built-in `wildcard` function to find all immediate children of each asset folder.
# Then use another built-in `pathsubst` function to "rename" them to the final output.
styles := $(patsubst %.css,%.min.css,$(filter-out %.min.css, $(wildcard priv/static/css/*.css)))
scripts := $(patsubst %.mjs,%.min.js,$(wildcard priv/static/js/*.mjs))

# The first target will be executed if running `make` with no target specified.
# This target is marked as "phony" with the `.PHONY`. Phony targets do not correspond
# to actual file or folder, and will always be considered outdated.
#
# This target also has no recipe, but have other targets as prerequisites. These
# prerequisites will be checked for freshness.
.PHONY: all
all: node_modules $(styles) $(scripts)

priv/static/css/%.min.css: priv/static/css/%.css priv/static/css/%/tailwind.css
	@npx esbuild '$<' --minify --sourcemap --bundle --outfile='$@'

priv/static/css/%/tailwind.css: tailwind.config.js $(call rwildcard,lib/usenet_web,*.eex) $(call rwildcard,lib/usenet_web,*.leex)
	npx tailwind build -o $@

priv/static/js/%.min.js: priv/static/js/%.mjs
	@npx esbuild '$<' --minify --sourcemap --bundle --outfile='$@'

# The node_modules target will run whenever `package.json` and/or `package-lock.json`
# changes, which is usually when we checkout from remote repo, or installing new module.
# Here, we run `npm install` to ensure all node modules are installed.
# We have to `touch` the folder since only addition and removal of files will change
# the modified date of the folder.
node_modules:	## Ensure dependencies are up-to-date
node_modules: package.json package-lock.json
	npm install
	@touch -m node_modules

watch: ## Simple interval-polling watcher that will run `make` when there is something to be done.
	while true; do $(MAKE) -q || $(MAKE); sleep 0.5; done
soup

soup

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.

Where Next? Top

Trending in Discussions Top

AstonJ
As the title says, please share what you’ve been up to with Elixir. Whether that’s been learning it, looking into it, making stuff with i...
2977 94592 917
New
cblavier
Hey there, It’s been more than a year since we started using LiveView as our main UI library and building a whole library of UI componen...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
heathen
Quite interesting article Google brought me. Didn’t find any mentions about it here. What do you think in general? Would you use togethe...
New
maennchen
:warning: Security advisory: Decimal DoS vulnerability A vulnerability has been published for decimal where very large exponents can cau...
New
marciol
It would be helpful to have a list of companies worldwide that hire engineers without prior experience in Elixir. Often, it can be quite ...
New
durvia
Anyone running long-lived stateful processes on BEAM? We’re building an AI agent runtime and would love to compare notes. We’re a small ...
New

Other Trending Topics Top

marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New
webofbits
Aludel - LLM Evaluation Workbench Aludel is an embeddable Phoenix LiveView dashboard for evaluating and comparing LLM prompts across mult...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews