Granted if you are talking frontend browser code then sure webpack, but that tool has been around and stable for many years now.
Added bonus too is browser adoption is way better than ever so you don't really need a transpile either, typescript being the exception.
Nah, Gradle is a fucking mess no matter what. If you don't absolutely understand the gradle life cycle, how to avoid task configuration, keeping everything lazy, avoid cross configuration, understand that buildSrc is shit, gradle will be hell.
Gradle feels to me like trying to set up a webpack project. Loads of magic configuration no one dares to touch after it happens to somewhat work correctly.
The only problem I find is the API updates between major versions. Still, I’m never going back to Maven. Love Gradle.
Building embedded server apps, many sub projects, single Java/Kotlin codebase.
Once you apply that same strategy to Maven, it actually tends to beat Gradle in performance too. See Maven Daemon: https://github.com/apache/maven-mvnd
Mvnd seems somewhat recent compared to Gradle’s daemon feature. Are there any measurements that confirm this statement? I don’t find any in the repo?
But I do agree that the dsl is quite cryptic.
I'd take that build system over Java's dog slow build systems any day. Just a shame about the JS ecosystem itself. Too many badly written libraries not written in Typescript (inexcusable these days) with a gazillion dependencies.
Java literally compiles as fast as it gets, while npm chews through the same files multiple passes, and goddamn barely does anything yet takes eons of time.
Loving FP and admiring `fp-ts`'s work, I can't help but think our communities would be better off doing FP in FP languages instead of writing unergonomic and idiomatic code to much of the splintered TypeScript community. Yet, we'll writing things this way because it feels like the correct way to do software, meanwhile a bootcamper would find it incomprehensible; this same person would find an FP language more approachable because there's only one way to code it.
At its core, gradle as a task runner is pretty neat. But the layers of abstraction built upon it often make things superhard when you need to deviate from the setup offered by the starters.
While the official docs have started to show examples in both, almost always a stackoverflow answer or online blog post you find while googling is in the other dsl and converting between them is non-trivial.
Gradle certainly isn't great but it's crappiness is overblown especially when comparing it to stuff like npm + webpack.
[1] https://kotlinlang.org/docs/maven.html#attributes-specific-t...
If you go the gradle route, of course use the Kotlin Script variety. Gradle is a bit complex and having your build logic written in Kotlin seems like it is the right thing to do.
Yes, in the abstract it does, but the but way Gradle actually does that (evaluating different parts of the program in different special and magical ways) is extremely confusing. And I don't understand how it could possible require the vast amounts of memory it does.
Maven is horrifically verbose, but at least its model makes sense after learning a few key concepts and the IDE can help you work with that model without setting fire to the CPU.
I have plenty of experience with maven and with ant before that. No project I've touched in the last six years used either of those other than a few conservative and, frankly, clueless/hopeless customers that I've helped out in some of my freelancing projects.
I don't get pedantic about persuading customers that maven is dead as a door nail but there is a pattern of behavior of mostly elderly (i.e. my age) slightly out of their depth CTOs insisting that maven is the way to do things because that's all they know.
I'm experienced enough to not fix what ain't broken. A build system either works or it doesn't. And it's not worth my hourly rate arguing against it. Anyway, it's not that hard to get them working regardless of what you use. I'm old enough to remember DOS batch files being an acceptable solution. Actually wasn't that hard to do either. I love bash shell scripts for the same reason.
People get hung up on build systems performing magic that they don't understand. Maven is mostly just a really convoluted way to compile Java code which isn't even all that hard when you understand what it does. Having done that with batch files I both appreciate what maven. gradle, etc. do and recognize that it doesn't matter much at all. Gradle does most of the same things as maven with less fuss. I'm still well capable doing the same with just bash and a compiler. But it's not worth my time. These days, I spend more time on figuring out github actions than on gradle. The stuff that gradle does is only a tiny part of the business of doing CI/CD these days. Gradle is the easy part.
And then to upgrade to the latest I had to manually go figure out what the latest was, and manually change the line number to the latest version. I did see there's a separate plugin you can install to now add it though, built by a third party, but still.
Decades.
But this:
> And then to upgrade to the latest I had to manually go figure out what the latest was
Yeah, in the java world you write code against specific known dependency versions. That's why when you try to build it again in a couple months, it still works. I sure wish the JS community would learn this old trick.
I wish the Java community (which I'm actually also a part of) would stop rejecting everything that's not "the Java/enterprise way" and be humbled by exploring better alternatives, or alternatives with different tradeoffs for once.
It's also a common practice to use npm ci in all build scripts to never update packages even if they declared a version range in package.json, and package.lock not being able to satisfy package.json won't cause lock to get overwritten.
[0] Yes, that's right. npm doesn't allow to to install incrementally respecting the lockfile. You can install incrementally with npm i and roll the dice, or install from scratch with npm ci to respect the lockfile. Basically the npm authors took the rm -rf node_modules/ workaround and productized it.
If you run npm i against that package.json and package-lock.json, the latter will never be updated, even if the package.json would be happy with newer versions.
If you manually edit your package.json to have different ranges and run npm i and those ranges aren't compatible with your package-lock.json then the latter will be updated with version that are compatible with your package.json. Further runs of npm i will be as with 2 above.
But of course you may think this behavior is a joke, I do not.
How? Why? What's your use-case?
1) For local development, I’m seeking a command I can use after pulling, to safely and quickly install any needed dependencies that have been added by others. Currently I use npm ci but it’s absurdly overkill (and therefore very slow).
2) For CI itself. I cache node_modules/ across builds, which significantly speeds up my builds. Currently I npm i, and check if lockfile changed, and if it did, checkout lockfile and npm ci.
I shouldn’t need to npm ci ever unless my node_modules/ became corrupt for some reason. Because npm ci ALWAYS blows away node_modules/, it’s not a reasonable piece of everyday functionality, it’s just a semantically ambiguous way to rm -rf node_modules/ && npm i -—respect-lockfile (made up flag I wish existed). The obvious explanation is that the npm developers couldn’t figure out how to reliably reconcile node_modules/ with the lockfile, so just gave up and shipped npm ci.
Or if the rm -rf node_modules/ isn’t strictly necessary for npm ci, then give me npm ci —-skip-drop-node-modules, that would be equivalent and fine for my purposes.
btw ci is super fast (caching) unless you have one of those modules that download the whole effing chromium after install (brain dead behavior).
What do you mean ci is super fast? Is it intended to be caching the packages somewhere other than node_modules?
There's been some bugs in the implementation but never had anything in the last few years, other than some people accidentally committing unapplied package.json changes, and built a precommit hook and a server-side check for that in many projects.
> What do you mean ci is super fast? Is it intended to be caching the packages somewhere other than node_modules?
Yes: https://docs.npmjs.com/cli/v6/commands/npm-cache#configurati... . If you want a more Java-like (to be more accurate, artifactory-like) experience, you can also opt-in for Verdaccio: https://verdaccio.org/ You can also use the artifactory itself: https://www.jfrog.com/confluence/display/RTF/Npm+Registry
I had more success with verdaccio though.
Quality of the packages has been discussed to death, say about that anything you like, but npm has been rock-solid for me in the last few years. Definitely not a joke IMHO.
I've been writing JS with npm locked to specific, exact versions of dependencies since 2014, IIRC.
Not everyone does this, obviously, but the tooling has been able to at least do a decent approximation of this for a long time (and I was and am very far from being a bleeding-edge adopter).
Pray tell me where the dependency comes from then? When I add a ‘This package requires dependency x at version y’ to my gradle/maven file, it doesn’t magically appear on my system.
Or rather, I think it does magically appear on my system, which is incredibly confusing.
Should it display ads instead and put random executables to my path? Or create a 1000000 file directory everywhere on which windows god damn chokes to open?
If you enable the general maven repository (the maven() you see at the top of many gradle build scripts), you'll get the code from maven. If you also add your personal repositories (which most people probably don't have), you'll get packages from there as well. I'm not sure how you add a second repository to node package managers, but I assume it's possible in some way without specifying the http download url.
The biggest difference between the two ways of package management in my opinion is that node packages are just a word or two and Java packages are a full com.example.product.service.package name. That's a lot better in my opinion as it distinguishes between projects much more easily. I thought node-ipc was related to the nodejs project, for example. Some nodejs packages use namespaces, but most don't.
Another difference is that nodejs has tons of tiny packages (I'll never get over how silly it is that is-odd and is-even appeared in my node folder by transitive dependencies) whereas the Java world generally uses huge packages almost exclusively. This leads to more boilerplate code (actually having to write simple functions like that yourself), but also to less dependencies that can break.
Once you do that in Node, the package lock will specify what version you've downloaded, to make it a repeatable build. You can tweak it to indicate you want to pin the version at a given levels, as well; that's done in one place, and separately from the package-lock file that gets generated, that tells you what -actually- is being used.
My follow up point is that when that version eventually goes stale, it's as simple as 'npm outdated' to determine if there's something more recent, and 'npm update' to update everything (based on whether you've pinned to a major/minor in your dependency list). You can also update specific packages with 'npm update (package name)'. I sure wish the Java community would learn this obvious 'trick' that every OS package manager enables. I know I want Jackson, say, I should be able to say "gradle install jackson" or whatever, and it would tell me all the options in the repo with jackson in the name. Then 'gradle install jackson com.fasterxml.jackson.core' and it would add that to my gradle file, with the most recent stable version. And 'gradle update jackson' would seek to update that dependency to the latest stable (with some syntax to pin the release, major, and maybe the full version, to enable 'gradle update' to update everything within a particularly defined scope).
1.1) Gradle is a build system. As such it doesn't care where you are getting your dependencies. You can skip all public package repositories and only use your own private one or mix and match. Adding repositories is literally as easy as doing the following to your build.gradle file:
buildscript { repositories { google() mavenCentral() maven("your private repo url") }
1.2) As has been mentioned in previous comments, you add dependencies to the project rather than install them in the system. Gradle then has various cache folders where these dependencies recide and will fetch those that it doesn't find locally (new libraries, new versions etc). This is akin to how most software defines its dependencies. Python's pip & requirements.txt, Flutter's pupspec.yaml etc.
1.3) Complaining about having to use a full resource identifier ('com.google.guava:guava:31.1-jre') for the dependency rather than just an alias ('guava:31.1-jre') for the package name simply sounds like complaining for the sake of it. What if a fork exists of guava ('my.forks:guava:31.1-jre'), how would that get used along side the original if dependencies are only defined by their project name?
2.1) In my books, package updating should be methodical processes where each and every update is made in isolation, thoroughly tested and then merged in. In that respect I find it very nice that the build system isn't constantly telling me about a new library version everytime it runs, as it pushes naive developers to upping all libraries to their latest versions immediatly and then scratch their heads when unexpected behaviour starts popping up all over the place.
2.2) Various IDE's have mechanisms for notifying visually about when a package has a new version available to them. There are also various tools available to check for package version statuses, such as the 'Gradle Version Plugin' just to name one. I use this plugin extensively to get information on stable dependency updates.
2.3) If you want to always use the latest version of a dependency, you have various mechanisms available to you. It is easy to declare if you want to always go for the latest major, minor og patch versions automatically. See 'https://docs.gradle.org/current/userguide/single_versions.ht...' for details. I'd hate to work an a project that had not clear version definition though as that would just signal very naive developers and/or sloppy practices (automatically going for latest patch versions is fine in my books).
Gradle however, is a dsl in a language almost no java devs use. All gradle files are different, so copying an example from somewhere else probably won't work in your context etc.
Gradle with Groovy sometimes gets kinda hard to comprehend
Gradle with Kotlin is entirely different experience, largely due to proper typing.