Skip to main content

2 posts tagged with "NextJS"

View All Tags

· 10 min read
加菲猫

📒 Golang 模拟 JS 的 Promise

https://www.bilibili.com/video/BV11v411h7t5

📒 Golang 如何通过 WebAssembly 调用 JS API

https://github.com/elliotforbes/go-webassembly-framework

📒 「目前全网唯一&2万字长文」从JS上下文到Chromium源码的极限拉扯!!兄弟姐妹们接好了!!

📒 浅谈 Vite 2.0 原理,依赖预编译,插件机制是如何兼容 Rollup 的?

📒 JS 两个注意点

  • 判断对象是否存在某属性,通常都用 Object.prototype.hasOwnProperty.call()。有同学问为什么不能直接 obj.hasOwnProperty() 去判断,因为有些对象是通过 Object.create(null) 创建的,这种情况下原型上就访问不到 hasOwnProperty,必须通过 Object.prototype.hasOwnProperty.call()

  • ES2016 新增的 Array.prototype.includes() 可以识别 NaN,而 Array.prototype.indexOf() 不能识别:

    const arr = ['es6', 'es7', NaN, 'es8'];
    arr.includes(NaN); // true
    arr.indexOf(NaN); // -1

📒 今年最受欢迎的项目:谷歌的 zx

使用 zx 可以编写简单的命令行脚本:

#!/usr/bin/env zx

await $`cat package.json | grep name`

let branch = await $`git branch --show-current`
await $`dep deploy --branch=${branch}`

await Promise.all([
$`sleep 1; echo 1`,
$`sleep 2; echo 2`,
$`sleep 3; echo 3`,
])

let name = 'foo bar'
await $`mkdir /tmp/${name}`

zx 涵盖了多个软件包提供的功能:

  • node-fetch:使用与浏览器中相同的 API 发出 HTTP 请求
  • fs-extra:运行文件系统

这块源码不是很多,推荐看一下:

https://github.com/google/zx

📒 工程化方案总结下

2021 年 TypeScript + React 工程化指南

2021 年当我们聊前端部署时,我们在聊什么

📒 TypeScript 类型体操

TypeScript 类型编程: 从基础到编译器实战

知其然,知其所以然:TypeScript 中的协变与逆变

📒 monorepo 项目

One For All:基于pnpm + lerna + typescript的最佳项目实践 - 理论篇

📒 漫画图解 Chrome 浏览器从输入到渲染的原理(7000 字)

📒 QUIC 协议

推荐看看 QUIC 101 视频以及 The QUIC transport protocol: design and Internet-scale deployment 论文

📒 ES2015+ 的代码要不要转为 ES5

Babel 主要做了两件事,一是语法转换,二是 api 兼容,其中 api 兼容是通过引入 core-js 的 polyfill 实现的。一般来说转换之后体积肯定会增大,并且很多语法转换的时候会引入 helper 函数,这就产生了副作用,导致无法 Tree-Shaking。

ES6 以上版本代码要不要转码成 ES5?

📒 如何覆盖 CRA 默认 webpack 配置

查看详情

在 CRA 创建的项目中,经常需要修改默认 webpack 配置。但是 CRA 不像 Vue-cli 可以提供自定义 webpack 配置,而 eject 又会把全部配置暴露出来,很麻烦。这种情况下可以使用 react-app-rewired 这个库:

$ yarn add react-app-rewired -D

在项目根目录创建一个 config-overrides.js 文件,添加自定义 webpack 配置:

/* config-overrides.js */

module.exports = function override(config, env) {
//do stuff with the webpack config...
return config;
}

最后在 package.json 中修改 npm scripts:

/* package.json */

"scripts": {
- "start": "react-scripts start",
+ "start": "react-app-rewired start",
- "build": "react-scripts build",
+ "build": "react-app-rewired build",
- "test": "react-scripts test",
+ "test": "react-app-rewired test",
"eject": "react-scripts eject"
}

这个库源码不是很多,推荐看一下:

https://github.com/timarney/react-app-rewired

tip

通常 react-app-rewired 会搭配 customize-cra 这个库一起用:

$ yarn add customize-cra react-app-rewired -D

支持在 config-overrides.js 中编写函数式的 API 去修改 webpack 配置:

const {
override,
addDecoratorsLegacy,
disableEsLint,
addWebpackAlias
} = require("customize-cra");
const path = require("path");

