Ink: React for interactive CLI apps

(github.com)

164 points | by brianzelip 5 days ago ago

108 comments

  • seveibar 5 days ago

    Ink is great for CLI tools and enables really great tools. People who are saying React only belongs on DOM are missing out- React is the world's most popular and powerful declarative programming paradigm. It's being used for native apps, VR, 3d, CAD and electronics.

    React allows you to mix declarative and imperative programming concepts together in an effective way. To give a sense of why this is important: Imagine a CLI built with XML. It'd probably be pretty verbose and have a lot of domain-specific configuration. There also wouldn't be a great typechecker. React combines the most robust type-system in the world (Typescript) with declarative style. It has issues, but being "built for DOM/web" is not one of them.

    RE: Ink. A simple example of where it is better than most tools is you can simply import a re-usable "ranger-style" file browsing component, and adapt it for things like exploring a database, a spreadsheet, or an API spec. The potential is very high. Hats off to the author and contributors!!

    • dragonwriter 5 days ago

      > React allows you to mix declarative and imperative programming concepts together in an effective way. To give a sense of why this is important: Imagine a CLI built with XML.

      Talk about a late-night-infomercial-level “let’s compare the thing we are talking up with the absolute worst alternative imaginable as if that was the next best choice” argument.

      • seveibar 5 days ago

        Sorry, my point was to illustrate that XML is verbose so data-representation isn't a good fit. Most languages implement some kind of language-specific builder-pattern for CLIs, which in some sense is "re-inventing" a declarative programming paradigm for the domain-specific task. Could have done better w/ the example!

        • kristopolous 5 days ago

          XML is a much maligned and poorly understood technology. It lacks glossy pitch pages and hypemen like react.

          Things like XSLT are really quite good if you can get past "ew xml icky"

          You can inline different schemas in modular, bazaar like ways from a variety of sources and pull in different parsers that do different tasks.

          For instance you could have, say an object subtype and pretend you, a spreadsheet developer made something compatible with it.

          As the tool parsers the XML, it sees the spreadsheet, which it has never encountered however, the schema tells it where to get the parser so it dynamically loads it, passes off the subtree it doesn't recognize and lets your spreadsheet parser do its things.

          It's remarkably clean and elegant clockwork for distributed modular applications.

          Things like a mobile phones share feature would be a perfect use case: a wide variety of objects from different applications passing through the same schema with a share directive invoked that allows you to share in a variety of ways. XML can handle this quite magically.

          I've built systems like this with XML, it just works. I was like "damn. XML... Who would have thought"

          People just never learned XMLs killer features because it got a bad reputation as being the thing that out of touch enterprise Java bozos make messes with - which is true.

          But that's also why JavaScript was shat on for 15 years. You gotta be adult enough to look past that. Try to separate the merits of a technology from your perceptive competency of its users.

          • treflop 5 days ago

            We’re not talking about XML as a data transport format.

            As a way to ultimately render a view, it has never been elegant.

            I’ve done it every possible way:

            - Templating libraries

            - XHTML with embedded XML data

            - XML and XLST

            - XML embedded in JavaScript (EMCAScript), aka React before React existed

            - React, which is similar EMCAScript

            I used the first public releases of React. I was immediately sold. No one had to sell anything to me. I knew it was going to win.

            I can’t imagine anyone with strong experience in all these ways possibly think that these other ways are more enjoyable.

            p.s. I’m not talking about Redux. I was never sold on Redux/Flux.

          • mbreese 5 days ago

            In general, I liked XML. But the entire system seemed fragile. Parsing and validation were great. It was a great system for ensuring your data matched the schema. But if it didn’t, it seems like it never failed gracefully. As in, you’d be unable to even open your spreadsheet document if some random web server was down. Or if you were on a plane.

            Just a few of the things I didn’t like about it. But when the system worked, it was quite capable.

          • dragonwriter 5 days ago

            > XML is a much maligned and poorly understood technology. It lacks glossy pitch pages and hypemen like react.

            The negative feelings about XML are not due to the lack of glossy pitch pages and hypemen pushing XML and XML-based technologies; they developed whole XML had those far more than React ever has.

            Some people may be too young to remember that, but...

            • kristopolous 5 days ago

              I'm too old to forget it. It was the wrong kind.

              They were the kinds with a bunch of worthless certifications who go everywhere in suits. I expected nothing but expensive clunky broken complicated bullshit from them. And that's exactly what they gave you when they pitched XML so I ignored it for over a decade as some tedious wasteful time-consuming thing that dumb people use to rake in hourly contract dollars.

              But then, maybe 15 years ago or so, I started hitting use-cases that it was designed for and everything changed.

          • seveibar 5 days ago

            XML is insanely powerful, there are 1,000 page books on XML alone. But React is a much smaller standard that extends XML to an insanely effective point (assuming basic JS as base knowledge) It's because I like XML that I think JSX is a logical/effective extension and we should support it as the sort of "champion" of declarative design

            Just to emphasize this: Why has XML been losing as the standard config format? Why did JSON win on web APIs? It's not because JSON is better, but because it's simpler and very-javascript-compatible.

            If you like XML, there is a strong argument to support JSX because it's a way to keep XML around!

            • kristopolous 5 days ago

              XML continues to be a poor and inappropriate choice for simple stand-alone things.

              In APIs you're talking to 1 server, calling 1 function, that returns 1 kind of thing at 1ce.

              XML starts becoming useful when you increment those numbers - any of them.

              People (including me) have been trained not to think in those ways. The web still isn't a web - it's merely a collection of computers with individual relationships.

              The 90s internet had fleeting attempts at other paradigms. We should probably put serious effort into a second bite at that apple since by every measure our technology is at least 1000x better in the same way we've revisited neural networks

            • lelanthran 5 days ago

              > Why has XML been losing as the standard config format?

              The short answer, as you answered it, is:

              > there are 1,000 page books on XML alone.

              The long answer: it was over-engineered for the intended use-case.

              It's easier to fix under-engineered stuff (like JSON) than to fix over-engineered stuff (like XML).

              > If you like XML, there is a strong argument to support JSX because it's a way to keep XML around!

              Well, this is basically pivoting XML to a different use-case. It'll still be over-engineered unless you stick to JSX only, in which case it's not XML anymore, anyway.

            • croes 5 days ago

              React isn’t a standard

    • cupofjoakim 5 days ago

      > the most robust type-system in the world (Typescript)

      This is very high praise for something that only provides safety at compile time and not runtime.

      • oorza 5 days ago

        Sure, but ten years ago, if I told you the concept of a "bottom type" would be common knowledge with web developers or they'd consider type algebra second nature, you'd have laughed at me. If I were to tell you they pushed a Turing complete type system into the mainstream and then abused its computational power to do things like create value types, you'd ask me where I was buying my LSD.

        TS might not be the most robust type system in the world with no qualifiers. And it might not even try to be sound. And it might disappear at compile time. But none of that changes the fact that it took a bunch of concepts that only programming language dorks knew or cared about and turned them into every day utilities that the junior most developers use. And it doesn't change the fact that it is the only mainstream programming language with a fully Turing complete type system.

        Give credit where it's due. I say all of this as one of the aforementioned programming language dorks who took a really long time to get on board with TS, as I thought Flow's focus on purity made it a better choice.

        • dragonwriter 5 days ago

          > Sure, but ten years ago, if I told you the concept of a “bottom type” would be common knowledge with web developers or they’d consider type algebra second nature, you’d have laughed at me.

          If you told me that was the case today with web developers generally, I’d laugh at you even harder than I would have if you made that prediction ten years ago.

          • oorza 5 days ago

            All the web developers I've worked with in the last four years understand the concept of a bottom type, even if they've never been introduced to the formal phrase, because `never` is the explicit bottom type in TS and appears all the time. You can't go very long consuming libraries written in TS before you run into it, at which point you become familiar with it.

            Similarly, a function that accepts (explicitly) `A | B | (C & D)` and then dispatches to functions that accept `A | (C&D)` vs `B` is, you guessed it, type algebra and is a common pattern in hot paths through every TS codebase.

            Just because the formal nomenclature is unknown does not mean the concepts are unfamiliar.

            • hu3 4 days ago

              > All the web developers I've worked with in the last four years understand the concept of a bottom type.

              It's the opposite in my experience. Most web developers I work with (a lot because of consulting), specially the average "React sprint runner" doesn't have a clue about anything slightly above basic types and just google/chatgpt whenever things break so they can move on to the next task in the sprint.

              cryptic typescript errors don't help here either.

            • yencabulator 4 days ago

              Meanwhile what I see is that everyone seems to think the {} type in Typescript means an empty object. Just because something has expressive power doesn't mean it's good.

        • bryanrasmussen 5 days ago

          OK, that's all well and good but I notice you still haven't told me where you're buying your LSD?

      • angra_mainyu 5 days ago

        Not to mention:

              type Thing = string | boolean;
        
              const arr: string[] = [];
        
              function add(item: Thing, dst: Thing[]): void {
                dst.push(item);
              }
        
              add(false, arr);
        
        
        Is valid typescript.
        • adamscybot 5 days ago

          If you are used to structural typed systems though this actually "feels" expected. Don't get me wrong, I know where you are coming from. But the realisation comes from nominal systems, which are different beasts. As long as it actually evaluates to the expectations in the head of the developers using it, then that's okay.

          However, regularly it's not the case -- especially with people moving from nominal systems.

          TS can't really be practically nominal when it has to be constrained by its compile target. So I guess it ultimately boils down to an anomaly/criticism born from the legacy of how web standards came about.

          • consteval 5 days ago

            Nominal type systems are pretty much better across the board IMO. Much safer and much less to keep in your head. Modern langs like Rust or F# have very complete and nice to use type systems.

            But yeah unfortunately not sure if JS is an appropriate target for these type systems. Nim does it, but I'm not sure how safe it is.

            • adamscybot 5 days ago

              One language that comes to mind is ReasonML. It doesn't have runtime checking. It's structural and compile time, but the guarantees are supposedly cast iron. https://reasonml-old.github.io/guide/language/type#design-de...

                  type thing = 
                    | String(string)
                    | Bool(bool);
              
                  let arr: list(thing) = [];
              
                  let add = (item: thing, dst: list(thing)): list(thing) => {
                    switch (item) {
                    | String(s) => dst @ [String(s)] 
                    | Bool(b) => dst @ [Bool(b)]    
                    };
                  };
              
                  let newList = add(String("asd"), arr);
              
              
              This doesn't work, since the dst array has to be one that can contain both string and bool in the first place.
        • Capricorn2481 4 days ago

          To me this is expected? Thing is supposed to be one or the other. If I wanted a homogeneous array I would use a generic <T> for the add function, which makes more sense for a function that just pushes to an array anyway.

          • trenchgun 4 days ago

            arr was defined to be an array of strings. How are you pushing a boolean there?

            • Capricorn2481 3 days ago

              Because you've given the function no information on whether those two "things" are related. You're saying when it gets passed into that function it can be treated as either with type widening.

              I understand it may be unwanted at first glance, but this is a contrived example for demo purposes. You wouldn't really make an "add to array" function like this so specifically. You would use generics, which would solve the exact issue that is posed.

                  function add<T>(item: T, dst: T[]): void {
                      dst.push(item);
                    }
              
              Now you can work with any array, and it will only add items with the right type.

              If you really need it to be just <Thing>, you can do this

                  function add<T extends Thing>(item: T, dst: T[]): void {
                      dst.push(item);
                  }
              
              Now it knows that Item and DST are related but need to be Thing.

              There's not a lot of languages with unions that handle this differently. F# discriminated unions make you specify which type you're using every time. For example, this doesn't even compile.

                  type Thing =
                      | A of int
                      | B of bool
                  let arr: Thing list = [1]  // Not an A or B type!
      • emoII 5 days ago

        Is there a type-system that provides runtime safety? I thought type-erasure was common practice

        • daotoad 5 days ago

          Raku has a really weird but cool type system[1] that does both compile time and runtime checks.

          Because some checks are expected to be runtime only, it lets you specify types like "Odd integers" by writing a `where` clause.

          ``` subset OddInteger of Int where !(* %% 2) ```

          You can use multiple dispatch to separate dispatch from processing: ``` subset Fizz where * %% 3 subset Buzz where * %% 5 subset FizzBuzz where * %% 15

            multi sub fizzbuzz(FizzBuzz $) { 'FizzBuzz' }
            multi sub fizzbuzz(Buzz $) { 'Buzz' }
            multi sub fizzbuzz(Fizz $) { 'Fizz' }
            multi sub fizzbuzz(Int $number) { $number }
            (1 .. 100)».&fizzbuzz.say;
          ```

          Or even use inline anonymous subsets when you declare your functions: ``` multi sub fizzbuzz(Int $ where * %% 15) { 'FizzBuzz' } multi sub fizzbuzz(Int $ where * %% 5) { 'Buzz' } multi sub fizzbuzz(Int $ where * %% 3) { 'Fizz' } multi sub fizzbuzz(Int $number ) { $number } (1 .. 100)».&fizzbuzz.say; ```

          Raku's type system is one of its features that will show you new ways of thinking about code. I advocate playing with Raku specifically for mind expansion because it has so many interesting ideas built in.

          [1] https://docs.raku.org/language/typesystem

      • seveibar 5 days ago

        Runtime safety is slower than compile type safety. Runtime safety SHOULD be opt-in if there's a performance penalty!

        For runtime safety, there are lots of frameworks that follow TS's standard, one of the best is called "zod" which allows runtime safety and complex types are inferred.

      • EddieRingle 5 days ago

        They're building a product that revolves around React and Typescript and include an email specifically for receiving investors, so it's reasonable that they'd talk up both technologies.

      • phpnode 5 days ago

        Out of all the type systems which provide safety at both compile time and run time, which are your favourites?

      • shepherdjerred 4 days ago

        Can you name a common language with runtime type safety?

        Anyway, you can get this with Zod https://zod.dev/

    • hajile 5 days ago

      Some people here seem to have a hard time understanding that React !== DOM

      React is descriptive. It creates a virtual tree and tells how that tree should be changed.

      What that tree renders into is a completely different problem. On the web, it renders into HTML. On your phone (ReactNative), it renders into native GUI. In ink, it uses a render engine to concat and output the text results (it's a little more complex than that as it uses Yoga[0] today).

      [0] https://www.yogalayout.dev/

      • rkagerer 5 days ago

        Is there a good resource that explains what React is and how it works, without limiting the focus to just the usual web applications?

        • hajile 5 days ago

          It's a bit older (and focused on web), but you can try this

          https://github.com/pomber/didact

          At a high level though, you create a tree of nested objects. Each has a handful of special properties (children which contains an array of child objects being the most interesting to users). The rest of the properties are used to interface with the rendering engine by passing it configuration and (usually) event functions it can call when something happens.

          That tree of objects gets passed to the rendering engine which turns the tree into some kind of output (DOM, Canvas, WebGL, Ink, etc)[0].

          When something happens (an external event, a timer, event from the render engine, etc), your code potentially changes the object tree. React then walks that tree and uses a few shortcuts to quickly detect what has changed. Instead of re-rendering everything, it can give a list of things that have changed and what the new values are. The render engine then decides how to make those changes happen and the cycle repeats.

          It's really pretty simple.

          [0] https://github.com/chentsulin/awesome-react-renderer

        • acemarke 5 days ago

          In addition to the excellent "Didact" article that explains how to _build_ React and its internals, I have an extensive "Guide to React Rendering Behavior" post that explains the user-visible behavior and mental model of rendering:

          - https://blog.isquaredsoftware.com/2020/05/blogged-answers-a-...

          I can also recommend Dan Abramov's post "React as a UI Runtime":

          - https://overreacted.io/react-as-a-ui-runtime/

          and then of course the actual React docs for learning how to _use_ React:

          - https://react.dev/learn

        • branislav 5 days ago

          One way to look at React is as an open loop desired state system, where you have a declarative way (js/jsx) of describing what you want to render and the reconciler figures out what operations to do (in the DOM), ideally in an effective way. But you could swap out the render target to other things. I wrote about it some time ago https://branislavjenco.github.io/desired-state-systems/

      • seveibar 5 days ago

        I love Yoga (flexbox++ engine built by Meta), and yes most people don't understand that React is simply not coupled to the DOM!

    • ryukoposting 5 days ago

      > React combines the most robust type-system in the world (Typescript)

      By what measure?

      Your comment reads like you have something to sell me.

      • consteval 5 days ago

        Right. It's a structural type system that automagically puns things at runtime. The "most robust type system", I would think, would be something like Haskell.

    • result2vino 5 days ago

      I’m sitting here waiting for you to close the sale on me. Who said anything about XML as the alternative!?

    • com2kid 5 days ago

      > To give a sense of why this is important: Imagine a CLI built with XML.

      If I'm not mistaken, JSX is a type of XML blended with JS code.

      • sureIy 5 days ago

        It's definitely XML/HTML inspired, but not a type of XML since it uses prop={value}

    • bilater 5 days ago

      " People who are saying React only belongs on DOM are missing out"

      yup - two of my favorite React packages are Remotion and React Email.

    • pjmlp 4 days ago

      Many of us only use React, because we are given no other choice on extension SDKs for SaaS products, which naturally wrongly contributes to its "popularity".

    • wyager 5 days ago

      > the most robust type-system in the world (Typescript)

      The rare combo of Blub Paradox + Poe's Law

      • mardifoufs 5 days ago

        What would you consider to be more robust, while still being usable? I'm referring to the type system here specifically.

        • wyager 4 days ago

          Haskell, any ML, Rust, etc. TS is on par with any crufty ad-hoc type system like that of Java or C++.

          The TS type system is neither especially powerful nor especially robust

        • timeon 5 days ago

          Anything with proper algebraic data types.

        • FridgeSeal 5 days ago

          Rudy, Haskell, Ocaml are obvious examples.

          • mardifoufs 5 days ago

            Agreed. I just think that those are (sadly, as I like OCaml) apparently not very practical, at least not according to most people. As far as "widely used languages" (which is a totally subjective concept I realize that!), TypeScript has a pretty solid type system. One of the most robust that is widely used.

    • timeon 5 days ago

      > most robust type-system in the world (Typescript)

      Are you serious?

  • oscb 5 days ago

    I like Ink as an idea for how to use React creatively. It’s very well done. At the same I think most CLIs do not need this kind of interaction. It is better to keep them simple and verbose rather than fancy and obscured. I spent a long time removing Ink from an enterprise tool where it didn’t fit as it was meant more for CI/CD. Not this tools fault of course.

    • hinkley 5 days ago

      Half the tools I write end up being used in CI/CD so even if I do fancy in a terminal you have to do simple for non interactive shells.

  • d4mi3n 5 days ago

    I don’t get all the hate. Sure, JS isn’t the most popular language for TUI apps, but there’s always room for more TUI tools and I’d you’re automating things for your JS project this is a pretty natural fit to make your project scripts friendlier to their users.

    I think I’d much rather have more nice TUIs than not, regardless of the language they’re written in.

  • itronitron 5 days ago

    I'm curious how developers that use React, but have never written an application using the MVC paradigm, would describe React.

    • cyberax 5 days ago

      React is nice, but it has some sharp edges.

      Basically, you're logically re-rendering _everything_ on every render. The React engine then diffs it with the last state, and then applies necessary actions to reconcile them. As a consequence, your rendering code is invoked by React, and you have to follow some rules to make sure that React doesn't have to _physically_ re-render everything.

      Another consequence is that physical component creation is taken out of your hands.

      This works great, if you're doing something with tons of simple components.

      It works less great if the actual rendering is a complicated task. E.g. you're making a map widget, or a 3D editor. You might be better off not using the reactive approach, and fall back onto the classic MVC.

    • klysm 5 days ago

      I’ve used both. MVC is too limiting

  • bcherny 5 days ago

    Ink is awesome, but it does have some rough edges. For example, want to absolutely position something on screen? Not possible. The UI also tends to flicker when you’re doing anything complicated, in a way that can be hard to debug.

    • yesthisiswes 5 days ago

      This! I hit both of these issues. I tried building a solitaire game using ink. I couldn’t stack and offset the cards on top one another so they took up a lot of screen real estate. Then when I had re-renders the screen would flicker. Other than that it was a joy to use. I think I even tried flipping the solitaire board horizontal but that felt too weird.

  • adamscybot 5 days ago

    Odd to see this come up. I used it about 6 years ago to produce a CLI for devs. It worked very well and React concepts map cleanly to pretty much any "UI" target as said targets can also be well represented by declarative & composable trees.

    Probably, other Ui frameworks could also map, seeing as the declarative/composable tree pattern is ubiquitous now. So it's important to note it's that pattern which enables this, and not a specific framework.

    But React is one of the ones that is also more removed from the web target than others.

  • seanw444 5 days ago

    Saving the world, one GitHub project README banner at a time.

    I don't know how I feel about writing CLIs in JS. Just seems a little bit janky to me, and I don't know why. I wonder if there's any push to have something JSXish in Go, even if it requires a pre-compiler to achieve the syntax, just for CLI apps like this. Then again, maybe I'd just rather stick with something like Nim where you can just have a first-class DSL through the macro system.

    • bartekpacia 4 days ago

      > Saving the world, one GitHub project README banner at a time.

      I can feel snarkiness in this response. I don't like it.

      From Ink's author [0] post:

      > The time has come though to move on from Ink. Since russia’s full-scale invasion of Ukraine in 2022, everything in my life revolves around the war. And anything else has lost all meaning to me. I no longer have the mental and physical capacity to maintain Ink and give it the attention it deserves.

      [0]: https://vadimdemedes.com/posts/moving-on-from-ink

    • russellendicott 5 days ago

      This is my side hobby, a server side TUI protocol with a light browser like client that can navigate any TUI.

      http://uggly.bytester.net

      The primitives are good enough to build anything you want. Right now I'm trying to figure out how to make better libs and tooling for creators (mainly myself) so I can crank out lots of examples apps that showcase the power of TUIs where you don't need a dedicated executable for each one.

    • captnasia 5 days ago

      there's a few attempts, templ[0], gomponents[1]. Not for cli apps per se but for web dev.

      0: https://github.com/a-h/templ 1: https://github.com/maragudk/gomponents

      • seanw444 5 days ago

        I've seen gomponents, but it seems very verbose. Although I guess that's what you're stuck with if you're doing it within Go.

    • kaba0 5 days ago

      I don't know, go has lackluster expressivity, and these pre-compile tools always feel like a hack in its case.

      • ipsum2 5 days ago

        I don't think its a Go-specific issue, its useful syntactic sugar. I would love an updated JSX for Python.

  • ProfessorZoom 5 days ago

    a cli that has a useEffect is so cursed

  • insane_dreamer 5 days ago

    Nice accomplishment! However, React seems overly complex for a TUI, unless you already work with React in the browser and love JS?

    • klysm 5 days ago

      Obviously that depends on the complexity of the TUI. React is the best tool I’ve used to build UIs out of all the tools I’ve ever tried. I don’t love JS at all.

  • cupofjoakim 5 days ago

    I get that there's a lot of people only comfortable in the js-landscape, but I still think this is a weird tool for the job. If performance is a concern there's no way node is the right thing to start, and react just seems silly to me here. Should be noted that I do a big portion of my day to day work in react - no hate on the framework.

    • johnfn 5 days ago

      How would performance be a concern for rendering the UI of a terminal app? Surely that happens in less than 0.001% of all cases. And of course no one in their right mind is implementing the core functionality of their app with react state variables. (Right..?)

      • CGamesPlay 5 days ago

        Haven’t used this library, but the answer is the same as it is for real React apps. How does this application perform if I have a scrollable view with 50,000 items in it and I press the down arrow? This kind of thing is why React can be the cause of bad performance.

        • johnfn 5 days ago

          How many terminal apps do you know of that have 50,000 items with a scroll wheel? This is what I meant by 0.001%.

          • CGamesPlay 10 hours ago

            Any viewer of data that has 50,000 elements in it has this many items with a scroll wheel. It doesn't matter if it's on the screen at the same time, this is the kind of thing that the UI is supposed to be abstracting away from you; you just describe the UI and the renderer makes it appear on the screen. Example apps (not built with Ink, just some that fit into this category): less, https://fx.wtf, sqlite...

            And this is why React apps end up with bad performance by default. Doesn't crop up in simple tests and light usage, but the bad scaling will catch up with you when you deploy to production.

          • yencabulator 4 days ago

            Since when is the basic pager an exotic terminal app?

            • johnfn 3 days ago

              A pager doesn’t show 50,000 items at the same time - at least not the ones I use…

              • yencabulator 3 days ago

                I don't see anything in grandparent implying in view at the same time, and that sounds pretty unlikely.

        • mrbombastic 5 days ago

          What kind of TUI are you making that requires a scrollable view of 50k items?

          • mike_hearn 4 days ago

            Any log viewer.

            • mrbombastic 3 days ago

              Fair example, I haven’t built a log viewer but this might be the wrong choice, or maybe there are escape hatches.

    • coffeemug 5 days ago

      Node/V8 is insanely fast. I never quite realized exactly how fast until I worked on this: https://www.spakhm.com/ts-wolfram-bench. It's mindblowing how fast it is.

      • wyager 5 days ago

        I don't find "performance parity with Mathematica" to be very compelling. Mathematica is a CAS system, not something I would use to write fast code.

        • coffeemug 5 days ago

          It's not that V8 has performance parity with Mathematica. The Mathematica interpreter is written in highly optimized C by experts over many years. My barely optimized js/V8 code has performance parity to _that C code_. That's what should blow your mind.

    • Etheryte 5 days ago

      For most apps, CLI or not, performance is not really a concern so long as it's good enough. Obsessing over performance before your program does The Thing is a great way to never actually get around to doing the useful bits. Now don't get me wrong, I'm not saying performance doesn't matter at all, but premature optimization and all its friends apply.

      • nicce 5 days ago

        However, before you build the Thing, you should note that the architecture itself does not make impossible to improve the performance later on, if there is a possibility that it can make The Thing much better in the end.

    • adamscybot 5 days ago

      The "should we use node for the core business logic for my use case" thing is absolutely valid and depends.

      But you'd be surprised about the "react for the front end of the CLI" part. I used this thing a whole six years ago in a complex interactive CLI and it came off great to use, maintainable and ergonomic. React is just one framework that proscribes to the "UI as declaritive/composable trees" pattern. And that UI doesn't have to be web based. That pattern works for all UI's I've come across.

      Its the pattern that is a good reason to do this. And not react/js landscape. That part is probably a bonus for many though.

    • slashdave 5 days ago

      Node.js is not necessarily bad, but React? What makes React great is the ability to embed the DOM in your app. For CLI? Square peg, round hole.

      • MrJohz 5 days ago

        I'm not sure that's true. There's lots of ways to use and manipulate the DOM. But React is particularly special because it turns out to be a simpler way to think about UI components. A TUI has nothing to do with the DOM, but it's got a lot to do with rendering UI components. So taking the ideas from React and applying them to drawing elements in a terminal makes a lot of sense.

        Arguably it makes even more sense than with React. One of the problems with React is that the underlying DOM is a stateful, imperative system, whereas React wants to behaves much more like an immediate-mode system, where the whole UI can be dropped and re-rendered at any time. But the terminal is not stateful like the DOM, and a more immediate-mode paradigm arguably works better in this context than in the browser.

      • hombre_fatal 5 days ago

        What makes React great is that you write a UI tree that updates when state changes instead of imperative code like a clearRect() + drawLine() cycle.

        This project and others like React Native show that it works outside of the DOM: you just render something else instead.

        Thinking that React is only helpful for DOM UI seems like a misunderstanding of what React is and what makes it great.

      • lowboy 5 days ago

        React enables declarative UI code instead of imperative. That's one of its biggest values. Even in the terminal, especially as the complexity of a tool increases.

  • evantbyrne 5 days ago

    Looks like someone reported a dependency vulnerability back in June and never got a response. Seems like one of those projects that is a pretty neat experiment, but users should probably expect to maintain their own fork if they plan to use it.

    • gausswho 5 days ago

      The creator handed over control in May due the invasion of Ukraine.

  • akie 5 days ago

    I'm unsurprised, disappointed, excited, and surprised at the same time. It's clear that the React paradigm works really well to model user interfaces, and as such it's no surprise that it can be used to build anything from desktop software to apps to websites to command line apps.

    Amazing work!

  • taskylizard 5 days ago

    See also the blog post by the author: https://vadimdemedes.com/posts/moving-on-from-ink

  • 5 days ago
    [deleted]
  • magicmicah85 5 days ago

    If your use case is mainly consuming web APIs or providing helper tools around your web framework, I can see why using this would be useful as you could reuse the same libraries you use in your application.

  • EddieRingle 5 days ago

    See also, Mosaic, experimental terminal UI using Jetpack Compose: https://github.com/JakeWharton/mosaic

    Since it's Kotlin, it has backends for the JVM, LLVM, and JS/Wasm, though curiously Jake recently removed the JS target because it wasn't seeing much usage.

  • throwaway106382 5 days ago

    just because you can doesn't mean you should

  • revskill 5 days ago

    React is a kind of declarative programming, not just for the UI !!!!

    I could take React as a kind of FP design pattern.

  • jacobp100 5 days ago

    I used this at a company that was going all in on micro frontends. You’d clone whatever MFE repos you want, and it would manage package installs, building, and restarting the server after a rebuild. Worked great!

  • synergy20 5 days ago

    very nice, write some js/ts with React and use node to run them to get a CLI.

  • sirtimbly 5 days ago

    JS will eat the software world. So having better tools on par with charm in the go world would be great.

    • haolez 5 days ago

      Or it will be the (huge) technical debt of tomorrow.

  • TikTikFook 5 days ago

    [dead]