Skip to main content

What If Web Didn't Support Dynamic Capabilities Initially

Free2020-10-03#Mind#移动端动态化#客户端容器化#移动端动态更新#热修复#插件化

If Web didn't support dynamic capabilities initially, what kind of dynamic path would the frontend army have forged?

Prologue

Web was born with extremely flexible dynamic capability foundations, such as:

  • Dynamically inserting script tags to execute arbitrary script logic

  • Dynamically inserting style tags to import any CSS style rules

  • Embedding entire sites through iframe tags

  • All above tags can directly load network resources

  • Web pages carrying this content are deployed on remote servers, can be dynamically updated at any time, and take effect immediately

Exploration and practice all along seems to only continuously discover the engineering value of dynamic capabilities, seeking more suitable application scenarios, such as early frameset, today's Micro-Frontends/Micro-Applications

Mobile is exactly the opposite, born with many flexibility limitations:

  • Native doesn't support dynamically executing logic code

  • Key resources constituting mobile applications mostly need to be packaged into installation packages ([Dynamic Libraries](/articles/node-js-c 扩展入门指南/) are exceptions)

  • Applications are installed on user devices, installation package updates require app store review, users need to reinstall to take effect

Mobile business development continuously puts higher requirements on dynamic capabilities, but suffering from lack of dynamic foundation capabilities, so has been exploring more flexible technical solutions, like early hot fixes/hot updates, to today's mini-programs

Actually, both need to solve consistent engineering problems in dynamic technical capabilities, such as dynamically loading dependency libraries, view components, even entire applications. So might as well open imagination, assuming Web doesn't support dynamic capabilities, deduce Web dynamic technology development trajectory with Native business requirements

Beginning: Native WebAssembly

0061 736d 0100 0000 0187 8080 8000 0160
027f 7f01 7f03 8280 8080 0001 0004 8480
8080 0001 7000 0005 8380 8080 0001 0001
0681 8080 8000 0007 9080 8080 0002 066d
656d 6f72 7902 0003 6763 6400 000a ab80
8080 0001 a580 8080 0001 017f 0240 2000
450d 0003 4020 0120 0022 026f 2100 2002
2101 2000 0d00 0b20 020f 0b20 010b

Once upon a time, Web applications could only be packaged into this [wasm](/articles/webassembly 试玩/) binary format, published to major browser app stores. During this, not only had to wait days for review, after passing still had to wait for users to actively install updates, waiting for new version to truly "take effect" (cover most users), might already be months later

Version iteration is slow, whether strategically important features or urgent problem fixes, cannot reach users in time. Even if online is on fire, fastest firefighting solution also takes days or even weeks to take effect

To be able to fix problems faster, reduce risks, exploration of hot fix solutions thus began

Spray: Introducing Script Language JavaScript for Hot Fixes

Hot fixes mean loading and running (outside installation package) logic code, so some people started directly from WebAssembly module loading mechanism, researched some Hook solutions, able to dynamically replace certain modules/files

Some people went further along this direction, weighing timeliness, performance, compatibility and stability, through compilation instrumentation, engineering supporting facilities, runtime framework and other means solved module dependencies, version management, differential updates and other issues, plugin-izing various functional modules of applications

Some people took another approach, introducing lightweight script language runtime (such as JavaScript engine), and built a bridge between native WebAssembly and JavaScript world, allowing calling native system platform capabilities through JavaScript, thereby expanding dynamic foundation capabilities

Dynamic capabilities rippled a wave, followed by roaring waves of dynamic updates

Tsunami: JavaScript-Based Dynamic Updates

After taking the first step towards dynamic capabilities, just one step away from the bright prospect of comprehensive dynamic capabilities:

Any application that can be written in JavaScript, will eventually be written in JavaScript. —— Jeff Atwood

(Excerpted from The Principle of Least Power)

Comprehensive dynamic capabilities means:

  • Migrate all parts of application that can be dynamicized to JavaScript implementation

  • Organize massive JavaScript code by functional modules, and manage dependencies between functional modules well

Thereby achieving rapid iteration with functional modules as units, equivalent to applying hot fix technology to requirement iteration beyond problem fixes, no need to release version, avoid review cycle, also no need to wait for users to actively install, new features can be dynamically published and quickly cover active users

Dam: Container Concept Forms

With continuous improvement of dynamic capability degree, JavaScript's proportion in applications gets higher and higher, finally only remaining parts that cannot be dynamicized (or no need to dynamicize) still implemented by WebAssembly, including:

  • System platform capability bridging

  • Basic UI controls, interaction capabilities

  • View layer framework (history stack management, lifecycle support, etc.)

  • Specific business domain capabilities (such as multimedia content production, IM SDK, etc.)

  • Communication mechanisms (broadcast, state sharing, etc.)

These parts form containers (native shell), equivalent to a dynamic runtime running in browser, within capability scope circled by container, business can fully utilize dynamic advantages, achieve rapid fixes, rapid publishing, rapid reach, rapid iteration