module.exports = override(
// enable legacy decorators babel plugin
addDecoratorsLegacy(),

// disable eslint in webpack
disableEsLint(),

// add an alias for "ag-grid-react" imports
addWebpackAlias({
["ag-grid-react$"]: path.resolve(__dirname, "src/shared/agGridWrapper.js")
}),
);

https://github.com/arackaf/customize-cra

📒 React 组件懒加载实现思路

项目中经常需要长列表渲染,一般都使用懒加载,滚动到底部时渲染下一屏数据,需要判断元素是否在 viewport 内。过去通常会监听滚动事件,然后调用 Element.getBoundingClientRect() 方法以获取元素的边界信息。由于滚动事件触发非常频繁,频繁调用会导致性能问题。

这种情况下可以使用 Intersection Observer API,仅在被监听元素进入或者退出 viewport 时触发回调,这样就不会大量占用主线程。

let observer = new IntersectionObserver(callback, options);
let target = document.querySelector('#listItem');
observer.observe(target);
tip

在 React 项目中,还可以使用 react-intersection-observer 这个库。

react-intersection-observer - npm

Intersection Observer API - MDN

懒加载 React 长页面 - 动态渲染组件

📒 如何避免 React 组件重复渲染

📒 React 16 架构

React16架构可以分为三层:

  • Scheduler(调度器)—— 核心职责只有 1 个, 就是执行回调。把react-reconciler提供的回调函数, 包装到一个任务对象中.在内部维护一个任务队列, 优先级高的排在最前面。循环消费任务队列, 直到队列清空
  • Reconciler(协调器)—— 负责找出变化的组件,16版本主要是Fiber,15版本是stack。区别在于增加了优先级系统,通过遍历的方式实现可中断的递归,将fiber树的构造过程包装在一个回调函数中, 并将此回调函数传入到scheduler包等待调度
  • Renderer(渲染器)—— 负责将变化的组件渲染到页面上,能够将react-reconciler包构造出来的fiber树表现出来, 生成 dom 节点(浏览器中), 生成字符串(ssr),比如说react-dom、react-native。 所以react-native的作用主要是将react提供的节点,渲染到app页面上

我们书写的react-native组件,比如说View、Text等,需要通过react-native-web来变成react-dom可以识别的节点

📒 如何在 JB 全家桶中使用 VS Code 的快捷键

查看详情

JB 全家桶,例如 IDEA、WebStorm、GoLand 等支持多种 keymap,如要使用 VS Code 的快捷键,只需要安装对应的 Keymap 即可:

Preview

安装后应用即可:

Preview

同理主题也可以安装,在 JB 全家桶中推荐使用 One Dark Theme,安装完成后点击 apply 即可:

Preview

📒 静态页面部署方案

一篇教你代码同步 Github 和 Gitee

教你如何使用vercel服务免费部署前端项目和serverless api

📒 webpack 热模块替换看下源码

webpack模块热更新原理

Webpack 原理系列十:HMR 原理全解析

📒 聊一聊前端算法面试——递归

📒 前端单元测试入门与最佳实践

📒 淘宝店铺的 TypeScript ESLint 规则集考量

📒 自动发布脚本

https://github.com/release-it/release-it

📒 diff 算法相关

https://github.com/snabbdom/snabbdom

DIff算法看不懂就一起来砍我(带图)

📒 如何盘点出掘金的年度高赞文章?

📒 盘点掘金 2021 高赞 Vue 文章

📒 盘点掘金 2021 高赞 React 文章

📒 盘点掘金 2021 点赞高达 6000,收藏过万的文章

📒 如何测试驱动开发 React 组件?

📒 一起来写 VS Code 插件:为你的团队提供常用代码片段

📒 黑暗模式常用换肤方案

CSS Variables

css variables 是 Web 标准实现了对深色模式的支持,以下代码通过 CSS 媒体查询:

:root {
color-scheme: light dark;
--nav-bg-color: #F7F7F7;
--content-bg-color: #FFFFFF;
--font-color: rgba(0,0,0,.9);
}

@media (prefers-color-scheme: dark) {
:root {
--nav-bg-color: #2F2F2F;
--content-bg-color: #2C2C2C;
--font-color: rgba(255, 255, 255, .8);
}
}

:root {
color: var(--font-color);
}

.header {
background-color: var(--nav-bg-color);
}

.content {
background-color: var(--content-bg-color);
}

优点:代码量最少,实现起来方便

