Some projects claim they are "zero dependencies" but a few sentences into the readme and you see an `npm install` and now you notice there is `package.json` after all . They meant zero runtime dependencies, which is still praiseworthy, but not zero `devDependencies`.
For my greenfield web app, I attempted to have zero dev dependencies on Node. I wrote some vanilla HTML, JS, CSS, and now needed to reduce network transfer. Requirements:
- minify
- inlining CSS file into HTML
- compress with Brotli
- print out final byte size
- nice to have: run a dev server that serves static Brotli
We know the story with WebPack. I looked to Parcel instead because it's the "zero-config" tool. It was promising because it inlined my `@import css` into my HTML, and logged out the filesize. The watch and reload feature wasn't working as promised, but that was nice to have anyways. For Brotli compression, which is mainstream at this point, I quickly needed to add a `.parcelrc` config. Their code sample didn't work because it turns out that in the real world you need to make your .parcelrc extend/inherit "@parcel/config-default". Parcel stopped logging at the compressed file sizes and not the final Brotli file sizes. Finally, Parcel's dev server is useless to me because you can't set encoding headers for "Brotli" files so the browser just attempts to download it. I didn't have a .gitignore file, and adding this one Node dependency on Parcel added 3,000 new files. To be fair, that's miniscule for a Node project.
I asked myself if I can achieve the same results with CLI tools that are not Node. I first looked to the Golang ecosystem. I stumbled upon https://github.com/tdewolff/minify. It just does minification. It's comparable in output size to other Node minifiers, but faster and just works. The lexer code is very readable, even for me who is not a compiler or systems expert. It's one command to install the CLI, and one command to Minify. You can do `npm install global -g` to get CLIs, but Node supply chains tend to be much deeper.
This bespoke one-liner does the CSS inlining for me:
RUN sed -i "s/@import \"style.css\"/$(cat style.css)/g" index.html`
For Brotli compression, I went with the official first party CLI ( also Go based ) instead of using a third-party wrapper like you'd have to do with JavaScript.One thing I was missing in NPM scripts as a self-documenting way of describing what commands to build, run, test. I've seen cases where people are beholden to a `package.json`, sometimes when their project doesn't even involve JavaScript. When you have a hammer, everything looks like a nail. It turns out Makefiles are a better way of doing this, especially if you don't already have a active relationship with Node
.PHONY: help
help: ## This help.
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
# DOCKER TASKS
build: ## Build the container
podman build -t ${APP_NAME} .
run: ## Run container on port configured in `config.env`
podman run -it --rm -d --env-file=./config.env -
p=$(HOST_PORT):80 --name="$(APP_NAME)"
It's even better than self-documentation, because the documentation is self-documenting: $ make help
help This help.
build Build the container
run Run container on port
configured in `config.env`