But appearing together with container concept, besides empowering business to run faster, there's also dependency problem between dynamic business and containers:

  • How to decouple strong coupling between them, such as routing, hybrid view container and other scenarios?

  • How to identify dependency relationships between them?

  • How to ensure dependency relationships are controllable, such as prohibiting publishing dynamic business depending on new capabilities to old containers?

After managing dependencies through engineering supporting facilities, next primary problem is finding ways to ensure reliability of underlying containers that dynamic business depends on

Boundary: HTML, JavaScript, CSS Form Container Standards

Common means to isolate changes is adding a layer of abstraction, placing changing parts below abstraction layer:

  • BOM API: Abstraction of system platform, view layer framework capabilities and communication mechanisms

  • Native Module API: Abstraction of specific business domain capabilities

  • DOM API: Abstraction of basic view rendering capabilities

  • JS API: Abstraction of JavaScript runtime

  • CSS: Abstraction of style, layout capabilities

  • HTML: Abstraction of basic UI controls, interaction capabilities

These abstracted standards establish solid container boundaries, inside boundaries, dynamic business can freely play, below boundaries, containers can also continuously improve, enrich container capabilities, widen boundaries. Meanwhile, APIs with standard definitions can be maintained in structured form, greatly beneficial for development experience

Cloud Sea: Browsers Support Loading Network Resources

On the other hand, during standardization process, some dynamic business practices also settled into containers, such as:

  • Dynamic scripts: script supports loading network resources

  • Dynamic styles: style supports loading network resources

  • Dynamic routing: Browsers support directly loading through URL, or embedding network applications through iframe

Although from hot fixes onwards could pull JS files from CDN, dynamically interpret and execute at runtime, but container standards not only provide convenient support for this method, also expand dynamic foundation capabilities from logic to views, styles, static resources, etc.

At this point, most critical dynamic foundation capabilities are complete. Functional modules migrated to JavaScript can even be further deployed to cloud, achieving flexible switching between offline integration, online hosting two modes

One Color: Synchronous, Asynchronous Mode Switching Freely

Complete dynamic foundation capabilities unlock many new ways to play, such as:

Further split business modules (bundle) into functional modules (chunk), and async out non-core modules, achieving dynamic on-demand loading, such as third-party JS SDKs, jQuery plugins, and heavyweight components like share/comment/city selection etc.

For content presentation偏向 static scenarios, can also complete (most) page rendering work on server through SSR, accelerate first-screen content display

On the other hand, runtime features like Hydration, lazy components, Suspense etc. enable online dynamic parts to fully integrate with offline non-dynamic parts, achieving finer-grained business dynamicization, letting online hosting truly become a deployment option

Meanwhile, dynamic business's own componentization degree also continuously deepens, frontend development's core work shifts from page, module development to component, orchestration logic development

Flowing Cloud: Data-Driven Frontend Applications

After component system tends to mature, a long-standing concept finally completely emerges——Data-Driven

From frontend-backend layered data protocols, gradually evolved into data-driven, here data includes 3 parts:

  • Backend business domain data

  • Frontend state data

  • Frontend derived data (based on backend business domain data)

Filling these data into business components can render complete functional modules (whether on client or server), then placing them into suitable slots in view containers, completes a component-level "publish" process

This mode involves 5 important links:

  • Production of business data (including backend business domain data and frontend derived data)

  • Production and maintenance of business components (including frontend state data)

  • Rendering of components (business data + business components = functional modules)

  • Production of slots

  • Deployment of functional modules

Among them, business components, slots are key to further dynamicization, can be divided into 4 stages:

  • One radish one slot: Static business components + Static slots

  • One radish thrown everywhere: Static business components + Dynamic slots

  • Multiple radishes thrown alternately: Dynamic business components + Static slots

  • Multiple radishes thrown everywhere: Dynamic business components + Dynamic slots

To achieve multiple radishes thrown everywhere component-level dynamic ultimate goal, requires being able to dynamically publish business components, dynamically publish slots

Fusion: Dynamic Business Components + Dynamic Slots

From perspective of client and cloud, business components can also be seen as part of data (cloud), in comparison slots are more closely related to client, and only means of dynamicization is moving client-side things to cloud, so key problem to solve is how to achieve slot dynamicization

There are 2 approaches:

  • Eliminate slot concept: Expand slot concept from component-level to page-level, one page container (one URL) is one slot

  • Componentize slots: Provide standard slot components, like iframe

Pages are natural dynamic slots, can open a new page container to load any URL

For other layout containers besides pages, such as dialogs, message bars, Banner positions, waistbands etc., can standardize slots into container components, dynamically published together with business components, maintain slot rental relationships on server side, as one of data-driven data

At this point, frontend-backend layering boundaries redefined several times, finally welcomed JSP/PHP golden era of fusing data and templates...

References

Comments

No comments yet. Be the first to share your thoughts.

Leave a comment