> It's kind of crazy that Facebook has let TypeScript takes so much market share. I've been using Flow for so long now. The techno is good, the integration with the code editors is good too, but Flow has a lot of small-but-really-annoying bugs (2235 issues on GitHub right now), the type definitions for third-party libs are meh (you often have to update/fix the definitions by yourself), the team seems extraordinarily unstaffed for such an important project, they don't share the roadmap at all, the priorities are clearly internal first (like improving the performances instead of fixing the bugs) and they don't seem to do much marketing or communication about it.
> I'd love to still recommend Flow, and as I said the techno is good and does the job, and they continue to release new versions, but I just don't see what benefits you would get by choosing Flow over TS at this point. Flow and TS do exactly the same job, with almost the same syntax (with different ways to transform it in JS tho), but TS has a bigger community and MS seems to put more efforts/resources into it. This has been true for 1 or 2 years now, so…
> I tried Flow and TypeScript for the first time a few months ago. Flow is absolutely abandoned and dying. TypeScript is taking over where Flow left off, and is far ahead of the game by now. I use TypeScript with create-react-app in my client work and it is invaluable and a wonderful experience, with no downsides as far as I can see.
To add to that, the only reason I can see to use Flow in 2018 instead of TypeScript is if you already have a large project that uses Flow and migrating to TypeScript might take a few days. But even then it's probably worth making the switch. I have noticed a much smoother experience and much better integration with TypeScript than with Flow. And there are many type errors that Flow never caught no matter how much I tried to configure it right. Existing code bases may have these too. Even more reason to switch sooner than later!
https://www.typescriptlang.org/play/#src=function%20a(x)%20%...
https://flow.org/try/#0GYVwdgxgLglg9mABAQwBQA8CUiDeAoRRAJwFM...
With Flow, we can surface type errors even in files that don't have any type information other than the @flow directive, e.g. http://eng.uber.com/wp-content/uploads/2018/07/image4.png
A big issue IMHO is Ocaml. FP heads usually hate JS, and they cannot dogfood Flow.
All the little issues feel like the devs don't use it enough to know the pain.
https://flow.org/en/docs/lang/nominal-structural/
"For example, Flow uses structural typing for objects and functions, but nominal typing for classes." This statement also applies to TS.
Flow does have nominally typed Opaque Type Aliases[1], which are essentially newtypes from what I've gathered. However, you can build similar zero-cost newtypes in TypeScript using union types, casting and "unique symbol"[2].
[1] https://flow.org/en/docs/types/opaque-types/
[2] https://github.com/Microsoft/TypeScript/issues/4895#issuecom...
* Wrap the application component tree in a React context provider component (which provides an instance that components will render styles into)
* On the server, extract rendered styles after SSR from provided instance and add necessary markup into the server-rendered page
* On the client, hydrate the provided instance from the server-rendered styles
* On the server and in development, set up a route handler that serves two assets, a web worker implementation and associated WebAssembly binary [1]
* On the client and in development, fetch and execute the web worker. Normally, this would be a somewhat difficult integration because of CSP-related issues with web workers, but because the plugin sets up its own route handlers, the requests will be same-origin, sidestepping most CSP issues that normally arise. Additionally, Fusion plugins can also modify response headers for requests, so if needed, CSP headers could also be set appropriately.
All the code to do this actually is related to a single concern, namely styling, but in a universal web app, such things typically requires the involvement of many different parts of the application lifecycle and both server and client code. Fusion plugins allow you to slice up the independent parts of your application logic in this fashion, somewhat analogous to how colocating HTML/CSS/JS for individual components in CSS-in-JSX is often much nicer than splitting apart component implementations across separate HTML/CSS/JS files.
[1]: This web worker generates debug CSS at runtime that maps rendered CSS to the source styled component definitions in JS using source maps, making it easier to reverse map the rendered CSS to the source CSS-in-JS when inspecting the DOM with the styles pane. https://github.com/rtsao/css-to-js-sourcemap
It’s nice to see more libs in this space, but it seems a little over complicated to me with the “plugin” style arch.
Conceptually it's simple: middleware is a function that typically accepts a downstream "app", and returns a new "app" which accepts a "request" and returns a "response":
const middleware = (app) =>
async (request) => {
// do stuff with request
const response = await app(request);
// do stuff with response
return response;
};
I worked on this idea way back in ~2009 (creatively called "JSGI" for the interface spec and "Jack" for an implementation) but promises weren't really a thing in JS, and async/await definitely wasn't a thing, so it was awkward.More recently Michael Jackson had a project called Mach which was a similar idea, but it's no longer active either: https://github.com/mjackson/mach
As an aside, one of my favorite aspects of this style is having symmetric interfaces for HTTP servers and clients. You could do neat things like use a cache middleware for both a client and server, or write a simple HTTP proxy in a couple lines.
Anyway, with the addition of promises, async/await, and async iterators to JS I'm starting to dust off these old ideas. prototype here https://github.com/tlrobinson/twosixonesix
Fusion.js is a team effort though: https://fusionjs.com/team
Does it only support react?
https://fusionjs.com/docs/getting-started/framework-comparis...
The main difference is Fusion.js has more support for backend things. For example, we provide a GraphQL plugin, and plugins such as I18N are bundle-splitting-aware out of the box.
The plugin system is universal (meaning you can isolate concerns by what the library is responsible for, rather than whether the code is server code, browser code, React provider boilerplate, HTML hydration code, etc).
This plugin architecture has already proved to be very valuable on more than a few occasions. One example is a service worker implementation we've been working on. It needs a middleware, browser-side registration code, etc, but all of this complexity is encapsulated in a plugin that can be added to any app with one line of code.
> Does it only support react?
Many plugins have a `-react` version that allow them to auto-integrate with React, but the core itself is view library agnostic.
The one thing I think should change though is decoupling from requiring Node from the runtime. I think the broader JS ecosystem could benefit from some of the ideas this library seems to promote.
Our company has standardized on Typescript, it has practically "won". Unfortunately for me, introducing Flow would get shot down.
- Fusion.js DI is token-based rather than string-based, so no naming collisions
- We support statically typing injectables (similar to Angular 2+)
- plugins are the only injectable entity type (whereas Angular is conceptually complex: e.g. modules, services, providers, factories, etc)
- plugins are isomorphic, whereas AngularJS injectables are not
I sorta already expected that people might get mixed feelings when seeing a DI system, but we spent a lot of time designing/tinkering with the plugin architecture to make it truly useful for managing complex library integrations and complex backends. I'd be happy to answer any questions about how we've been using it.
- isomorphic treeshaking
- more powerful bundle splitting (i.e. lazy loading can happen in any component rather than only at "page" level)
- async server-side rendering is composable via HOCs rather than only at top-level getInitialProps
- more things are provided by the team via plugins (e.g. I18N, CSRF protection, atomic CSS, async font loading, etc)
- better support for maintaining server-side complexity (e.g. by using Koa + DI system to make testing/mocking easier)
- out-of-band brotli level 11 compression for static assets
The team is about a dozen people now and we've been working on Fusion.js for over a year, so there's probably other stuff I'm forgetting right now :)
> lazy loading can happen in any component rather than only at "page" level
You can use dynamic imports anywhere in Next using `react-loadable`.
> more things are provided by the team via plugins
Next relies on its thorough `examples` dir for integrations. But it means a lot of manual coding.
I had a crack at a plugin system in the past (i.e plugins for adding features like apollo, redux, etc. AOT like stuff). I found that it obfuscated the code too much. Makes it hard to trace what is happening and make adjustments. The closer the code is to the "Getting Started" examples of Redux, I18n, Apollo, the easier it is to tweak and understand.
E.g. Sometimes it might be clearer to just wrap a Provider manually around the app root, than expose a plugin hook. Because you can see the React tree, whereas with plugins everything is dynamic so you must rely on logging.
I think devs are naturally drawn to DRYness and dividing code up by feature, which is what a plugin system offers, but there are big tradeoffs. I'm interested to dive into Fusion to learn more about their approach though.
> - better support for maintaining server-side complexity (e.g. by using Koa + DI system to make testing/mocking easier)
Great to see you adopting Koa! I use it myself, and feared that the community had stagnated, but now with Fusion, it may be reinvigorated.
> DI system to make testing/mocking easier
Very cautious of DI systems. Same reasons as plugin systems: its hard to see what is going on. And sometimes manually wiring up all the dependencies is actually not much code at all, and you can manage cyclic dependencies and ordering easier.
Keen to dive in deeper though.
In Fusion.js, the injectable registration is done in the entry file, and initialization patterns are the concern of the service API. I think these design choices simplify things a lot.
The increase in complexity and lack of visibility from a DI system, vs what the manual wiring code would look like, can be immense.
Fusion.js locks you in, Reframe doesn't.
(I'm Reframe's main author.)
Without a more detailed argument this sounds like you're just plugging your product.