[HN Gopher] Makefiles for web work
___________________________________________________________________
Makefiles for web work
Author : sarahdellysse
Score : 80 points
Date : 2023-01-10 19:28 UTC (1 days ago)
(HTM) web link (rosszurowski.com)
(TXT) w3m dump (rosszurowski.com)
| abathur wrote:
| I haven't played around with the make-alikes, but I have also
| taken to using make for this sort of thing.
|
| My blog, for example, has make targets for things like making a
| production build, publishing, cleaning out generated artifacts,
| and running a dev build (with drafts) + bringing up the test
| server.
|
| Last year I wrote a little post about how I also use make + nix-
| shell to supply dependencies for Makefile tasks without needing
| to have them on my PATH: https://t-ravis.com/post/nix/nix-make/
| LAC-Tech wrote:
| I tried this for a bit until I found out make couldn't deal with
| spaces in the file name. switched to rake (ruby), which had the
| advantage of not needing to write separate shell scripts.
| saurik wrote:
| Why do you have spaces in the filenames of your project in the
| first place? They require annoying escapes to work with
| essentially everywhere, notably including on the web. You have
| complete control over the filenames in your project... why are
| actively choosing to use a space character? I can see a better
| argument for wanting to use an _apostrophe_ in a filename than
| a _space character_ :(.
| LAC-Tech wrote:
| Because I wanted the title of my blog posts to match the file
| name, so I didn't have to remember which markdown file was
| which post.
| FatActor wrote:
| Just making a bunch of phony rules is writing a shell script with
| extra steps.
|
| How about converting electron-forge-webpack-ts to make. That
| would be epic.
| srhtftw wrote:
| I've done things this way for many years but now that I'm working
| with rust I find myself doing more with cargo instead.
|
| Compared to make, one thing I like about cargo is I don't need to
| worry about the current directory as much. e.g. "cargo check"
| works from anywhere in my workspace but something like "make
| check" will fail if the Makefile isn't in the current directory.
|
| Yes I know I could probably create an alias, direnv or something
| to improve make's behavior but I'd rather not have more things to
| manage. All this stuff is too complicated as it is. Overall the
| cargo defaults are much more ergonomic.
| hk1337 wrote:
| I went through my Makefile stage. It can be nice but it can also
| get messy and ugly. If you're doing simple tasks fine but your
| project still needs to have a lot things anyways that negates its
| usefulness.
| zelphirkalt wrote:
| It is at least much better than having tasks and their
| dependencies merely specified as plain strings in a package.json
| file, as unstructured data, out of which the tool (npm) does not
| have any knowledge about dependencies and simply runs all strings
| as commands. This is done by countless web projects and it is
| embarrassing. I would rather have a package.json script that
| calls Make, than define my steps in the package.json itself.
| xalava wrote:
| I realize that I have been using shell scripts for this. I just
| copy-paste commands and add a selector. It has the benefit that I
| didn't need to learn a new syntax.
| jsoverson wrote:
| I tried repeatedly to just stick with Makefiles but I kept having
| to add workaround and hack to do basic stuff. They got uglier and
| uglier. I checked out go task and cargo make, but eventually gave
| in to `just`. It has worked just fine and the files are
| infinitely more readable than the comparable ones w/ make.
| ajross wrote:
| What kind of workarounds and hacks? Make's task interface is
| essentially "anything you can do at the command line",
| generally with the same syntax (though you have to put extra
| parens around your variable names).
|
| It's true that more modern tools have features make doesn't
| (especially with regard to manipulating complicated dependency
| graphs) or attack parts of the problem that make doesn't
| (hermetic build environments, language-aware features like
| package management).
|
| But... I can't see "lack of ability to do basic stuff" as one
| of its problems. What basic things are you trying to do?
| klodolph wrote:
| GNU Make only recently added any support for rules which
| produce multiple targets.
| jsoverson wrote:
| I see `.PHONY` as a hack, `MAKEFLAGS += --no-builtin-rules`
| as a workaround, and many of the builtin functions as being
| difficult to use, read, and understand. A long string of
| nested replacements generating the sources for a task is a
| pain to read and maintain.
|
| What I want out of task runners nowadays is to _run tasks_.
| If I can 't make a task without writing '.PHONY' - there's a
| problem with the task runner.
| ajross wrote:
| Meh. OK. Though almost always, "run tasks" implies some
| level of state. Are you tasks truly all idempotent and
| parallelizable? If not, maybe they should produce output
| and be tracked by dependencies? If so, then you probably
| have bugs in your "task runners" that will show up in weird
| ways.
|
| It's absolutely true that ".PHONY" looks like a hack; it
| was sort of meant to. In general you shouldn't be using it,
| except maybe as a facade layer where you can put an "API"
| (c.f. the "all" or "clean" targets) on top of things that
| are themselves proper dependencies.
|
| I'm not going to hold up make as the ultimate expression of
| a dependency-based build system. But I will say that
| history has a _LONG_ trail of products that tried to
| replace it with decidedly mixed results. Categorical
| statements like yours tend to trigger my "code smell"
| layer, most of the time attempts to replace make produce
| worse results.
| throw10920 wrote:
| > Though almost always, "run tasks" implies some level of
| state.
|
| Yes! But isn't one of the major design principles of Make
| that the host filesystem is the container for the state?
| (iirc Make decides when to re-run rules based on when the
| timestamp on a target is older than the timestamp on an
| input file)
| ajross wrote:
| Sure, so where does that state get stored in a pure "task
| runner" tool? Attempts to muck with this metaphor ("state
| is what is left behind when the tool is not running") are
| among the _worst_ mistakes made by build systems. It 's a
| feature, not a bug, and everyone who believes otherwise
| ends up rediscovering it the hard way.
| benatkin wrote:
| This is sweet but `just` is even sweeter - can use multistage
| build files to elegantly add it to any Containerfile, no?
|
| Edit: I don't see a publicized image - added an issue:
| https://github.com/casey/just/issues/1497
|
| However, anyone could add a docker just for just for their own
| project and use it to pull in just for all their projects,
| avoiding a download command to get just in other Containerfiles.
| skwee357 wrote:
| Totally agree with the author. As someone who jumps between
| multiple projects, in different languages-I have hard time
| remembering what build/test/script runner in used in particular
| project. Hell, even two JS/TS projects can use different tools
| (one could use npm with jest, the other yarn with webpack, etc).
|
| I written[1] a blog on that as well. Glad to see there are more
| like minded people out there.
|
| [1] https://www.yieldcode.blog/post/why-you-should-adpot-
| makefil...
| latchkey wrote:
| Just [0] was discussed on HN. I think I'll give that a shot next
| time I have to write something like this. .PHONY is lame.
|
| [0] https://news.ycombinator.com/item?id=34315779
| pdimitar wrote:
| I strongly recommend `just`. I used it successfully with
| projects written in OCaml, Rust, Go, Elixir and Lua. Define a
| few tasks, give them 1-2 character aliases, profit.
|
| Super ergonomic.
|
| Though I have to admit, Go and Rust projects hardly needed
| `just`; the `go` program and the `cargo` tool are _that_ good.
| I used `just` in them mostly to have short aliases and common
| names for tasks.
| latchkey wrote:
| > Go and Rust projects hardly needed just
|
| It depends on what you're producing as output.
|
| One of my golang projects needs `-s -w -X '' -trimpath` along
| with separate GOOS and GOARCH depending on platform.
|
| It is nice to have all that documented in a build file.
| pdimitar wrote:
| Yep, agreed!
| timw4mail wrote:
| I really like how easy it is with Just to make it self-
| documenting.
|
| There's some good things about Makefiles, yes, but there's also
| a lot of weird legacy functionality. Make was meant to create
| files and directories, and the .PHONY functionality seems to be
| a workaround added to make it usable as a general-purpose task
| runner.
| woodrowbarlow wrote:
| `make` is not a taskrunner, it is for tracking dependencies
| between files. a .PHONY target that isn't named "all", "clean",
| or "dist" is a code smell. there are many design decisions in
| `make` that are the opposite of what you want in a taskrunner:
|
| * each line executes in an isolated environment
|
| * can't pass options or arguments to a make target
|
| * not portable to other operating systems
|
| the author is already using node packages. purpose-built
| taskrunners are plentiful, and the resulting scripts will be
| written in the same language as the rest of the codebase instead
| of adding a second language.
|
| hiding a tool behind a makefile is my pet peeve. a proper
| taskrunner makes common operations easy _without_ kneecapping the
| flexibility of the underlying tools.
| shadowgovt wrote:
| It's interesting, but I can't help but think that by the time
| you're adding `.PHONY` after most rules, you're not using the
| right tool for the job.
|
| (I generally find a small set of shell scripts work, or just
| three or four rules in the package.json file I can access with
| `npm run`).
| randomdata wrote:
| I generally find shell/npm scripts work until you get to the
| few cases that actually benefit from the dependency management
| and then you wish you'd just given in to .PHONY, no matter how
| inelegant it may be.
| shadowgovt wrote:
| All of my dependency management issues are handled by npm.
|
| The main problem `make` solved was not wasting work
| rebuilding dependencies that hadn't changed, but in 2023 on
| modern computers I don't notice the CPU cycles burned on that
| kind of thing.
|
| (... if I _do_ start to notice them, I reach for a tool like
| bazel, because it can handle spaces in filenames).
| [deleted]
| hk1337 wrote:
| https://c.tenor.com/2hLnLe93160AAAAd/family-guy-youre-a-big-...
| xyzzy_plugh wrote:
| I think .PHONY is mostly fine, but as soon as you have any sort
| of runtime arguments or interactive stdin/stdout you are
| definitely using the wrong tool.
| klodolph wrote:
| I think the reason for the .PHONY is just so people don't have
| to ./
|
| I generally reach for a shell script with "case" instead,
| though. Can always invoke make from the shell script.
| akira2501 wrote:
| In our case we have most of the processes that are run by make
| tee their output into a project log directory. Then the make
| rules can use the log file itself as the dependency for the
| target. Works great in a lot of cases, and, you get the added
| benefit of being able to easily go back and observe previous
| process output and compare it across projects.
| nine_k wrote:
| The [Just] task runner can be what you want: it's simpler than
| Make, with less magic, but it allows to declare task
| dependencies.
|
| [Just]: https://github.com/casey/just
| charcircuit wrote:
| >People routinely point out that npm/yarn scripts are shockingly
| slow to start
|
| The claim that 157 ms and 126 ms is "shockingly slow" is quite an
| exaggeration.
| naniwaduni wrote:
| 126 ms is already well above the threshold of latency you can
| expect to notice when typing at a keyboard. By comparison, it'd
| almost be a long enough time to start caring as a TTFB. It
| really is a shockingly long time.
| pdimitar wrote:
| It's not an exaggeration when you inevitably end up chaining
| them. The overhead adds up very quickly and becomes noticeable.
|
| Also they take even longer to start in CI/CD containers.
| masukomi wrote:
| true, but the moment you add containers to your mix you're
| functionally admitting that you don't care about startup
| times. Or possibly, you've been forced to do it by some
| service provider who doesn't give you a better option...
| pdimitar wrote:
| I mean you're not wrong in general, it's just that if the
| tool is written in C/C++, Zig, Rust, Golang, OCaml, D, V,
| and a few others, it still start in maximum 20ms even in
| containers.
| klysm wrote:
| Make becomes a pretty terrible tool at a fairly low level of
| complexity. I would never choose it voluntarily to build things.
| shadowgovt wrote:
| I agree. It has its merits, but it's hard for me to get around
| my visceral reaction to the fact it just bombs on filenames
| with spaces in them.
| david2ndaccount wrote:
| You can escape spaces in makefiles.
| turmeric_root wrote:
| "can" or "have to"?
| klodolph wrote:
| Sure... but if you have spaces in filenames, and filenames
| in variables, what happens then?
| drowsspa wrote:
| Yeah, think of how programming languages invent and reinvent
| stuff to handle the interaction with Make and native libraries,
| how we have generators of generators of Makefiles... Heck, even
| Docker's use case is mostly because of the living hell that is
| C stuff.
| teg4n_ wrote:
| I'm unconvinced. I don't see a reasonable benefit for learning
| yet another config syntax just to run some scripts.
| otsaloma wrote:
| That's specifically the gain here, you don't need to keep
| learning new build tools or language-specific tools. Make works
| for all languages, all kinds of projects, has been around since
| forever and is not going away. It's the only build tool you
| need to learn.
| pdimitar wrote:
| `just` does the same but better, is much quicker to learn
| (we're talking literal 5-10 minutes), and doesn't have
| decades of weird syntax baggage.
| honkycat wrote:
| My main problem with make: When you want to write sophisticated
| build processes, the syntax is bizarre and difficult to work
| with.
| zelphirkalt wrote:
| The creator of Make actually apologized for it, as far as I
| have read.
|
| I'm very happy with Make, though I have to agree, the syntax
| could be better. I don't mind using tabs, but why are spaces
| not OK as well? It would also be good to be able to not have to
| break long lines or multiline things with backslashes all the
| time. Yes you can set that oneshell thingy, but that is
| inconvenient in other ways, because it is for the whole file
| instead of a single command or a single target.
|
| So it could be better, definitely, but it does the job of doing
| DAGs well and it is available on most systems, so I don't have
| to add some huge tree of dependencies just to run tasks.
| mrweasel wrote:
| True, but having "sophisticated" build processes are a problem
| in their own right. I understand that there may be special
| cases, but generally, if you have troubles making a build
| process work with Make, then using a "better" tool is just
| paving over the underlying problem.
|
| Just today I was trying to help a friend build some tool with
| Bazel. While I'm sure there's a reason for Bazels existence,
| but it's just way to complex. The build failed and debugging
| the Bazel config was just a major hassle compared to had we
| just looked at the Java commands in a Makefile.
|
| Similar with Pythons setuptools, even though that is
| significantly easier with the new pyproject.toml. It's really
| powerful, but what all I wanted is basically to copy a bunch of
| files and add a bit of metadata.
| FatActor wrote:
| Not only that, but look at any advanced-age project that uses
| make. There are layers of includes, and defines and rules are
| smeared across multiple files.
|
| I think many modern web-build tools were made by people who
| thought "hey, I can do better than make" (or worse, "What's
| make?" and reinvented the wheel) and then wound up in a similar
| conundrum.
___________________________________________________________________
(page generated 2023-01-11 23:01 UTC)