Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

We used NextJS on a couple of projects where I work and are already phasing them out. The reasons are manifold, but a few key factors:

* difficult auth story. next-auth is limited in a few ways that drove us to use iron-session, such as not being able to use a dynamic identity provider domain (we have some gov clients who require us to use a special domain). This required us to basically own the whole openid flow, which is possible but definitely time we didn’t expect to have to spend in a supposedly mature framework.

* because the NextJS server wasn’t our primary API gateway we ended up having to proxy all requests through it just to add an access token to avoid exposing it on the client. The docs around this were not very clear, and this adds yet another hop with random gotchas like request timeout/max header size/etc.

* the framework is very aggressive about getting you on their cloud, and they make decisions accordingly. This was at odds with our goals.

* the maintainers aren’t particularly helpful. While on its own this would be easy to look past, there are other tools/frameworks we use in spite of their flaws because the maintainers are so accessible and helpful (shout out to Chillicream/HotChocolate!)



What did you move to? We've been using NextJS as a frontend with somehelpful server-side/api handling, but the backend is done in Django. We are basically just using ReactJS with the convenience of NextJS (like file based routing)


I like Remix a lot better for this use case than Next.js. Much simpler, easier to host on your own servers.

Astro is also really nice and easy to learn and host.


We have some other projects that are Angular, and NextJS was sort of a proof of concept for us. The goal is to just have one front-end framework for our devs to work with (and keep up to date, ugh!), so we’re folding those deploys back into our Angular family of features.


Have you checked out https://astro.build/ yet? You can drop in any framework where you need it, so if you need to bring along those Angular components you can but you can also lean on React if you need it.


No, and on a cursory look it doesn’t seem very aligned with our goals anyhow.


Not OP; but when I was thinking about using Next.JS, and doing a deep investigation, I came to the decision that, for server-side rendering, I'm quite happy to use Kotlin and Ktor (my backend is also Kotlin - I have a lot of client-types, which is why they're separate), and I've been quite happy with Ktor's html dsl + htmx for speed.

And Kotlin + Ktor feels very good to write in on serverside. Fast, easy and fluent to write in, like Ruby; but with Java's ecosystem, speed and types.


How are you doing reusable components with the html dsl? From the little bit I’ve tried ktor this was something I could not figure out and it kinda just pushed me away since I couldn’t find anything.


To build reusable components, I end up using a mix of a lot of extension functions and Kotlin's function pointer syntax.

So, the components themselves will look something like this:

    fun HtmlBlockTag.radioButtonWithLabel(
        groupName: String,
        id: String,
        hidden: Boolean = false,
        radioButtonFunc: (INPUT.() -> Unit)? = null,
        func: LABEL.() -> Unit
    ) {
        radioInput(name=groupName) {
            this.id = id
            this.hidden = hidden
            radioButtonFunc?.invoke(this)
        }
        label { this.htmlFor = id; func() }
    }
And then use of them will be like this:

  call.respondHtml {
      body {
          div(CSS_CLASS_NAME) {
              radioButtonWIthLabel(MORE_CSS_CLASS_NAME, "group", "id") {
                  +"Text for the label"
              }
          }
      }
  }
More complicated examples just extend that quite a lot.

I've also got whole files dedicated to single extension functions that end up being a whole section that I can place anywhere.

---

And then to test those single-function components, I'll do something like this:

  class SingleSectionTest {
      private suspend fun ApplicationTestBuilder.buildApplicationAndCall(
          data: DataUsedForSection
      ): Document {
            application {
                routing {
                    get("test") {
                        call.respondHtml {
                            body {
                                renderSingleSection(data)
                            }
                        }
                    }
                }
            }
    
            val response = client.get("test")
            val body = Jsoup.parse(response.bodyAsText())
    
            return body;
        }

      @Test
      fun `simple test case`() = testApplication {
          val data = DataUsedForSection("a", "b", "c")
          val body = buildApplicationAndCall(data)
          
          // all the asserts
      }
  }
And so on. Is this what you were wondering? Or would you like a different sort of example?


That's pretty much what I was looking for, thank you for sharing! I think that's probably the nicest way I've seen to do it, annoying that Kotlin seems to force you to add it as a child (? idk the word...) of an existing HTML tag, wish you could just import a component or something :(


Kotlin calls those "Extensions" [0], and yeah, they can be pretty annoying. I first learned about them in C# and I had a bunch of frustrations with them, especially when I found some code on StackOverflow or Microsoft's docs and they'd use one of those methods and it just plain wouldn't be there for me because I hadn't downloaded the right nuget package or anything.

I've gotten more used to them and I get why they can be so great now; but there's still some real annoyances with them I just can't shake (like the import problem and the related "where is this code?!" problem)

---

Purely importing a component that's just a simple class, like you can do in Java/Typescript with their jsx and tsx files would be pretty cool, yeah. You could fake it by making a data class and adding a

  fun renderInto(tag: HtmlBlockTag) { ... }
type method, but with how Ktor's Dsl is implemented, you're still going to need to connect it into the giant StringBuilder (or whatever) that the dsl is building to.

To help me get something close to that idea, I tend to dedicate whole files to bigger components and even name the file the same as the root HtmlBlockTag Extension method (like RadioButtonWithLabel.kt if I did it for the earlier one). Those files are great because you can put a bunch of helper methods in the same file and keep it all contained, a lot like a class.

[0] https://kotlinlang.org/docs/extensions.html




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: