软件技术学习笔记

个人博客,记录软件技术与程序员的点点滴滴。

UniApp小程序分包异步化–预告

经过10多天的努力修改UniApp与新增Webpack插件,终于实现ES6语法的JS异步化、Vue组件异步化。

用法如下:

// pkg-b/b.js
const myFunc = async () => {
  const { yourFunc } = await import('@/pkg-a/a.js');
}


// pkg-d/d.vue
// Vue组件经过特殊处理,不需要 import(). 缺点是不兼容h5动态import,后续有空再优化.
import YourComp from '@/pkg-c/c.vue';

export default {
  components: {
    YourComp
  }
}

继续阅读→

React Polyfill ReplaceAll

最近使用Create React App创建一个APP,使用react-app-polyfill/stable完成Polyfill,但是,发现string.replaceAll()函数一直没有polyfill。打开core-js/stable/index.js,发现已经包含了require('../modules/es.string.replace-all')。第一次遇到这种情况,相对懵逼。

经过一番的查阅,最后在babel官网看到一条消息(https://babeljs.io/docs/en/babel-preset-env#corejs):

By default, only polyfills for stable ECMAScript features are injected: if you want to polyfill proposals, you have three different options:

* when using useBuiltIns: "entry", you can directly import a proposal polyfill: import "core-js/proposals/string-replace-all".
继续阅读→

Nginx Log前端上报的错误

使用Nginx搭建前端静态资源服务时,有时想在服务端收集一些前端的严重错误。如果不想搭建或引用其它服务来处理上报的错误日志,可以将简要的错误信息放到HTTP Header中,然后使用Nginx的 $http_xxx 变量打印到 access_log 中。在没有新增其它Nginx模块时,Nginx是无法直接访问HTTP Body中的内容,但是Header中内容可以直接访问。

Nginx配置:

log_format  reportError escape=none  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" '
                      '"$http_fe_href" "$http_fe_error"';

server {
    location = /api/reportError {
        # Methods Limit
        limit_except POST {
          deny all;
        }

        expires epoch;

        ### Log the error
        access_log  /var/log/nginx/access.log  reportError;
        return 200;
    }
}
继续阅读→

vConsole兼容Android与Polyfill

目前,在低版本的Android模拟器中,比较稳定的 vConsole 版本有:3.3.4 与 1.0.x。

vConsole依赖MutationObserver,在Android 4.4及以上版本中不需要Polyfill。但是,在Android 4.3中,需要引入MutationObserver Polyfill,勉强可以打开vConsole,如下:

<link href="https://cdn.bootcdn.net/ajax/libs/normalize/8.0.1/normalize.min.css" rel="stylesheet">
<script crossorigin="anonymous" src="https://polyfill.io/v3/polyfill.min.js?version=3.46.0&features=default%2Ces6%2Ces7%2CMutationObserver"></script>

总的来说,Android 4.3 与 4.4 浏览器之间的差异还是比较大,见 Can I use

继续阅读→

微信小程序插件不适合快速迭代

前段时间,我们开发一款toC的小收据,选择微信小程序插件的方式进行开发。起初的目的是避免主程序过大、容易被别的小程序集成,做新的独立APP时避免重复开发,也选择团队中大部分人熟悉的Taro + React技术栈。

但是,在产品迭代过程中,隔三差五就需要改动这个小收据插件,麻烦就出现了。要发布新功能时,需先插件提审,插件通过之后在主程序中更新插件的版本号,最后才是主程序提审、发布,发布流程漫长。

继续阅读→

SSR超时回退到CSR

去年的时候,为了提升用户首屏显示时间,我们使用React SSR。但是,前段时间用户访问量比较大,发现用户导航之后首屏很久才出来。查看链路追踪,发现后端接口的响应时间远大于平常。

SSR的目的是为了让用户更快地看到内容,但是后端接口超时就白屏很久。为了解决这个问题,在SSR请求后端接口时,也启动一个超时Promise。如果超时先返回,立刻给用户返回CSR HTML模板,确保用户尽快能够看得界面。还没有数据的Loading界面,总比一直白屏好。

继续阅读→

第一个Flutter程序

以前没有真正学过Android或iOS客户端开发,只使用React开发过H5页面,但是H5页面的性能远比不上Native,即使使用React Native也达不到60 FPS。

刚好Flutter可以实现一套代码在Android与iOS上运行,性能是最接近Native。于是参考微信的布局,使用Flutter实现一个Demo:主屏4个页面、一个子页面、网络请求。

继续阅读→

Dart实现一个HTTP服务

这段时间使用Flutter写一个移动客户端,也学习一下Dart语言。Dart语言也是类C高级编程语言,在熟悉C++或Java的基础上,非常容易上手。

Dart也可以写服务端程序,于是写一个小小的后端服务给移动端使用。虽然其性能比不上GoLang、生态系统不及NodeJS,自己学习语法时玩玩也不错。

继续阅读→

NodeJS网络调用链优化

为了提升用户体验,前端首屏使用NodeJS SSR。为了容易观测多个环境NodeJS层的网络调用链与性能,我们加入了Jaeger链路追踪,这也是微服务开发中常用的手段。

通过Jaeger UI观察,我们很容易发现首屏SSR与API转发有以下问题:

  1. 多段接口依次执行,有先后次序依赖,没有发挥并发请求的优势。
  2. 未区分用户类型,有多余的网络请求。
  3. 转发的API请求,也请求多余的用户信息等。

如果使用以前打日志的方式,缺少可视化的分析手段,定位问题的周期比较长。处理以上的问题之后,首屏SSR与API转发的网络性能提升50%,给后端的请求数分别减少3/8与3/4。在并发量比较大的情况下,可以很大程度上减轻服务器的压力。

目前,用户量比较少,在云上后端接口返回在50ms时,首屏SSR可以在100ms内处理完成(不算用户到服务器的网络延时)。这也是我目前性能优化的极限了。

继续阅读→