Skip to content

202305

INFO

五月了,还不知道路在哪儿? 要做长久打算!

  • 20230214

0504

  • 建立中提及的东西不能一问三不知,需要多复习下
  • 了解 rollup/vite 打包构建流程以及相关 plugin 插件,这个都忘得差不多了 了解 babel 编译原理, 了解 postcss 编译原理,实践实践
js
const postcssFocus = require("postcss-focus");
const postcss = require("postcss");
const fs = require("fs");
// 输入的 css 文件地址
const from = "src/a.css";
const to = "output/a.css";

fs.readFile(from, (err, css) => {
  postcss(postcssFocus)
    .process(css, { from, to })
    .then((result) => {
      console.log(result.css);
    });
});

postcss plugin 模板

js
module.exports = (opts = {}) => {
  // Plugin creator to check options or prepare caches
  return {
    postcssPlugin: "PLUGIN NAME",
    // Plugin listeners
    Once(root) {
      // Calls once per file, since every file has single Root
    },
    Declaration(decl) {
      // All declaration nodes
    },
  };
};
module.exports.postcss = true;

nextjs 中的 getServerSideProps/getStaticProps 怎么实现的,如何才能实现

  • tailwindcss 是如何运行起来的,如果让你设计一个怎么实现

yalc:Yalc 完美模拟了正式发包装包的流程。可以将本地构建好的包发布到本地全局的 .yalc 文件夹下,也可以将发布在本地的包安装到本地的任何一个项目里。

使用过程:

1.发布本地 npm 包(npm 包根目录下执行)yalc publish --push

2.项目本地包(项目根目录下执行) yalc add myPackage

3.项目本地包更新,执行 yalc update

4.项目删除 npm 包,执行 yalc remove --all

静态分析:静态分析不会运行代码,而是通过编译的方式来分析源代码。它的目的不是为了生成目标代码,而是为了提取一些想要的信息,这是和编译的不同之处。

0505

webpack 打包流程

  • npm run build 命令也是通过环境变量调用 bin 脚本去调用 Node Api 去执行编译打包。

  • 手写 Nodejs 中的 EventEmitter Api

js
class EventEmitter {
  constructor() {
    this.events = {};
  }
  // on 订阅
  on(name, cb) {
    const cbs = this.events[name] || [];
    cbs.push(cb);
    this.events[name] = cbs;
  }
  // emit 执行
  emit(name, ...arg) {
    const cbs = this.events[name] || [];
    cbs.forEach((cb) => cb.apply(this, arg));
  }
  // off 取消订阅
  off(name, cb) {
    if (!this.events[name]) return false;
    const cbs = this.events[name] || [];
    const newCbs = cbs.filter((fn) => fn !== cb);
    this.events[name] = newCbs;
  }
  // once单次执行
  once(name, cb) {
    function one(...arg) {
      cb(...arg);
      this.off(name, one);
    }
    this.on(name, one);
  }
}

0506

  • pm2 start app.js -i max // 启动进程的时候加上 -i num 就是启动 num 个进程做负载均衡的意思
  • pm2 start app.js --max-memory-restart 1K // 指定 1k 内存就重启:
  • pm2 start app.js --watch // 当文件内容改变自动重启:

tailwindcss 核心代码

js
import setupTrackingContext from "./lib/setupTrackingContext";
import processTailwindFeatures from "./processTailwindFeatures";
import { findAtConfigPath } from "./lib/findAtConfigPath";

module.exports = function tailwindcss(configOrPath) {
  return {
    postcssPlugin: "tailwindcss",
    plugins: [
      function (root, result) {
        // Use the path for the `@config` directive if it exists, otherwise use the
        // path for the file being processed
        configOrPath = findAtConfigPath(root, result) ?? configOrPath;

        let context = setupTrackingContext(configOrPath);

        if (root.type === "document") {
          let roots = root.nodes.filter((node) => node.type === "root");

          for (const root of roots) {
            if (root.type === "root") {
              processTailwindFeatures(context)(root, result);
            }
          }
          return;
        }

        processTailwindFeatures(context)(root, result);
      },
    ].filter(Boolean),
  };
};
module.exports.postcss = true;

