上微服务时,我们必需有全链路追踪、应用程序性能监测(APM)。开源的Elastic Stack是一个不错的选择,它包含日志、指标、APM、搜索、Kibana等。使用Elastic Stack做NodeJS APM时,使用起来非常方便,代码也无入侵。
只需在程序的前面添加一行代码: const apm = require('elastic-apm-node').start()
; 然后添加环境变量ELASTIC_APM_SERVER_URL
,正常启动程序: node index.js
。
能如此方便地使用,也是得益于NodeJS的事件模型、async_hooks
与elastic-apm-node
,其中的elastic-apm-node
已经帮我们创建好同步或异步流程中的Transaction与Span。大部分时候,我们只需写好自己的业务代码。
样例代码:apm-nodejs-app-a、apm-nodejs-app-b、apm-nodejs-app-c
继续阅读→
随着业务的发展,单页面应用(SPA)开发的前端系统也越来越复杂,这时需要多个团队并行开发。为了提高生产效率,每个团队需要能够独立开发、部署与维护,于是引入了与后端微服务相似的“微”架构:微前端与SSR微服务。即使一个团队,为了新特性不影响其它部分、能够更快速的上线,也引入了“微”架构。无逻辑的前端静态资源服务,就不在讨论之列。
本文主要探讨React与Vue的微前端 + SSR微服务
。
继续阅读→
这几天研究一下Vue,看看在Vue中如何实现微前端。期间发现Vue Router v3比较坑:
- 只支持动态加载从根路由(parent)开始的嵌套路由,这限制了有路由的微前端颗粒必需从根路由开始。没有路由的微前端,不受这影响。😟
- 在导航守卫router.beforeEach之前,Vue Router已经闭包缓存本次的匹配路由,造成router.beforeEach中动态加载新路由也无法立即匹配到。
坑1,不好解决,等待Vue Router v4出炉就好,暂时使用大颗粒的含路由微前端。坑2,我们需要在router.beforeEach之前加载微前端APP相关的JS与路由注册。本文就介绍解决坑2的简单方法。
继续阅读→
Vue SSR官方的指导教程只有简单的Webpack配置,没有指导如果使用Vue CLI来构建SSR。Vue CLI构建CSR的SPA比较方便,默认不支持构建SSR。好在Vue CLI的可定制性比较强,经过一番的摸索,终于成功使用Vue CLI构建Vue SSR。
在构建SSR之前,需要按照官方的指导完成代码的改造,让SSR与CSR代码复用。
继续阅读→
前端客户端渲染(CSR)时,一般都进行代码拆分,按需懒加载页面相关的JS/CSS与数据,交互体验比较好且容易开发。但是只进行CSR时,首屏显示比较缓慢。服务端渲染(SSR)时,一次请求能拿到页面完整的HTML内容,我们用来解决首屏显示缓慢的问题。同时使用CSR与SSR,就面临如何复用所有的代码,包含CSR代码拆分。
在React/Preact中,SSR复用CSR代码拆分有两种实现:@loadable/component与preact-cli 。@loadable/component中使用NodeJS的require()动态加载JS文件,而preact-cli则直接静态打包到一个JS文件中。
继续阅读→
在开发客户端渲染(CSR)与服务端渲染(SSR)共用的前端代码时,需要使用Redux初始化状态。但是发现Redux-saga的take等函数只能在createStore()之后才能使用,不是很方便。于是,造一个跨组件通信的Redux side-effect中间件: ChanMiddleware 。
ChanMiddleware支持以下3个函数:
interface ChanHandler {
(state?: any, action?: AnyAction, dispatch?: Dispatch, next?: () => void): void
}
const use = (type: string, handler: ChanHandler) => void;
const useOnce = (type: string, handler: ChanHandler) => void;
const unUse = (type: string, handler: ChanHandler) => void;
type等于'‘时,handler处理所有的Action。
继续阅读→
NodeJS C++插件直接扩展NodeJS V8引擎,性能比JS要高很多。同时,通过N-API跨越JS与C++的边界,不需要做序列化/反序列化,性能代价也很小。根据二八法则,使用C++插件来解决NodeJS业务系统的性能问题/密集型计算,而不是完整业务系统的主要功能。
在开发NodeJS插件时,可以选择N-API、nan、或者内部V8接口实现。但是,N-API有良好的ABI兼容性,可确保插件一次编译能够在多个NodeJS版本中运行,更新NodeJS版本之后不需要重新编译插件。学习NodeJS插件开发,可参考官方的node-addon-examples。
在本示例中,我们使用C++11 std与boost实现4个导出函数:
generateNumbers(n: number, callback: (v: number) => void): void;
joinStrings(arr: string[], sep: string): string;
isPrime(n: number) => boolean;
isPrimeAsync(n: number): Promise<boolean>;
本示例源码:napi-addon-1-hello-primes
继续阅读→
C++的构建环境比别的计算机语言要复杂得多,一切从头开始安装是最麻烦的,比如:安装编译器、第三方库等。在容器时代,使用已准备好的Docker镜像就省事多了。在开发WebAssembly C++时,可直接使用Emscripten SDK docker镜像。虽然C++ WebAssembly的构建比较复杂,但是,其生成的目标文件(*.wasm)比GoLang的要小很多,更适合于Web网络传输。
示例代码,见: hello-web-assembly-cpp
继续阅读→
以前写过一篇 Hybrid App体验(Android),但是未动手验证Native和Web之间的双向消息通信。今天起床之后,想在Web中启动Android相机与振动通知玩玩,于是开始实现双向的通信,技术特点还是JSBridge。
比较坑的是Android权限管理,几个Android版本还不一样。新版本要调用相机拍照与保存,需要动态申请权限,还需要提供Provider才能给Intent传递文件路径,同时,想在getExternalFilesDir()之外创建文件困难重重。最后,为了避免消耗时间太大,只能放弃保存功能。也许在当前Activity中获取到相机数据之后,自己保存到JPG文件还更加方便。
代码仓库,见 android-webview-1
继续阅读→
我从开始学习编程到现在,大部分都是在做与用户界面有关的桌面应用或Web应用,也开发过少量的后端项目。我的第一份工作就是桌面应用开发,工作的时间最长,主要用到C++/JS/HTML/CSS。
桌面应用有它自己的优点:本地数据或文件处理,传感器数据采集,响应快,不需在线,无服务器压力等。日常工作中,我们用得最多的软件就是桌面应用。目前,Electron在开发跨平台的桌面应用很方便,但在性能方面它没有优势。在项目技术选型时,我们需要做更多的考虑。
继续阅读→