本网站不收集任何访问者的行为与信息,不做任何商业运作,仅仅为个人使用。闽ICP备17026139号-1

2025

  1. scrollbar-gutter: stable both-edges 有渲染上的 bug,它的本意是让元素的左右边都出现滚动条的宽度,从而保持视觉平衡。但是它的渲染逻辑存在 bug,应该是使用了硬件加速,但是层叠的顺序不对,导致右边会出现一个视觉上的截断,但是 DOM 属性上并没有截断。如图:

    bug

    要绕过这个 BUG,可以强制使用硬件加速渲染,让滚动视图的子元素,全部启用 3D 加速,比如:

    .scrollbar > * {
      /* 3D加速可以顺便解决 scrollbar: both-edges 带来的边缘裁切的BUG */
      transform: translateZ(0);
    }
    

    如图: fixed

  2. 我发现 Solidjs 官方的 examples 页面,居然直接集成了 Chrome DevTools。 它应该是使用了 chii 这个库来实现的。

  3. perchance.org/ai-icon-generator 是一个很好用的完全免费的 AI 图标生成器。 用法是最好先通过它的 ai-text 来生成完整精确的提示词,然后再去生成图标,这样效果会好很多。

  4. 《关于软件编程思路的一点借鉴》 这篇文章总结得很好,很有启发。

    • “软件工程不是编程,它是带有时间维度的编程”。

      这里的“时间”,我更倾向于“成本”这个词。

    • 在“团队领导”这一节,分成了“基层领导”和“大团队领导”,二者一个向下一个向前,都很有启发。

      但我仍然觉得,即便是“大团队领导”,也应该将“向基层工程师学习”纳入自己的成长规划中。这样可以倒逼自己不断蒸馏自己的思维链,避免和至简的大道脱钩。

  5. 发现一个很好用的绘图工具,Excalidraw

    它还能可以快速选择部分内容复制成 svg,因此可以作为一个大的画板来使用。

  6. 简单解构 Iced 运行时模型与设计哲学

    参考资料:

    1. 架构总览:消息驱动的响应式系统

    Iced 的核心架构启发于经典的 Elm 架构(The Elm Architecture)。 通过对界面系统的本质分析,我们可以识别出四个核心组件及其职责:

    • 模型(Model):应用程序的状态
  7. The-Future-Outlook-of-AI-Software-and-Humanity

    最近这段时间一直在思考这个问题。关于未来和人相关的问题,其实本质上都属于哲学的研究范畴。我本人对哲学一无所知,但同样的,我对 AI、对软件、对于人性,也相当的无知。只是在软件开发这个行业,有过一些记忆,仅此而已。 但我还是会使用我局限性的思维思考这个问题、讨论这个话题,这篇文章也是用来与自己对话。

    首先这篇文章并不是要讨论“AI 抢人饭碗”这个问题,因此在文章开头,我直接把这个话题给简单终结掉,我的观点是从三点出发:

    1. AI 会替代人类的工作这是必然的,这是对资本奴役人类劳动力的解放运动。
    2. 人从来不是由工作来定义其价值,相反的,是人类来决定什么是有价值的工作。
    3. 任何前进都是有牺牲的,这本就是人生的一部分。

    归根结底,我也会恐惧某些改变,因为当下的社会是残酷的、是互相踩踏的,哪怕我们都在向前走,但是当下一个相对错误的方向和选择,都有可能导致我们成为他人的脚踏石,这种踩踏是苦痛的,是非人道的,但是它客观发生在生活中的每一个角落。我们会恐惧,也应当恐惧,但也应该笃定,科技改变生活,虽然可能我们坚持不到这一天的到来,但只要确保自己是在这条路上,那便是一种希望,足以支撑人们幸福感的获取。


    接下来,回到文章的话题上来,关于 AI 与软件与人三者的关系。

  8. 一些社会性相关技术的自我讨论

    这篇文章写给自己的文章,是一篇关于“解构与重组”的文章,解构的对象,可能是技术,也可能是我自己。 不论如何,我不想让的阅读者(特别是任何时刻的我)在阅读的时候有太多的心理负担。 所以在此之前,我需要对自己做一个简单的结构,以此做为文章的起点,以确保接下来的文章内容能被阅读者简单明了的理解。 但我写作的风格是跳脱的,我不能确保文章上下文具有常理,哪怕对我来说,是的,它有常理。但这种常理并不适用于所有人。

    首先我是一个记忆力很差的人,这点不是自我贬低,我也从来没有觉得这有什么不好(除了应试教育,但这已经是过去式了)。 而我之所以强调这点,是因为这个基因给我的思维方式带来了巨大的影响。 因为我可以瞬间遗忘自己认为不重要的信息(不论是主观的还是潜意识的),从而让自己时刻处于一种轻装上阵的状态。而对于需要记住的信息,我本能的遗忘让我不得不对这些信息进行一些预处理,以确保能保存在记忆中,因此长期依赖我形成了一种思维习惯,那就是用解构替代记忆:将记忆分解成更多细碎的模式,在需要的回忆的时候,将这些细碎的模式重新组合成记忆本身。而模式本身也是一种记忆,或者某种感受。 这种记忆模式在找代码 BUG 的时候,非常有优势,至少我没有从身边的其它同行中看到过类似的能力水平(当然很大原因是我的圈子很小,并没有接触到足够多优秀的人,所以我到目前为止,并没有觉得这是一个超能力,而只是类似在一个五六十人的班级中,我偏科了,仅此而已)。这种优势体现在,我看到一个模糊的错误信息,就能瞬间感知到错误来源或者范围,然后用二分法做测试,慢慢定位,或者将这个错误分解成更多个小错误。这也导致我带的项目很少去写测试(当然我也在努力改正这个问题,我知道这并不好),更多时候是依赖于我自己的思维能力去定位问题解决问题,其它人遇到问题,只能将问题抛给我去定位。 但这种能力的使用需要我完全的专注,包括我自己写代码的过程中,也一直在使用这种能力,让我一边开发,一边架构。因此我很佩服那些能一边开发一边听小说,一心两用的人,但往往他们的代码会被我否定掉大部分,然后我来重写。 但这种分解对于有逻辑的信息,是有严重的损耗的,特别是遇到复杂的事物,比如人心。也就意味着这种损耗会让我无视掉很多当下重要的信息,但同时,正如内耗无处不在,这些损耗从概率上来说正好抵消了内耗带来的影响,可以让我发现事物底层的脉络。 这并不是说我拥有了预知未来的能力,相反的,这让我客观的意识到未来是不可预知的。 但我不想把篇幅过多的放在“解释为什么”上面,我只想提出一些结论,大部分情况下这些结论只适用于这篇文章的目的短暂存在。 当下的 AI 技术,本质上是一个没有记忆的东西,哪怕它用了巨量的数据去训练。所以我很能感同身受,它所谓的智慧涌现,到底是一个什么玩意儿。

    但不论如何,AI 是一次新的工业革命,它势必会替代人类的工作,也必然会替代人类工作。 但这是一个过程,不是一蹴而就,在这个过程中,政府需要解决人类资源的分配问题。 目前,大部分人使用工作来进行分配,少部分人使用资源来进行分配。 但我说过,我无法确切地预知未来,本质是因为少部分人或者说是少部分利益主体在主导着世界的进程。

  9. 跨平台技术的回顾与展望

    在很久以前,高级编程语言还没出来的时候,硬件和软件其实是深度绑定,定制开发的。 随着高级编程语言的出现,以及操作系统的市场收敛,才有了跨平台开发这个概念的出现。

    再往后,就是 Google 的 Chrome 推出,占领了 Web 技术的话语权,Web、Chrome、Google 三者共同发展了二十年左右,慢慢的,Web 成了高性价比跨平台开发技术的重要选择之一。 直到移动端的出现,除了 Safari(Webkit)这种与原生视图进行了深度绑定,Android 上的 Webview 技术仍然基于独立的绘制引擎,过深的技术路径,也导致了 Webview 技术在 Android 设备上的性能并不够好。当然 IOS 也没好到哪去,但至少它的技术路径使得它更容易做一些优化。再叠加安全防护的问题,导致一些高性能需求的软件,更不可能在 Mobile-Web 上落地,因此移动端上,更多是回归了原生开发或者混合开发(Native 为基础,部分场景使用 Web 或者 Web-Like 的混合开发)。

    这里有必要要谈一下 WASM: 即便现在 WASM 的出现,它也只是画了一个大饼给开发者,但本质上,它们的性能并没有全面超越 js,因为它本质上只是给静态语言提供了一个编译目标,相比编译成 js,编译器的输出与 wasm 的指令更加贴近。但相比直接在 js 上开发,js 的性能和 wasm 的性能并没有太多差距,即便是一些算法相关的层面也是如此。目前 WASM 相关的大量提案还在逐步跟进,但是进展相对缓慢,但本质上它的意义只是能让其它编程语言不需要生产 js,而是直接编译成 wasm,从而进行 Web 开发。因此 WASM 并不是完全取代 JS,只能说给 Web 生态提供了更多的可能。 但在画了饼中,WASM 加入了一些更接近硬件的指令集,所以它的未来,至少在一些并行计算方面是可以超越 JS 的,当然这部分的工作更可能会被 WebGPU 给取代。 不过,WASM 有一个 JS 无法取代的优势,就是关于多线程的提案,它会比 WebWorker 更加的底层,具有更多的优化潜力。并且目前多核设备已经是标配,所以未来 WASM 可能真的会依靠多线程技术,取代 JS 开发的一些场景(在开发成本基本不变的基础上,提升应用性能)。

    因为 Mobile-Web 客观的阻碍,所以跨平台开发,更多的变成了 Android+IOS+Desktop 这样的概念。 不过,在 Web 技术的发展的过程中,给开发者带来了一系列的开发工具套件,这些工具使得 Web 开发的体验远超任何其它编程语言的体验。这也就导致了即便 Web 性能上限不佳或者说难以优化,但是它的开发成本极低,迭代速度极快,仍然成立很多产品的选择方向,或者是魔改的方向,当然,也可能是“发展”的方向。 国内厂商大多选择“魔改”,其实“魔改”和“发展”,其实就在于它的开放程度与簇拥程度。你只要足够的开放,并且吸纳社区的建议,那么就是“发展”,否则通常会被人们嘲弄成“KPI 项目”。因此哪怕国内其实有很多厂商在做类似的发展,哪怕也开源了,但是没有和全球开发者接轨,没有听取他们的意见,仍然以自家开发者和产品需求为基础去推进项目,那么难免不被嘲讽。 这里举一些正向的发展例子,比如:react-native、ark-ui。 先说 react-native,它算是在 Web 的生态和标准上发展起来的,首先它由 react 的声明式的开发所孵化,引入了 jsx 语法,颠覆了过往布局文件和控制代码拆分开的模式。这也启发了一个全新的 UI 开发纪元,可以看到后来的 flutter、compose、swiftui、ark-ui 都是类似的开发方案。它的工作原理非常的聪明,是一种生成器的运作模式,以至于它的渲染性能可以优化得非常彻底。虽然它在 Web 上性能并不怎么样,这是因为 Web-DOM 所提供的接口是命令式的接口,但是在原生平台上,绘制本身就是一个只需不断的循环程序,加持上编程语言的优化,它的性能潜力非常巨大的,因此各家操作系统厂商都选择这个长远的方案。 现在 react-native 发展到了一定的程度,开始了 react-strict-dom 的发展,可以说它在做一种 mini-web 的标准:提取了 Web 的主要技术标准,做为一个现代 UI 开发的最小标准,将它移至到 Android/IOS 平台上。这样引擎标准将会更加干净通用,从而为跨平台提供了更多的可能性,未来新的原生平台,只需要根据这个小标准集合进行适配即可。这点本质上也是在解决我前文提到的 Mobile-Web 的痛点:过剩的技术路径,导致难以优化。现在有了 react-strict-dom,似乎这样的 Web 又可以作为一个跨平台标准了。 说完 react-native,再说 dart+flutter,它和 Web 平台有很深的渊源。首先是 dart 语言一开始是要更 typescript 做竞争的,所以本身它和 js 语言就非常的相似,再者是它的定位实在根 ts 太像了,引入了类型安全。不同的是,dart 有自己的 runtime,当初 chrome 甚至尝试直接集成了 dart-runtime,同时 v8 共存,想解决 js 的语言问题导致的性能瓶颈,且不说是否存在垄断的嫌疑,至少 WASM 是一个更加开放且更具长远未来的选择,因为大家知道,性能问题并不能通过某一个编程语言来解决,像 WASM 这种提供底层指令集,是一种更加彻底的解决方案。 为此,dart 被 chrome 抛弃后,这个项目几乎就快要结束了,这时候 flutter 这个项目拯救了它,因为恰好 flutter 需要一个跨平台的编程语言,索性把 dart 语言团队拉进来,一同发展 flutter。一开始 flutter 的底层是 skia,所以 flutter+dart,你可以类比成 html-canvas+js,只不过 flutter+dart 的技术路径更加清澈,所以当然不会有 html-canvas+js 的障碍,性能问题直接上 C++来解决。并且因为它开箱即用的 Weight 组件,以及和 js 相似的语法,使得大家对它的接受度出奇的高。几年下来,逐渐就发展成了一个跨平台开发的强力工具。现在它在 Web 上的渲染性能越来越好,当然这也是依赖 WASM 的发展,是的 dart 语言能编译成 wasm 而不是 js,从而获得更高的性能。渲染层面也从原来的 skia 发展成了现在的 impeller(目前支持 Android/iOS/Desktop,未来也会加入对 WebGPU 的支持)。 再有就是 ark-ui,它进一步糅合了 dart、swiftui、kotlin,直接在 ts 语法上进一步改造。它直接把 ts 当 dart 用,用自己的方舟引擎替代 dart-runtime。同时它的 API 设计,也是大量参考了 Web-API 的安全考虑。