缺点:存在浏览器兼容性,需要 edge16+ 才支持

打包多份 css

当然也可以手动打包 2 份 CSS 样式,通过动态引入样式文件进行切换。这种方式存在一个问题,当点击切换的时候会引起整个页面重排,因此我们需要单独打包出只包含颜色的样式文件。从这个思路出发,我们就接触到了 PostCSS。

使用 PostCSS 插件让你的网站支持暗黑模式

📒 使用 NextJS 和 TailwindCSS 重构我的博客

⭐️ 2022 前端技术领域会有哪些新的变化?

· 11 min read
加菲猫

📒 clsx:classnames 的替代方案

📒 TS 类型系统实现大数相加

一位数相加,总共只有 100 种情况,为了提高性能,可以选择 打表

用 TS 类型系统实现大数加法

📒 盘点那些让开发效率翻倍的React Hook

⭐️ ESM 与 CJS 的 Interop 来世今生

📒 浏览器渲染中的合成层与 will-change

合成就是将页面的各个部分分成多个层、单独 光栅化(浏览器根据文档的结构、每个元素的样式、页面的几何形状和绘制顺序转换为屏幕上的像素的过程)它们并在合成器线程中合成为一个页面的技术。

一般来说,拥有一些特定属性的渲染层,会被浏览器自动提升为合成层。合成层拥有单独的图层(GraphicsLayer),和其他图层之间无不影响。而其它不是合成层的渲染层,则和第一个拥有图层的父层共用一个,也就是普通文档流中的内容,我们看一些常见的提升为合成层的属性。

  • 设置 transform: translateZ(0)
  • backface-visibility: hidden 指定当元素背面朝向观察者时是否可见
  • will-change 该属性告诉浏览器该元素会有哪些变化,这样浏览器可以提前做好对应的优化准备工作
  • videocanvasiframe 等元素
tip

使用 transform 和 opacity 来实现动画

在开发中经常会实现一些动画,有时候我们可能会选择改变 top/left 去实现,那么这个节点的渲染会发生在普通文档流中。而使用 transformopacity 实现动画能够让节点被放置到一个独立合成层中进行渲染绘制,动画不会影响其他图层,并且 GPU 渲染相比 CPU 能够更快,这会让你的动画变的更加流畅。

按照下面的操作打开查看帧率的界面:

Preview

通过 transform 来实现动画,页面的 fps 能够稳定在 60 左右,而通过 left 来实现存在波动,fps 大概稳定在 30 左右,这会影响你的用户体验指标。

浏览器渲染魔法之合成层

⭐️ 前端 Code Review 不完全指北(万字长文,50+case)

📒 Node.js 相关

Node.js 适合 IO 密集型任务,例如处理网络请求、文件 IO 等等;

Node.js 不适合 CPU 密集型任务,例如 MD5、SHA 加密算法等;

📒 升级Yarn 2,摆脱node_modules

📒 什么是 inode

inode (index nodes) 是操作系统中重要的概念,是一种文件数据结构,用于存储有关除名称和数据之外的任何 Linux 文件的信息。

软链接&硬链接在前端中的应用

📒 gitlab上代码回滚把自己坑了后, 陷入思考🤔"bug是谁"?

⭐️ 提交代码的时候使用 rebase

一般提交代码都是先本地 commit,然后执行 git pull 将仓库的代码拉取到本地 merge,然后再 push 到仓库。这样会导致时间线很不干净,提交记录中混杂很多 merge 分支的无用记录。

在拉取仓库代码的时候,我们可以不进行合并,而是使用 rebase(变基),直接把我们原先的基础变掉,变成以别人修改过后的新代码为基础,把我们的修改在这个新的基础之上重新进行。使用变基之后,就可以使我们的时间线变得非常干净。

两条命令让你的git自动变基

📒 如何使用 VS Code 任务

开发经典模式:从主仓库 fork => 从个人仓库提 Merge Request

【手把手】学会VS Code"任务"神技,成为项目组最靓的崽!

📒 如何分析每行代码的执行耗时

首先使用 Performance 工具分析页面性能。

在分析性能的时候,为排除插件的影响,需要启用无痕模式

在火焰图中找到长任务,点击顶部 Task,点击 Button-Up,这时候可以看到根据耗时列出的调用栈:

Preview

找到那个执行耗时最长的,然后点击右侧源码地址,可以跳到 source 对应的源码:

Preview