三个重要方法 findAtConfigPath / setupTrackingContext / processTailwindFeatures

0507

躺平,确定了结婚当天摄影师

0508

JIT“捆绑”了一些更灵活的写法:

html
<!-- 支持任意值 -->
<button class="bg-[#1da1f1]">button</button>

<!-- 内置重要修饰符 !important-->
<p class="font-bold !font-medium">
  This will be medium even though bold comes later in the CSS.
</p>

<!-- 可堆叠变体 -->
<button class="md:dark:disabled:focus:hover:bg-gray-400">
  <!-- 颜色/不透明度简写 -->
  <div class="bg-red-500/25"></div>
</button>

tailwindcss 中的 group 和 group-hover 组合

html
<a
  href="/post"
  className="dark:text-darkPrimary 
            relative font-bold text-3xl w-full h-10 inline-block text-center mx-0 
            group 
            underline
            overflow-hidden text-orange-300
            "
>
  <span
    className="font-bold absolute left-0 top-0 inline-block w-full h-10 text-3xl
              overflow-hidden
              translate-x-[-100%]
              transition-transform
              duration-700
              before:inline-block
              before:content-[attr(data-content)]
              before:w-full
              before:text-blue-700
              dark:before:text-red-700
              before:underline
              before:translate-x-[100%]
              before:transition-transform
              before:duration-700
              group-hover:translate-x-0
              group-hover:before:translate-x-0
              "
    data-content="{`${title}`}"
  ></span>
  {title}
</a>

0509

  • 正如肖申克的救赎中所说的:“这些墙很有趣。刚入狱的时候,你痛恨周围的高墙,慢慢地,你习惯了生活在其中;最终你会发现自己不得不依靠它而生存,这就叫体制化”。只不过在体制内的是无形的精神高墙。

  • useEvent 源码,主要应用场景:封装事件处理函数

useEvent 有俩个特性:

  • 在组件多次 render 时保持引用一致
  • 函数内始终能获取到最新的 props 与 state
tsx
import { useRef, useLayoutEffect, useCallback } from "react";

const useEvent = (handler: any) => {
  const handleRef = useRef();
  useLayoutEffect(() => {
    handleRef.current = handler;
  });
  return useCallback((...args: []) => {
    handleRef && (handleRef as any).current(...args);
  }, []);
};
export default useEvent;

Signal:更多前端框架的选择

Vue、Solid.js、Preact、Svelte 都已实现Signal。实际上,signal 并不是一个新概念,他还有很多别名,比如:

  • 响应式更新
  • 细粒度更新

React 的理念可以用一句话概括:「UI 反映状态在某一刻的快照」。

既然是快照,那就不是局部的,而是个整体概念。在 React 中,状态更新会引起整个应用重新 render,就是对 React 快照理念的最好诠释。

Qwik vs React 中的 ssr

都是卡颂老师写的,强烈推荐

主流前端框架都支持 SSR,但不管是 React、Vue 还是 Angular,他们都是 CSR(客户端渲染)优先。在这些框架中,SSR 是在 CSR 的基础上附加的新功能。 传统前端框架都是「CSR 优先」的产物,才导致一些常见 SSR 问题,比如:

  • 首屏渲染时,页面短时间无法响应交互,因为此时框架还未 hydrate 水合 完成
  • 即使仅有部分内容需要交互,但整个页面还得全量 hydrate 水合 这些问题拉低了 SSR 场景下的 FCP[1](First Contentful Paint 首屏内容绘制)与 TTI[2]指标(time to interactive 首次可交互时间)。

SSR 场景下 hydrate 的流程,包括 4 个步骤,只有在整个流程完成后应用才能响应交互:

1.下载 HTML 2.下载所有 JS 文件 3.解析、执行 JS 文件(主要是框架及其依赖,还有业务逻辑代码)4.绑定事件(即 hydrate 操作)

Qwik 框架中 Resumable(可复用)技术的设计理念 —— HTML 优先,JS 按需下载: 要实现 Resumable,需要抛弃传统框架以 CSR 为基础(用 JS 生成 HTML 为主)的思路,转而以 SSR 为基础(以服务端生成 HTML 为主),再在此基础上附加 CSR 功能。

这项技术之所以叫 Resumable(恢复),是因为它与传统Hydration 技术在首屏渲染时客户端逻辑的区别。

传统 Hydration 技术在首屏渲染时,客户端(比如浏览器)会全量执行框架代码与业务逻辑代码,并在此过程中完成:

  • 框架组件对应的树状数据结构初始化(比如在 React 中叫 Fiber 树,在 Vue 中叫 VNode 树)

  • 组件内状态初始化

  • 事件绑定

react hooks 闭包陷进,面试者常考的

js
import { useEffect, useState } from "react";

function Dong() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const timer = setInterval(() => {
      setCount(count + 1);
    }, 500);
    return () => clearInterval(timer);
  }, [count]);

  useEffect(() => {
    const timer = setInterval(() => {
      console.log(count);
    }, 500);
    return () => clearInterval(timer);
  }, [count]);

  return <div>guang</div>;
}

export default Dong;

每次执行新的函数之前会把上次设置的定时器清掉

闭包陷阱产生的原因就是 useEffect 等 hook 里用到了某个 state,但是没有加到 deps 数组里,这样导致 state 变了却没有执行新传入的函数,依然引用的之前的 state。

闭包陷阱的解决也很简单,正确设置 deps 数组就可以了,这样每次用到的 state 变了就会执行新函数,引用新的 state。不过还要注意要清理下上次的定时器、事件监听器等。

0510

0511

  • nba 比赛看的胆战心惊,可能作为球迷太想赢了,没有好好享受看球的乐趣,接下来减少看球时间投入,重新转移注意力

是 js 的加载阻塞了页面的渲染还是 js 的执行阻塞了页面的渲染?

在浏览器接收到一个 HTML 文档时,粗糙的来说会经历一个所谓叫做**关键渲染路径(crp)**的步骤,最终将我们的文档渲染到页面上。

关键渲染路径包含了五个步骤, 1.构造文档对象模型(DOM),2.构造 CSS 对象模型(CSSOM),3.生成渲染树、4.布局以及 5.绘制。 Js 引擎线程负责 JavaScript 代码的解析和执行,而渲染线程则负责具体页面的解析和渲染(比如上述的 HTML Parse 过程)。再简单来说,Js 引擎线程和渲染线程这两者是互斥的。当 HTML 下载时,Parse HTML (上述关键渲染路径中生成 DomTree)的过程如果碰到 JS 脚本是会停止后续 Dom 的解析的。

网络上绝大多数文章都是片面的告诉你结论: JS 会阻塞页面渲染,不过结果真的是这样吗?

首先,在 HTML 加载 JavaScript 存在两种方式,一种为内敛脚本也就是直接将 JS 写在 HTML 中,另一个中称为外部资源,也就通过 script 脚本加载的外部资源。另外 JavaScript 产生的阻塞,指的是加载(DownLoad)Js 文件时,还是执行 Js 文件时这又是另一个话题。

内敛 JS:

你把内联脚本放在哪里都是会阻塞页面的渲染,不过是放在底部在脚本中可以拿到内存中已经构造好的 Dom 节点进行 Dom 操作而已。

外部 JS:

外链资源会阻塞页面渲染吗?首先,外部 JS 资源的确可能会阻塞页面的渲染,不过这也是分情况而论。无论是 JS 资源的加载和执行,我们有一个明确的前提:当 Parse Html 的过程中如果碰到外部 JS 脚本,那么外链脚本的确是会停止解析后续 Dom 的,但是停止解析后续 Dom 并不意味着一定会阻塞页面的渲染。