2024

  1. 以华为的技术储备,做一款替代AR1的芯片和对应的产品,应该可以非常具有颠覆性的竞争力。25年相关的新技术也都可以量产了

  2. Publishing Your Deno Project as a Monorepo using dnt

    Publishing Your Deno Project as a Monorepo using dnt

    Before providing theoretical guidance, let's look at how to achieve this in practice. After completion, I will explain the advantages of this project management solution.

    Tools

    1. deno
    2. pnpm

    Preparation

    1. Create your project:
      deno init dnt-mono
      # cd dnt-mono
      # code . # open in ide
      
    2. Initialize a git repository
  3. 使用 dnt 将你的 deno 项目发布成 monorepo 风格

    使用 dnt 将你的 deno 项目发布成 monorepo 风格

    在提供理论指导之前,我们先看具体的实践如何做到,完成后,我再说明这种项目管理方案的优势在哪里。

    工具

    1. deno
    2. pnpm

    准备工作

    1. 创建你的项目:
      deno init dnt-mono
      # cd dnt-mono
      # code . # open in ide
      
    2. 初始化 git 仓库
  4. MutableSharedFlow 随记

    MutableSharedFlow 作为一个建立在 Flow 基础上的设计,它的 Shared 特性其实与 Flow 的 collect 有着设计上的冲突。 因为 Shared 特性,它的 emit 与它的订阅者有关系,订阅者的消费速度决定着它的发射速度。然而如果没有消费者,就意味着它的 emit 会直接丢失,而没有被消费到。 举个例子:

    val sharedFlow = MutableSharedFlow<Int>();
    launch {
        sharedFlow.collect {
            println(it) // 这里通常不会有任何打印
        }
    }
    sharedFlow.emit(1)
    

    因为 launch 的执行需要时间,在这段时间里,emit 可能已经执行完毕了,从而导致发射的值没有被任何人消费从而丢失。 这对于将 MutableSharedFlow 直接作为 EventEmitter 的替代者来说,会是一个很严重的设计缺陷。