📒 关于数组遍历方法的比较

  • 相比 forEachmap 性能略差一些,因为需要创建新数组
  • 数据量大的时候,手写 for 循环性能明显优于 forEachmap
    • 倒序 for 循环性能最好,因为只访问了一次 array.length
      // 正序
      for (let i=0; i<arr.length; i++)
      // 倒序
      for (let i=arr.length-1; i>=0; i--)
    • 如果想提升正序遍历性能,可以这样写
      for (let i=0, len=arr.length-1; i<len; i++)
    • 无论遍历数组还是对象,都尽量少用 for...in 循环,性能比较烂
  • 无论 new Array() 还是 Array.from() 性能都不如写一个 for 循环往空数组里面 push
  • 另外不推荐使用 [].fill() 方法,TS 无法推导类型,建议使用 Array.from({length: 10}, () => 1) 的方式

📒 如何指定一个项目所需的 node 最小版本

指定一个项目所需的 node 最小版本,这属于一个项目的质量工程。我们可以在 package.json 中的 engines 字段中指定 Node 版本号:

{
"engines": {
"node": ">=14.0.0"
}
}

如果本地运行的 Node 版本不匹配,yarn 将会报错,npm 则会打印警告信息。engines 字段不仅可以用于前端项目,也可用于第三方库。

tip

如果项目的 package.json 中没用 engines 字段,可查看 Dockerfile 中 node 镜像确定项目所需的 node 版本号。

📒 Vue SFC playground

https://sfc.vuejs.org/

研究下插槽的实现

📒 写一个 Vue3 自定义指令

Vue 自定义指令的范式:

const lazyPlugin = {
install (app, options) {
app.directive('lazy', {
// install 方法的第一个参数可以拿到 Vue 构造器
// 这块可以参考 Vue.use 源码
})
}
}

export default lazyPlugin

在项目中使用如下:

import { createApp } from 'vue'
import App from './App.vue'
import lazyPlugin from 'vue3-lazy'

createApp(App).use(lazyPlugin, {
// 添加一些配置参数
})

手把手带你写一个 Vue3 的自定义指令

📒 揭秘 Vue.js 九个性能优化技巧

📒 2020最新React Hooks+TS项目最佳实践

📒 「react进阶」一文吃透react-hooks原理

📒 useCallback 使用场景

在 React 中经常需要将父组件定义的方法传入子组件(即事件钩子,也可以看作子组件状态提升到父组件),例如:

const Parent = () => {
const handleSearch = (val) => {
console.log("搜索结果:", val);
}

return <Input onSearch={handleSearch} />
}

const Input = React.memo(({ onSearch }) => {
return (
<form onSubmit={(e) => {
const submitData = Array.from(
e.target.childNodes,
item => ({ name: item.name, value: item.value })
);
onSearch(submitData);
}}>
<input type="text" name="search" />
</form>
)
})

在上面的代码中,如果父组件重新渲染,则会导致 handleSearch 方法重新生成,进而导致 onSearch prop 改变,即使子组件用了 React.memo,子组件还是会重新渲染。在这种情况下,就可以使用 useCallback 缓存函数,避免函数重复生成,进而避免子组件重复渲染,提高性能:

const Parent = () => {
const handleSearch = React.useCallback((val) => {
console.log("搜索结果:", val);
}, []);

return <Input onSearch={handleSearch} />
}
tip

注意 useCallback 需要和 React.memo 一起使用。如果不用 React.memo,只要父组件重新渲染,即使 prop 没有改变,子组件还是会重新渲染

React Hooks 详解 【近 1W 字】+ 项目实战

📒 老板:你来弄一个团队代码规范!?

📒 前端工程化系列文章

https://shanyue.tech/frontend-engineering/npm-install.html#%E4%BD%BF%E7%94%A8-npm-ci-%E6%9B%BF%E4%BB%A3-npm-i

📒 ES 新语法 Array.prototype.groupBy

一个专门用来做数据分组的提案 Array.prototype.groupBy 已经到达 Stage 3

const array = [1, 2, 3, 4, 5];

// groupBy groups items by arbitrary key.
// In this case, we're grouping by even/odd keys
array.groupBy((num, index, array) => {
return num % 2 === 0 ? 'even': 'odd';
});

// => { odd: [1, 3, 5], even: [2, 4] }

https://github.com/tc39/proposal-array-grouping

📒 基于 Next.js 的 SSR/SSG 方案了解一下?