外部脚本链接的加载和执行只会影响后续 Dom 的解析和渲染,对于脚本之前的的 Dom 并不会阻塞它的解析以及渲染,这也就是为什么我们常说将 js 放在底部

defer: 这个布尔属性被设定用来通知浏览器该脚本将在文档完成解析后,触发 DOMContentLoaded 事件前执行。 有 defer 属性的脚本会阻止 DOMContentLoaded 事件,直到脚本被加载并且解析完成

0512

  • 15 年前今天,汶川地震,当年我还在海头中学读高一,谁道想到 15 年后我是这个鬼样子,在预想下,15 年之后自己又将在何方,过着什么样的日子

  • 雷军:你经历的所有的挫折和失败,甚至那些看似毫无意义消磨时间的事情,都将成为你最重要的、最宝贵的财富。

  • 在 cookie 中设置了 HttpOnly 属性,那么通过 js 脚本将无法读取到 cookie 信息,这样能有效的防止 XSS 攻击。

  • XMLHttpRequest.withCredentials 属性是一个布尔值,它指示了是否该使用类似 cookie、Authorization 标头或者 TLS 客户端证书等凭据进行跨站点访问控制(Acess-Control)请求。设置 withCredentials 对同源请求是无效的。

js
const xhr = new XMLHttpRequest();
xhr.open("GET", "http://example.com/", true);
xhr.withCredentials = true;
xhr.send(null);

0513/0514

买电动车,看房子,再一次搬家,希望这次能住的久一点,搬完最后一次,想回去了 爱萌

0515

  • 有一位大佬离开左耳朵耗子,大佬名言: 我相信技术。我相信技术是一定会让人失业。

0516

0517

  • 玉兰香苑原始主卧带独卫,有燃气厨房,预算 2500 左右
  • 就业形势越来越严峻,必须要先保住目前的工作,还有就是房贷还需要提前,本来是打算 3 年,现在还掉感觉越来越远了,差距太大

0518

  • 确定要租的房子,租期是 2023/03-2024/03,不知道未来一年将会发生什么,为啥会这么穷
  • 身体大不如前,溃疡不断,修养生息为主,尽量消除一切娱乐形式
  • 就业环境让自己有点焦虑,焦虑的同时,自己又没能去做足准备

0519/0520/0521

  • 搬家浴火重生,开启新的一段漂泊旅程,预期是 2026 年
  • 算法和源码还是不能遗漏,需要重新捡起来
  • 个人博客需要在努力最后一把,把二级域名整合

0522

人生在世,总有各种不如意,努力就好,事在人为。比赛输了就输了,至少已经绝望过。我现在需要做的就是提前几年还完房贷,能尽早还就尽早还,早点摆脱房贷,当还完房贷的那一刻,人生才是快乐的,才是幸福的。怎样才能摆脱呢,急死了!!

0523

  • 房贷焦虑不能太大,只能说接受现实,打磨自身技术
  • 2.5+1
  • 还热爱前端吗?如果热爱,要对得起这份热爱

0524

  • 预约 0822 提前还款,一定要在 0822 前保持足够的现金流,如果没有提前一天撤销预约。到现在 6 7 8 还有 3 个月
  • useMemo 和 useCallback 区别
js
React.useCallback(function helloWorld() {}, []);

// ...功能相当于:
React.useMemo(() => function helloWorld() {}, []);

useCallback 的用途与 useMemo 相同,但它是专门为函数构建的。我们直接给返回它一个函数,它会记住这个函数,在渲染之间线程化它。

react 版的图片懒加载

