Introducing Fusion.js: A Plugin-based Universal Web Framewor资料
本文为去找网小编(www.7zhao.net)为您推荐的Introducing Fusion.js: A Plugin-based Universal Web Framework，希望对您有所帮助，谢谢！
A more well-known fact is that web technologies change quickly and best practices are constantly evolving. Providing a high quality framework with modern features to hundreds of web engineers while keeping up with the dynamic nature of the web platform has historically been a challenge.
To address this challenge, Uber’s Web Platform team built , an open source web framework that makes web development easier and produces lightweight, high-performing apps.
As web industry best practices evolved, Uber needed to revamp its aging monolithic web framework to something that addressed the challenges posed by the years-long accrual of technical debt. However, we also wanted to let engineers keep using the technologies they love (e.g., React, and Redux) while maintaining compatibility with Uber’s app health monitoring infrastructure.
Specifically, we wanted the core framework to address the following pain points:
Complex configuration and required boilerplate of multiple tools needed for server-side rendering, code splitting, and hot module reloading
Lack of good abstractions for implementing and sharing features that involve different aspects of server-rendered React applications (i.e., spanning both server and client, dealing with serialization/hydration, server-client communication, etc.)
Brittleness resulting from tight coupling of code located in different places
Testing difficulties arising from side effects and singletons
Lack of flexibility of a monolithic framework
While existing solutions addressed some of these challenges, we found that gluing a library on top of a framework often required changes to multiple unrelated files. For example, supporting Redux in a server-renderable app involves adding setup code somewhere in the server-related files, similar code somewhere in the browser ones, hydration code to the HTML template, a React Provider component, etc. Integrating an library or browser performance metrics library leads to the same problem.
To make matters more difficult, a lot of application-specific code can depend on libraries that manage side effects (e.g., for logging or data persistence), and it can be difficult for an engineer to integrate such a library in a testable way without the help of a service layer abstraction.
While we wanted to provide easy-to-setup, battle-tested integrations with the various libraries that are used by teams at Uber, we also wanted to avoid a monolithic framework in order to keep bundle sizes small.
Another reason we prefered a modular approach over our existing monolithic approach is that it forces us to be explicit about dependencies, which makes it easier to avoid common sources of technical debt such as , ad-hoc internal interfaces, and tight coupling.
is the culmination of our efforts.
Who should use Fusion.js?
Fusion.js is a good choice for someone looking for an open source boilerplate to build a modern, non-trivial web app.
On top of the obvious benefits of a pre-configured, optimized boilerplate, Fusion.js also provides a flexible plugin-based architecture. This makes it well-suited to modern single-page applications and web apps that depend on complex service layers to meet quality requirements such as observability (e.g. trace logging, metrics dashboards, etc.), thorough testing (e.g., unit / integration / E2E), and internationalization.
For more on the benefits of Fusion.js, check out our .
The single entry point architecture enables Fusion.js plugins themselves to be universal, too, which allows plugin developers to co-locate snippets of code based on the library the code pertains to, as opposed to the environment the code runs in.
Figure 1. Fusion.js plugins encapsulate logic based on their logical grouping rather than based on where the code needs to be added.
Plugins have access to the HTTP request lifecycle via middlewares and can also access the React tree to add Provider components.
Ultimately, these qualities make it possible to install a library into an application with a single line of code, regardless of how many different integration points the library requires. Since plugins are easy to add and remove, it also becomes easy to reason about their coupling, impact on bundle size, and other code quality attributes when refactoring. They can also initialize browser code.
Typed dependency injection
Plugins leverage dependency injection, meaning they can expose well-defined APIs as services to other plugins, and a plugin’s dependencies can easily be mocked during tests. This is especially important when dependencies are responsible for communicating with data storage infrastructure or when they relate to observability (e.g., logging, analytics, and metrics).
It’s also possible to ensure type safety statically among dependencies via Flow.js, as depicted below:
Figure 2. Surfacing type errors directly in the code editor helps catch bugs before the code runs.
One challenge that became apparent years ago was that the popular HTTP server library has an API that encourages eager side effects, which made complex response transformations difficult to encapsulate and test. For our previous architecture, application developers often needed to resort to ad-hoc monkey-patching of Express request/response objects and careful colocation of unrelated concerns in ways that only made sense in terms of the order functions needed to be called for things to work as expected. Naturally, given the high coupling of timing requirements for side effect-rich subsystems, testing became extremely difficult.
This problem had been a concern since the design stages of Fusion.js. After much research, we chose to adopt , which provides a more unit-test friendly context-based API, and an elegant and lightweight abstraction for request lifetime management based on the concept of downstreams and upstreams.
As it turns out, the design decisions adopted by Koa complement the design decisions in Fusion.js very well.
Koa middleware provides a logical integration point for React Provider components and the downstream/upstream abstraction aligns perfectly with the lifecycle of the React server-rendered context. Network side effects are decoupled from application logic, improving testability.
The God object and order-of-operation issues that plagued our older apps are now resolved by the Fusion.js dependency injection and graph resolution mechanisms.
Figure 3. Fusion.js core segregates network side effects from application state and leverages Koa and DI to achieve loose coupling between subsystems.
, , and , Fusion.js also provides tooling for developers to test plugins. The package allows mocking the server itself, making it possible to quickly run integration tests between any permutation of plugins and mocks.
Just the beginning
Within Uber, there are already more than 60 repositories using Fusion.js since its internal release. We expect this number to increase rapidly due to a combination of new web projects and automated migration of older projects to Fusion.js. Given this demand, improvements at the framework level should significantly improve the software quality baseline for these projects.
Our roadmap includes adding more performance optimizations and test-oriented tooling, as well as better Flow support.
If you’re interested in using Fusion.js and/or want to contribute, check out the and our . If you have comments or questions, you can also reach us on .
to keep up with the latest innovations from Uber Engineering.
以上为Introducing Fusion.js: A Plugin-based Universal Web Framework文章的全部内容，若您也有好的文章，欢迎与我们分享！