2023

  1. 我发现浏览器有一个很离谱的 BUG,我不知道它是出于什么原因

    import { a } from "http:/127.0.0.1:8000/test.mjs";
    console.log(a);
    

    这个协议头不规范,居然能宽容地正确解析出来。 也就意味着在浏览器中,new URL("https:/qaq.dweb/index.ts") 能被合法解析成 new URL("https://qaq.dweb/index.ts"):

    这个 bug,可以带来一个玩法。我可以利用这个 bug,用 node 实现类似 deno 的功能。因为 deno 近乎是完全使用浏览器的标准,所以说浏览器上面的这个 bug,在 deno 中同样也会有,也同样适用…… 在 nodejs 项目里,只需要在 node_modules 里头创建一个 https: 的文件夹。它完全不会报错,可以正确解析。

    比如说以下 deno 代码:

    import { Server } from "https:/deno.land/std@0.187.0/http/server.ts"; // 这里使用单斜杆,也会被认为是双斜杠
    

    然后同样的代码,在 nodejs 项目中,不启用 deno,只添加一个 tsconfig.json,使用 ts5+ 来实现 .ts 文件后缀的支持

    // tsconfig.json
    {
      "compilerOptions": {
        "target": "ES2020",
        "module": "ESNext",
        "moduleResolution": "bundler",
        "allowImportingTsExtensions": true,
        "esModuleInterop": true,
        "forceConsistentCasingInFileNames": true,
        "strict": true,
        "skipLibCheck": true
      }
    }
    

    最终效果如下图:

  2. 这是社区的讨论:Add onclose event to MessagePort #1766 当初我提到一个垫片方案,那时是 2020 年,所以当初只有 chrome69+的内核能支持:

    /// worker
    const lockReqId = "process-live-" + Date.now() + Math.random();
    navigator.locks.request(lockReqId, () => new Promise(() => {}));
    postMessage(lockReqId);
    
    /// master
    worker.addEventListener("message", (me) => {
      if (typeof me.data === "string" && me.data.startsWith("process-live-")) {
        navigator.locks.request(me.data, () => {
          worker.dispatchEvent(new CloseEvent("close"));
        });
      }
    });
    

    现在已经普遍支持

    caniuse-locks

  3. Web Design Principles 这篇文章提供了 Web 平台的接口设计最佳实践