js
  const ObserverRef = useRef(
    env.isClient &&
      new IntersectionObserver(
        (entries) => {
          entries.forEach((entry) => {
            const { target, intersectionRatio } = entry;
            // target 为具体的 dom
            // intersectionRatio 范围为 0 ~ 1, 0 为完全不可见, 1 为完全可见
            // 因此只需判断当 intersectionRatio 大于 0 即可
            if (intersectionRatio > 0) {
              const _target = target as HTMLImageElement;
              _target.src = _target.dataset.src ?? "";
              _target.onload = () => {
                _target.style.opacity = "1";
              };
              ObserverRef.current && ObserverRef.current.unobserve(_target);
            }
          });
        }
      )
  );
  useEffect(() => {
    const exposeRef = ObserverRef.current;
    // img设置data-src属性
    if (document.querySelectorAll("[data-src]") && exposeRef) {
      Array.from(document.querySelectorAll("[data-src]")).forEach((img) => {
        if (img) {
          exposeRef.observe(img);
        }
      });
    }
    return () => {
      exposeRef && exposeRef.disconnect();
    };
  }, []);

0525

  • 对于不真诚的人,任何事的决定都要三思后行,特别对于时间这块,要留有余地。
  • 以前总会觉得自己想干就能干成,现在不一样了,必须向现实低头。为啥要把还贷的压力给亲人呢,自己默默承担就好

nextjs 中如何使用数据流方案,主要思路应该是在服务端预取数据存到仓库,然后页面直出的时候,客户端渲染也能拿到数据

Next.js 中 Redux 使用方案和 wrapper 概念

如何把服务端存储的数据传递给客户端 首先,我们需要弄清楚几个问题:我们为什么需要在服务端请求数据后再把数据传递给客户端? 这个问题比较重要,这也是服务端使用 redux 的意义。 一般我们使用 redux 是为了存储一些共享状态,比如:

  • 应用公共状态:比如应用全局信息、用户基础信息、用户权限信息等等
  • 复杂页面状态:页面复杂度较高时,在深层次子组件需要用到的页面的信息

而服务端使用 redux 的原因:一般在于服务端渲染页面内容时依赖前面描述的的状态,这样就导致这部分信息需要在服务端进行请求初始化,然后存储到 redux 中,页面渲染后,可以直接获取到这部分信息,而不是再去请求一次接口。

Next.js 本身服务端传递数据到客户端的方式是把 Next.js 数据获取 方法的返回值注入到 **window.NEXT_DATA** 属性里。 而 **next-redux-wrappe** 的 wrapper 通过包裹 Next.js 数据获取 方法,也可以在其包裹函数内部对返回值进一步注入 redux 数据。

  • 《悠长假期》里有句台词:人生不如意的时候,是上帝给的长假,这时候应该好好享受假期。突然有一天假期结束,时来运转,人生才是真正开始了

0526

  • 618/818/1111 存酒的好时机,首选:五粮液浓香型白酒第八代普五 52 度 500ml 1765.75 元,单瓶 883 元,再者就是 汾酒青花 20,一箱 2671/6 = 445

0527/28

  • 周末在家躺平,看了一部权谋电视剧《庆余年》,不想谈看完感受,只想说看电视身体太累了,身体想休息,两者矛盾,马上要拍婚纱照了,最近还是以修身养性为主。
  • 总是被外界各种繁杂所吵,失了心境,不知道如何是好
  • 自从五一回来之后就没怎么静下心来学习,罪过

0529

  • DDos 攻击是什么,有哪些方式 DDoS(Distributed Denial of Service)分布式拒绝攻击,攻击是指利用多个计算机发起协同攻击,使目标服务器无法正常响应或处理请求的攻击方式。根据攻击的方式和手段,DDoS 攻击可以分成以下几种类型:

SYN Flood 攻击(泛洪攻击):攻击者向目标服务器不断发送大量的 SYN 请求,但不完成三次握手过程,从而导致服务器资源耗尽,无法响应正常请求。

