days
0
-24
-4
hours
-2
-2
minutes
-2
-6
seconds
-5
-7
search
Interview with Crank.js creator Brian Kim

“Crank.js uses all four of JavaScript’s fundamental function syntaxes for writing more declarative code.”

Ann-Cathrin Klose
Crank.js
© Shutterstock / Sinart Creative

Crank.js adds yet another framework to the JavaScript ecosystem. It was designed for creating JSX-based promises, and it also comes with its own syntax for components. We spoke to its creator, Brian Kim, about the framework, its benefits, and future expectations.

JAXenter: Hi Brian and thank you for taking the time for this interview. Crank.js is another JavaScript framework – why did you develop it? 

If you want to play a role in shaping the future of Crank, then I’d be very happy to have you.

Brian Kim: Creating your own JavaScript Framework takes equal parts tenacity and insanity, because you’re essentially saying “all you people writing apps, I want you to write them my way,” which is a cocky thing to say. So I did not view the task lightly and treated creating a framework as a method of last resort.

In short, I felt like I was forced into writing a framework because, up to that point, I had been using React happily, but I was increasingly frustrated by the latest APIs and how each of them seemed to take a little bit of my ability to reason about components away from me. I knew I wanted to continue using JSX, and I had been experimenting a lot with generators and async generators, and it suddenly hit me that I could write stateful components with generators and I really just followed this idea to its logical conclusion.

JAXenter: What kind of project would profit from using your framework instead of React?

Brian Kim: Greenfield projects! If you’re starting something new and want to be on the frontier and play a role in shaping the future of Crank, then I’d be very happy to have you. There’s enough different with React that I don’t think you could just convert a React app in production to Crank easily, though I’m curious if there are codemod solutions for this in the future. One thing I would warn React developers about, though, is that I’ve noticed that React developers are putting more and more logic into hooks. This is an extreme form of vendor lock-in, in the sense that hooks cannot be called outside of React. The more hooks you use, the harder it will be to migrate in the future.

SEE ALSO: Node 14 released with diagnostic reports as stable feature

JAXenter: You specifically say that the Suspense API in React was a tipping point for you. What was it that you did not like about it?

Brian Kim: There were a couple of things that I did not like about Suspense:

  1. The mechanism: Suspense requires components to throw promises like you would throw errors to indicate asynchrony. I know that this might change, but it’s how React and library maintainers assume it will work as of today. I don’t think it’s a sound mechanism because it means all async calls require caching, which can be tricky to work with. Cache invalidation is one of the two hard problems of computer science, and to ask people to have a cache for all their async calls seems like a big ask to me and opens developers up to a whole class of stale cache bugs.
  2. async/await syntax: When I finally got async components working, I was surprised at how natural it felt, while React developers were constantly saying virtual DOM and promises don’t match. Every day, as beginners learn React, one of their big questions is: How do I use async/await syntax? There’s no good answer, because it almost seems like React goes out of its way to make using async/await hard. For instance, the useEffect hook requires the callback to return a function, so you couldn’t make the callback asynchronous.

JAXenter: What did you do differently with Crank regarding the use cases covered by the Suspense API in React?

Brian Kim: In Crank, the Suspense API is fully implementable in user-space thanks to async generator functions. Essentially, you can use the same virtual-DOM diffing algorithm to race components against each other, solving the problem of fallback states. Here, for instance, is how you would implement the Suspense component in Crank:

async function Fallback({timeout = 1000, children}) {
  await new Promise((resolve) => setTimeout(resolve, timeout));
  return children;
}
 
async function *Suspense({timeout, fallback, children}) {
  for await ({timeout, fallback, children} of this) {
    yield <Fallback timeout={timeout}>{fallback}</Fallback>;
    yield <Fragment>{children}</Fragment>;
  }
}
 
(async () => {
  await renderer.render(
    <Suspense fallback={<Spinner />}>
      <ProfilePage />
    </Suspense>,
    document.body,
  );
})();

JAXenter: In your introduction to Crank.js, you also say that you think you created a new way of developing components. How are your components different from other concepts?

The only thing that developers need is a modern JavaScript environment.

Brian Kim: The big idea is that React only uses synchronous functions to model components. However, JavaScript has four fundamental function syntaxes (function, async function, function * and async function *), and Crank uses all of them to empower users to write more declarative code. I think some people had this dogmatism that React UIs = pure functions, but I think what we really wanted all along was to just use function syntax, and leveraging all the different function syntaxes expands the notion of what a component can be.

JAXenter: Can you give us an example of how a stateful component in Crank.js would look like?

Brian Kim: All state in Crank is encapsulated with generator components:

function *Timer() {
  let seconds = 0;
  const interval = setInterval(() => {
    seconds++;
    this.refresh();
  }, 1000);
 
  try {
    while (true) {
      yield (
 <div>Seconds elapsed: {seconds}</div>
      );
    }
  } finally {
    clearInterval(interval);
  }
} 

Rather than returning JSX expressions, you yield them, meaning that the generator’s natural internal state, which is really just its variable scope, is preserved between renders. This means that state is just local variables, and the simplicity of this idea cannot be overstated. All of React’s separate concepts like props, state and refs can be mixed freely, which is really liberating as a developer experience.

JAXenter: Which technologies did you use to build the framework; are there any dependencies developers need to use Crank on their projects?

Brian Kim: Crank has one dependency on event-target-shim, which I plan to pull in and refactor at some point, and I already bundle it with rollup. The only thing that developers need is a modern JavaScript environment which has promises, generators and async generators. Once you have that, you’re all set.

SEE ALSO: Progressive React Apps

JAXenter: What features would you like to add to Crank.js going forward?

Brian Kim: I’d like to see a way to work with web components! Being able to somehow “compile” Crank to standalone web components so you could incorporate them into apps without having to know or care about Crank would be neat.

I’d like to see a way to work with web components!

However, besides incorporating community feedback and making performance improvements, I really want to limit the scope of the core API. My dream is to make Crank so simple and fundamental that an experienced JavaScript developer who was stuck on a deserted island with only a laptop (and a power source) could recreate all of Crank from scratch, because the algorithms that Crank uses were so clear in their head.

Thank you for the interview!

Author
Ann-Cathrin Klose

Ann-Cathrin Klose

All Posts by Ann-Cathrin Klose

Ann-Cathrin Klose is an editor and has been working for S&S Media since 2015. Before joining the team she studied General Linguistics at Johannes Gutenberg University Mainz.

Leave a Reply

avatar
400