2022

  1. 在本机配置 CNAME

    1. 安装 dnsmasq

      sudo apt-get install dnsmasq
      
    2. 配置 dnsmasq

      vi /etc/dnsmasq.d/test.conf # 随便开一个文件
      

      填入:

      cname=from.gaubee.com,to.gaubee.com
      
    3. 修改本地 dns 配置:

  2. 基于AsyncIterator的响应式编程

    最近在重新思考响应式编程的一些事情,其实我很少使用 RxJS,往往是直接手撸各种异步策略。 因为我自己是更加倾向于使用原生的 async-await/generaor 来实现。因为会有更好的调式支持,性能也会更好。但可维护性可能就不一定,如果没有好好封装,别人读代码的时候,就会比较晦涩。 虽然 RxJS 在开始的时候也是晦涩,但是至少他们的高级的概念能够很好的复用。 而像我这种直接手撸的就往往是按照需求来进行编程,阅读者如果对需求没有足够的理解,那这种代码的可维护性可以说是相对比较低的。

    但最近有打算把 RxJS 的一些常见概念和我自己的经验结合起来,写一个基于异步迭代器的响应式编程的库。 这篇文章就简单的讲一下这个库里头涉及到的一些有趣的经验点。

    首先就是我异步编程时最常使用的 PromiseOut,它是对 promise 的再封装

    class PromiseOut<T> {
      resolve: Function;
      reject: Function;
      promise = new Promise<T>((resolve, reject) => {
        this.resolve = resolve;
        this.reject = reject;
      });
    }
    

