因为工作关系,开源通迅没有及时得到更新。
经过考虑,今后以短篇幅的简报形势发布,类似于开源软件的发布理念,“尽早发布,尽快迭代”。
本期内容要和大家介绍一些前端技术的趋势。
前端技术应该说是技术更新换代最快的,别说早已淘汰的Applet,XUL等,就是曾经大红大紫的JQuery,Flash等,目前也早已被代替。
目前主流前端技术是基于Javascript的框架,如React,Angular等,除了可以运行在较新的浏览器上,也可以适配各种尺寸的移动终端,还有原生APP的框架,如React Native, Ionic等。受益于NodeJS高效编译和运行技术,Javascript各代语法特性和进化语言,快速纷呈发展。P
C端跨平台的高生产里的UI技术,如基于Electron和NW.js的应用,像目前大火的IDE Vscode,制作小程序的开发工具等,也都是JS框架技术。可以说,现在做前端,不懂JS将寸步难行。
从三个侧面介绍去年下半年以来出现的一些趋势。
一,Web Components技术已经越来越被更多的浏览器作为标准技术进行实现。
用一段代码来说明吧:
index.html:
<html lang="en">
<head>
<title>Web Component</title>
<link rel="import" href="./world.html">
</head>
<body>
<h1>Web Component</h1>
<!--2. 使用web component -->
<world id="wd" title="helle world"></world>
<script>
通过更新组件的属性,来触发title的改变
setTimeout(function() {
document.querySelector('#world').setAttribute('title', '你好, 世界!');
}, 1000)
</script>
</body>
</html>
world.html:
<template>
<style>
.title {
color: red;
}
</style>
<h1 class="title">你好</h1>
</template>
<script>
(function () {
var thisDoc = document.currentScript.ownerDocument;
var template = thisDoc.querySelector('template').content;
var element = Object.create(HTMLElement.prototype);
初始化创建的时候回调
element.createdCallback = function() {
var clone = document.importNode(template, true);
开启shadow的子根节点,这样才能 this.shadowRoot.querySelector('.title')获取到h1
var shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.appendChild(clone);
}
属性改变的时候触发的回调
element.attributeChangedCallback = function(attr, oldVal, newVal) {
this.shadowRoot.querySelector('.title').innerText = newVal;
}
document.registerElement('world', {
prototype: element
})
}());
</script>
利用这段文字,可以自行定义元素名称,如"world",实现元素界面的扩展。
目前 W3C 对 Web Components的定义包括:
Custom Elements自定义元素。
就是上面体现的特性,提供一种方式让开发者可以自定义 HTML 元素,包括特定的组成,样式和行为。
支持 Web Components 标准的浏览器会提供一系列 API 给开发者用于创建自定义的元素,或者扩展现有元素。
HTML Templates HTML模板。
提供了一个 template 标签来存放以后需要但是暂时不渲染的 HTML 代码。
Shadow DOM 旨在提供一种更好地组织页面元素的方式,来为日趋复杂的页面应用提供强大支持,避免代码间的相互影响。
JSON, CSS, HTML Modules。
对各种资源文件提供统一的模块化引入机制。
看到这个规范内容,让我想到XML格式又会引起纷争,还有20年前就已经定义完备的XUL语法。技术界的轮回真是一次又一次。
二,Martin Fowler提出的Micro Frontends模式
Martin的PEAA是软件架构的经典之作,也几乎踏准了每一次的技术演进。Micro Frontends这个词,我们可以按照MicroService的方式,翻译成微前端。
经典的Web架构,分拆前后端之后,前端和后端可以都看作“单体”,即把所有的功能都混合在一起,组成完备的应用。目前业界已经完全接纳了微服务后端体系,那么前端也可以进行分拆吧。
按照目前的技术,实现“微前端”的方式可以有几种方法:
1. 服务器端的模板组合。通过服务器,可以同时渲染多个页面到单一页面中。这种方式容易实现,但需要服务器配合。
2. 构建时集成。目前JS框架写成的前端,有构建(编译)的过程,用来减少体积,提升效率和适度混淆,可以利用这个过程进行多个模块的集成。
3. 通过iframes在运行时集成。通过JS代码,分析请求并在子frame中加载不同的页面。这种方法也容易理解,只是子frame方式割裂了整体页面完整性。
4. 通过JS在运行时集成。通过JS代码,分析请求并将路由导入不同的页面和JS代码中。这种方法是目前主要采用的方式。
5. 通过Web Components运行时集成。和上面的方法相同,只是利用前面谈到的标准Web组件的方式。应该是最“优雅”的方式。
通过“微前端”技术定义,前端开发人员也可以进行分工协作,完成各自的工作模块。其实目前的JS框架都有模块的概念,这个从规范性进一步明确定义。
三,WebAssembly
WebAssembly中有汇编Assembly,从名字上就能知道是给Web使用的汇编语言,可以通过浏览器执行二进制语法。
但WebAssembly并不是直接用汇编语言,而提供了中间语言机制(LLVM IR),把高级语言(C,C++和Rust)编译为WebAssembly,在浏览器中运行。可以解决目前JS语言的效率问题,设计目标为快速,内存安全和开放。
所以是一种运行机制,一种字节码格式(.wasm)。简单来说,可以认为浏览器从之前的解释执行 js 变为直接运行二进制格式的代码,
通过LLVM等工具,可以编译不同的语言到字节码wasm格式。WebAssembly 模块,它可以加载到 JavaScript 中使用。
function fetchAndInstantiate(url, importObject) {
return fetch(url).then(response =>
response.arrayBuffer()
).then(bytes =>
WebAssembly.instantiate(bytes, importObject)
).then(results =>
results.instance
);
}
.wasm文件包括必须的和可选的部分。
必须部分:
Type:在模块中定义的函数的函数声明和所有引入函数的函数声明。
Function:给出模块中每个函数一个索引。
Code:模块中每个函数的实际函数体。
可选部分:
Export:使函数、内存、表(tables)、全局变量等对其他 WebAssembly 或 JavaScript 可见,允许动态链接一些分开编译的组件。
Import:允许从其他 WebAssembly 或者 JavaScript 中导入指定的函数、内存、表或者全局变量。
Start:当 WebAssembly 模块加载进来的时候,可以自动运行的函数(类似于 main 函数)。
Global:声明模块的全局变量。
Memory:定义模块用到的内存。
Table:使得可以映射到 WebAssembly 模块以外的值,如映射到 JavaScript 的对象。这在间接函数调用时很有用。
Data:初始化导入的或者局部内存。
Element:初始化导入的或者局部的表。
目前主流的语言基本已经都有对WebAssembly的支持。Java语言中,也有一些开源项目。
TeaVM是一个AOT编译器,可以将Java文件编译成wsam格式,Java语法采用和GWT类似的方式。
import org.teavm.jso.ajax.XMLHttpRequest;
import org.teavm.jso.browser.Window;
import org.teavm.jso.dom.html.HTMLButtonElement;
import org.teavm.jso.dom.html.HTMLDocument;
import org.teavm.jso.dom.html.HTMLElement;
public final class Client {
private static HTMLDocument document = Window.current().getDocument();
private static HTMLButtonElement helloButton = document.getElementById("hello-button").cast();
private static HTMLElement responsePanel = document.getElementById("response-panel");
private static HTMLElement thinkingPanel = document.getElementById("thinking-panel");
private Client() {
}
public static void main(String[] args) {
helloButton.listenClick(evt -> sayHello());
}
private static void sayHello() {
helloButton.setDisabled(true);
thinkingPanel.getStyle().setProperty("display", "");
XMLHttpRequest xhr = XMLHttpRequest.create();
xhr.onComplete(() -> receiveResponse(xhr.getResponseText()));
xhr.open("GET", "hello");
xhr.send();
}
private static void receiveResponse(String text) {
HTMLElement responseElem = document.createElement("div");
responseElem.appendChild(document.createTextNode(text));
responsePanel.appendChild(responseElem);
helloButton.setDisabled(false);
thinkingPanel.getStyle().setProperty("display", "none");
}
}
熟悉Javascript和GWT的开发者可以很容易理解这段代码,通过编译成wasm文件供浏览器加载执行。
JWebAssembly 是一个Java二进制的编译器,可以编译代码片段,使用方式和上面的TeaVM类似,不过没有使用GWT类似的封装方式。
另外GraalVM项目也宣布了发布GraalWasm项目,提供一个引擎运行wasm格式文件。作为Graal的外部项目,通过gu命令进行安装。Java应用程序可以使用GraalWasm引擎来执行wasm文件。
总结
前端技术进入一个有趣的新阶段,以上介绍的技术还有待继续成熟。
作为中间件后端技术的爱好者,我认为上述前端很有前途,可以和后端中间件新技术更好的配合使用,更高效的开发软件应用。