UDP Flood 攻击:攻击者向目标服务器发送大量的 UDP 数据包,从而占满服务器带宽,使得合法请求无法得到响应。

HTTP Flood 攻击:攻击者模拟大量的 HTTP 请求,向目标服务器发送大量的 HTTP GET 或 POST 请求,从而消耗服务器资源,使其无法响应正常请求。

  • @reduxjs/toolkit

0530

  • 昨晚一觉睡的不错,算是一种长时间得到休息
  • 练习 ts 体操

Unique 去重

ts
type Res = Unique<[1, 1, 2, 2, 3, 3]>; // expected to be [1, 2, 3]
type Unique<T, R extends unknown[] = []> = T extends [infer F, ...infer Rest]
  ? Include<Rest, F> extends true
    ? Unique<Rest, R>
    : Unique<Rest, [...R, F]>
  : R;
// 数组中是否包含某一项
type Include<Arr, Val> = Arr extends [infer F, ...infer Rest]
  ? Equal<F, Val> extends true
    ? true
    : Include<Rest, Val>
  : false;

type Equal<A, B> = (<T>() => T extends A ? 1 : 2) extends <T>() => T extends B
  ? 1
  : 2
  ? true
  : false;
type T1 = Equal<1, 1>;
type T2 = Equal<any, 1>;
type T3 = Equal<unknown, any>; // false

type T4 = Include<[1, 2, 3], 1>;

精读《我们为何弃用 css-in-js》

未来全栈框架会卷的方向

  • 房屋出租信息如果能整合,只做房屋租赁,信息分散,豆瓣小组也被各种中介占据

今天务必把自己的个人博客网站部署完毕

设置 output: export 阔以输出静态文件,通过 nginx 配置即可访问,但是现在访问其他路径不行了?另辟蹊径,通过设置子域名来解决访问 xx.com/love 路径不通问题

js
http {
server {
        # 个人博客
        location / {
        index index.html index.htm;
        try_files $uri $uri/ /index.html /learn/ /love;
        }
·
        # 个人生活
        location  /love {
            root /www/web/;
            index  index.html index.htm;
            gzip on;
            try_files $uri $uri/ /index.html;
        }
        # 个人学习
        location  /learn {
            alias /www/web/learn;
            index  index.html index.htm;
            #error_page  /wx/index.html;
            if (!-e $request_filename) {
                rewrite ^/(.*) /learn/index.html last;
               break;
            }
            try_files $uri $uri/ /index.html;
        }
    }
}
ts
http {
  server {
          listen       80;                   #监听的端口
          server_name  love.bythewayer.com;
          root /www/web/love;
          #修改反向代理地址
          location / {
              index  index.html index.htm;
              gzip on;
              # 启用gzip压缩的最小文件,小于设置值的文件将不会压缩
              gzip_min_length 1k;

              # gzip 压缩级别,1-9,数字越大压缩的越好,也越占用CPU时间,后面会有详细说明
              gzip_comp_level 2;

              # 进行压缩的文件类型。javascript有多种形式,后面的图片压缩不需要的可以自行删除
              gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;

              # 是否在http header中添加Vary: Accept-Encoding,建议开启
              gzip_vary on;

              # 设置压缩所需要的缓冲区大小
              gzip_buffers 4 16k;
              try_files $uri $uri/ /index.html;
          }
  }
}

0531

  • 每日一练 TS,生成指定长度的 tuple
ts
type result = ConstructTuple<2>; // expect to be [unknown, unkonwn]
type ConstructTuple<
  L extends number,
  V extends unknown = unknown,
  Arr extends unknown[] = []
> = Arr["length"] extends L ? Arr : ConstructTuple<L, V, [V, ...Arr]>;
type TP31 = ConstructTuple<3>;
// type TP31 = [unknown, unknown, unknown]

设置二级域名,通过自定义创建 DNS Host即可拥有

多个子级域名,比如 http://love.bythewayer.com or http://learn.bythewayer.com

dnshost