2021

  1. 尝试 Deploy to GitHub Pages

  2. Event模块是用于快速记录一些小事件。比如一些想法;一些值得分享的链接;一些图片等等

  3. Web 未来技术猜想(一)

    对于近十年来 Web 技术的高速发展,很有多精彩的概念与设计涌现出来,但也有很多设计是建立在历史 Web 技术的架构上。

    这间接地导致了浏览器的开发越来越难,现在还存活的浏览器内核也就只剩下 Webkit 和 Blink 了(Firefix 的 Servo 份额实在太小了,开发进度也实在缓慢)……

    即便这两个内核的代码都是开源的,但并不意味着“不垄断”,Web 技术再这样发展下去,只会制造出越来越高的技术壁垒。因为开源并不意味着自由,技术标准的话语权还是掌握在别人手里,你想贡献代码,还得看社区是否“有时间”去接纳,还得有大量的条条框框在限制着你,而反观 Chrome 团队,它们则是能肆无忌惮地往 Chrome 中添加各种实验性功能。从技术层面上来说,技术人的贡献固然是令人尊敬值得肯定,但从资本的层面上来说,这些新技术的堆在这般的堆砌,制造技术壁垒、掌握标准话语权,不正是垄断牟利的老套路吗?

    我这里大胆预测一下,未来 Web 技术一定带来突变。 或者说这不是预测,是我个人假设要去从头设计一个浏览器,我应该怎么去做。宏观上会分成两大种类的模块来开发:

    第一种是功能性模块

    比如蓝牙模块、HTTP1/2/3 协议模块、USB 模块、摄像头模块等等。对此可以理解成“驱动模块”,但不同的是,驱动模块目的只是将硬件被操作系统的接口所认知,功能性模块还加入了隐私保护的概念,所有的行为对于使用者来说必须是公开透明的。这不是单纯做好“功能授权”与“信息流向透明”就能解决的问题,还是确保用户的身份不被追踪,用户的偏好不被预测等等。 这类模块由两部分组成:一部分是“原子接口”,一部分是“应用接口”。

    1. 其中“原子接口”只能由操作系统提供,类似于操作系统的 API,但是要符合上文所提到的 Web 的隐私安全性的定义。

      Web 开发者可以直接在网页上进行使用 WASM/JS 围绕“原子接口”进行开发。

      比如说摄像头模块的原子接口,可以做到对相机预览功能的二次开发,或者直接拿到 YUV、RGB、RAW 等格式进行处理等等。但现实情况是,每一个物理硬件都有它的特性,我们只能说这些硬件在出厂的时候通过了可用性的测试,但并无法保证所有的硬件都是一致的,所以我们往往需要加入一个理想数据模型,来结合实际硬件的情况,加入一定的偏移与噪点来消除误差,这其实是需要硬件厂商和系统驱动要去解决的问题。

    2. 其次“应用接口”是基于“原子接口”开发出来的应用。首先操作系统会提供一套默认的“应用接口”,正因为将浏览器的开发成本嫁接到操作系统上,并将之模块化,才有可能将浏览器的开发成本大大降低。
  4. CSS“文字”渐变,一种比background-clip通用性更好的方案,可以用于SVG中(CSS svg icon gradients, a more versatile solution than background-clip)

    示例 Demo

    SOME TEXT
    背景色 Background Color