LINNIL

LINNIL

跨平台桌面应用开发新选择 Tauri 2.0
Introduction

跨平台桌面应用开发新选择 Tauri 2.0

Tauri 2.0 在 2024/10/02 官方正式发布了 Tauri 2.0 的稳定版本,这给我们构建跨平台桌面应用提供了新的选择。首先我们先了解一下 Tauri 是什么? 借用官方的话来说: Tauri 是用于为所有主流桌面(macOS、linux、windows)和移动(iOS、Android)平台构建微小二快速的二进制文件的框架。开发人员可以使用任何编译为 HTML、JavaScript 和 CSS 的前端框架来构建他们的应用,并且也可以在需要时使用 Rust、Swift 和 Kotlin 等语言来实现后端逻辑。总结一下 Tauri 是可以使用 Web 技术构建跨平台桌面应用,同时提供对系统本地资源访问能力的框架,没错,这介绍很容易想到另一个也是很好用的框架 Electron。Tauri 的优势在于轻量,性能,
5 min read
SVGO 压缩 SVG 后不能正常缩放
Bug

SVGO 压缩 SVG 后不能正常缩放

前情提要 在前端开发过程中,SVG 图标(可缩放矢量图形)被广泛使用,因为它们具有可伸缩性、清晰的显示效果以及较小的文件大小。使用 SVG 作为图标有很多优势,尤其是在响应式设计和高分辨率屏幕上的表现。 但是,SVG 图标的制作过程也有很多不便之处。一千个读者就有一千个哈姆雷特,一千个制作者绘制同一个图标也可能会有一千个不同的版本。尽管 SVG 本身已经足够小了,但是在很多矢量编辑器/软件中,导出来的 SVG 文件会有很多其他冗余信息(当然这里面制作者和导出软件可能都会有问题)。 为了解决这些问题,我们需要一个工具来压缩 SVG 图标,使其更小、更清晰、更易于管理。所以选择了 SVGO 对图片进行压缩并且使用 SVGR 将 SVG 代码转换为 React Component 。 你可以在这尝试进行 svg 的压缩与转化。 * svgo playground * svgr playground ps:
3 min read
基于 Lexical 的富文本输入框
Demo

基于 Lexical 的富文本输入框

这次先放 demo 富文本输入框 最近都在写后台项目,在项目中使用 富文本输入框 的频率很高。也使用过蛮多富文本编辑器,比如 tinymce, quill, jodit 等等。 因为一些特殊的业务需求,比如图片/视频的上传改成从后台库中选择图片,支持 youtube 视频嵌入等等,又不希望使用付费商业版,所以决定二次开发一个开源的高度自定义的富文本编辑器。在调研/使用了多个项目之后决定使用 lexical 开发。 Lexical Lexical 是一个开源的富文本编辑器框架,由 Facebook 开发,旨在提供灵活和可扩展的文本编辑体验。最主要的优势在于 Lexical 的开发者体验一流。不需要过多与 DOM 的交互,通过声明性的 API 和插件就可以快速实现想要的功能。 在开始之前强烈建议先阅读完整的官方文档 ,后面的内容会从实践出发,不会过多介绍相关概念。 依赖安装 npm install --save lexical @lexical/
9 min read
世界地图插件
Demo

世界地图插件

开个新系列,主要写些不知道有什么用的功能 Demo,反正就是突然想做个试试。 像素点地图 一些简单的需求: * [ ] 渲染显示世界地图 * [ ] 能够缩放 / 移动地图 * [ ] 在地图上添加标点 * [ ] 地图添加高亮某块区域的交互 实现 绘制地图 本来企图用 three 实现 3D 地图,最后还是使用 canvas 绘制 2D 地图。 * 定义像素点结构 interface Node { x: number; y: number; isHighLight?: boolean; } * canvas 绘制地图 const canvasRef = useRef<HTMLCanvasElement>(null); const [data, setData] = useImmer(worldData); useEffect(() => { const canvas
7 min read
AST 抽象语法树
Node

AST 抽象语法树

什么是 AST Abstract Syntax Tree(AST,抽象语法树) 是一种用于表示程序源代码的抽象语法结构的树形数据结构。每个节点(Node)都表示源代码中的一个语法构造(Syntax Construct),例如表达式、语句、操作符、函数、变量等。AST 通过去除代码中的不必要的语法细节(如括号、逗号、空格和注释),提供了一种更高层次的代码表示形式,使编译器或解释器可以更容易地进行分析、优化和代码生成。 在前端开发过程中,其实有很多工具都需要依赖于AST抽象语法树,比如:ESLint、Babel、Prettier等等。当我们使用 Vue.js 编写 template 时, template 转化成 render function 的过程,其实就是 AST 的转换过程,AST 是帮助程序理解代码的重要工具。 AST 的结构
7 min read
CSS 居中元素
Node

CSS 居中元素

开发过程中居中对齐是最常见最基础的需求。根据具体情况(元素类型,父容器属性等),有很多方式可以实现居中。写下这篇笔记的原因是 2024 CSS 终于可以通过 align-content 属性实现垂直居中,顺便巩固其他的居中方式吧。 <div class="parent"> <div class="child">居中元素</div> </div> 使用 flex 布局实现居中 flex 弹性布局时最现代化,最简洁的布局方式之一,适用于大部分的场景。 .parent { display: flex; justify-content: center; /* 水平居中 */ align-items: center; /* 垂直居中 */ height:
2 min read
Javascript 中的作用域
Node

Javascript 中的作用域

基本概念 作用域(Scope)是编程中的一个基本概念,它指的是变量和函数在代码中的可访问范围。简单来说就是程序在哪个部分可以访问这个变量或函数。作用域可以帮助控制和管理变量的生命周期,避免命名冲突。 作用域的类型 在 Javascript 中有三种作用域: 1. 全局作用域(Global Scope):全局作用域指的是在代码的最外层定义的作用域。全局作用域中的变量可以在整个代码中访问。 2. 函数作用域(Function Scope):函数作用域是指在函数内部定义的变量只能在该函数内部访问。函数内部的变量对外部不可见。 3. 块级作用域(Block Scope):块级作用域指的是在代码块(由 {} 包围的部分)内部定义的变量只能在该块内部访问。块级作用域是在 ES6 引入的,使用 let 和 const 声明的变量具有块级作用域。 静态作用域与动态作用域 静态作用域(Lexical Scope) * 静态作用域是在编写代码时确定的作用域。这意味着变量的作用范围由其在源代码中的位置决定,而不是在程序运行时的调用上下文决定。JavaScript、P
8 min read
节流/防抖
Node

节流/防抖

什么时候需要防抖/节流 在正常开发过程中,特别是在处理用户输入或窗口调整大小等频繁触发的事件时,如果事件的回调函数过于复杂或者是 ajax 请求,在高频调用下难免会出现卡顿。为了限制函数执行频率,一般有两种解决方案: 1. debounce 防抖 2. throttle 节流 防抖的原理:在一定时间内函数只调用一次,当防抖函数被触发时,它不会立即执行目标函数,而是设置一个定时器。若在定时器时间到期前再次触发,则取消之前的定时器并重新设置定时器。只有当一段时间内没有新的触发,目标函数才会执行。 从简单的例子入手: <!DOCTYPE html> <html> <head> <title>Debounce Example</title> <meta charset="UTF-8"
5 min read
原型链
Node

原型链

总结:用于在现有对象的基础上构建新类型的对象。类似于类的语言中的继承。 对象实例上的原型可通过 Object.getPrototypeOf(object) 或 proto 属性获得,而构造函数上的原型可以通过 Object.prototype 获得。 虽然 Object.prototype 是原型链的最顶层,但它本身也有一个原型对象 => null 。所以原型链的顶端实际上是 null 。总的来说,JavaScript 中的原型链顶端是 null,而原型链的最顶层对象是 Object.prototype。 构造函数创建对象 function Fruit() {} var fruit = new Fruit(); fruit.name = 'Apple' console.log(fruit.name) // Apple Fruit 就是构造函数,fruit
4 min read
React-状态管理
Node

React-状态管理

MVC 和 MVVM 模型 1. MVC:Model-View-Controller,模型-视图-控制器。 2. MVVM:Model-View-ViewModel,模型-视图-视图模型。视图模型负责将模型的数据转换为试图可以使用的格式,并且负责处理试图交互逻辑。 MVC 和 MVVM 都是组织和管理应用程序代码结构的模式,具体实现和使用上有一些不同。MVC 更关注控制器和模型的交互,MVVM 更关注视图模型和试图的交互。 状态管理的概念 状态管理一般处于 MVC 中的模型层,MVVM 中的视图模型层。 1. 状态:指的是应用程序中的数据或状态信息,可以是用户信息、界面状态、网络请求状态等等。在状态管理中,状态通常被集中存储和管理,以确保整个应用程序的一致性和可维护性。 2. 管理:指的是对状态的管理和控制。状态管理工具通常提供了一套 API 或机制,用于更新、访问和监听状态的变化。这些工具还可以帮助开发人员组织和结构化状态,以便更容易地维护和调试应用程序。 3. 通信:
11 min read
Golang中循环变量引用问题

Golang中循环变量引用问题

问题描述 在开发过程中发现在循环中引用捕获了变量,导致最后输出结果都是同一个值。 arr := []int{1, 2, 3, 4, 5} for i, v := range arr { go func() { fmt.Println(v) }() } // 输出结果: 5 5 5 5 5 搜索后发现这个坑可以说是新手必踩,所以记录一下。 * bug 产生原因:在 Golang 的循环中,由于 func 或者指针的引用,并且这个引用逃逸出了当前循环的生命周期范围。而在 Golang 中,循环变量的生命周期为整个循环,而不是每个迭代都会创建一个新的变量,所以导致每个迭代的引用实际上都指向同一个值。 更多关于Golang中逃逸现象可以看一下这篇文章 github 解决方案 * 使用临时变量来接收循环变量的值,避免引用逃逸。 arr := []int{
1 min read
如何在浏览器中下载PDF文件
Bug

如何在浏览器中下载PDF文件

问题描述 在开发过程中,遇到了需要下载文件的需求,一般是直接使用 window.open() 方法,或者通过 a 标签点击下载。但是 PDF 文件只是打开了浏览器携带的 PDF 预览,需要用户手动点击预览页面的下载按钮才能下载文件。那么如何实现直接下载呢。 解决方案 将 PDF 文件的 MIME type 改成 application/octet-stream 并加入 Content-Disposition: attachment header。(原本的 PDF 文件 MIME type 为 application/pdf,浏览器识别到这个类型会自动打开) 可以通过后端接口返回时修改,也可以通过前端自行修改,前端修改如下: fetch(url, {method: 'get'}) .then(function
1 min read
浏览器运行机制
Node

浏览器运行机制

进程和线程 进程和线程是操作系统中管理和执行任务的基本单位。它们有不同的概念和作用,理解它们之间的区别对于编程和系统设计非常重要。 * 进程(process):程序的一次执行过程,是程序在执行过程中操作系统分配资源和管理任务的基本单位;每个进程都拥有自己独立的内存空间和系统资源,进程之间无法直接访问彼此的内存,这也意味着一个进程的崩溃不会直接影响到其他进程。 * 线程(thread)是 CPU 调度和分派的基本单位,它可与同属一个进程的其他的线程共享进程所拥有的全部资源,但彼此独立执行。 浏览器的多进程 浏览器可以视作一个复杂的应用程序。当用户启动浏览器时,操作系统会为该应用程序分配一个进程。这个进程启动后,CPU 会为其分配相应的内存空间,供其运行和存储数据。进程启动后,便可以利用线程来执行特定任务,从而实现应用程序的功能。 在一个应用程序中,单一进程可能无法满足所有的功能需求,因此它会创建新的进程来处理其他任务。这些新创建的进程与原有进程是相互独立的,它们各自拥有独立的内存空间,无法直接共享数据。这种隔离增强了应用程序的安全性和稳定性。 尽管这些进程不
11 min read
Remix-路由驱动的前端开发模型
Introduction

Remix-路由驱动的前端开发模型

Remix 是什么 Remix 是一个面向 React 开发者的现代化全栈框架,它提供了一种新的方法来构建 web 应用程序。Remix 的核心理念是将前端和后端代码统一在一个项目中,并且通过路由和路由参数来管理页面和数据的加载。 Remix 的特点 1. 允许或者说是鼓励全栈框架,将前后端代码整合到一个项目。 2. 路由和路由参数来管理页面和数据的加载,使得页面之间的跳转和数据传递更简单直观。 3. 提供了多种钩子。 4. 内置缓存。 创建 Remix 项目 以下内容均基于 v2 版本,旧版本内容不会提及。更多信息可以查阅 官方文档。 创建一个简单的 Remix 模板项目 npx create-remix@latest --template remix-run/indie-stack blog-tutorial // remix.config.js module.exports = { future: { v2_
10 min read
GraphQL 一种更灵活的 API 解决方案
Introduction

GraphQL 一种更灵活的 API 解决方案

简单介绍 GraphQL 是一种用于 API 的查询语言和运行时环境,由 Facebook 开发并于2015年公开发布。它旨在提供一个更高效、强大且灵活的替代方案,用于客户端和服务器之间的数据交互。与传统的 RESTful API 不同,精确的数据查询,允许仅获取所需的数据等都是 GraphQL 的优势。 GraphQL 的优势 GraphQL 的优势主要在于精确的数据查询,允许仅获取所需的数据,从而节省带宽和资源,这将通过一个例子来理解。 GraphQL 服务是通过定义类型和字段,为每种类型上的每个字段提供函数来创建的。查询用户的 GraphQL 服务可能长这样: type Query { me: User } type User { id: ID! name: String! } GraphQL 服务在运行时主要由两部分组成,Query Language 和 Engine,后端定义了类型和字段,客户端一样需要通过
6 min read
事件循环 Event Loop
Node

事件循环 Event Loop

基本概念 事件循环(Event Loop)是 JavaScript 运行时环境中负责管理异步任务执行的一种机制。在浏览器中,事件循环是由浏览器的 JavaScript 引擎(如 V8 引擎)负责实现;在 Node.js 等环境中,也有自己的事件循环实现。简单来说,事件循环就是轮询任务队列,执行任务,休眠的无限循环。 事件循环的意义 原因很简单,JavaScript 是单线程语言,单线程意味着同一时间只能执行一个任务,为了能有效处理异步任务,而不会阻塞主线程,就需要并发处理,而事件循环就是并发的一种形式。这对于交互式的 Web 应用和处理网络请求等操作至关重要。 任务队列 任务队列是事件循环的核心组成部分,用于管理和调度异步任务的执行顺序。当任务到来时,JavaScript 引擎可能处于忙碌状态,那么任务会被排入队列里。 队列中的任务遵循 “先进先出” 的原则。当浏览器引擎执行完 script 后,它会处理
6 min read
定时器为什么不准
Bug

定时器为什么不准

setTimeout 和 setInterval 的差异 两个方法都是用于执行定时任务的函数,主要差异存在于执行次数和间隔的处理方式。 setTimeout 在一定延迟后执行一次指定的函数或代码块。执行完成后停止计时。 setInterval 每隔一定时间重复执行指定函数,会不断执行直到被取消或者页面销毁。 定时器的一些注意事项: * js 中定时器不能准时执行,主要原因包括以下几点: 1. JavaScript 是单线程执行的语言,在同一时间只执行一个任务。在执行 JavaScript 代码时,如果遇到长时间运行的任务(大量计算或阻塞操作),会导致计时器执行收到影响。 2. 浏览器有最小定时器间隔,通常为 4ms 或 10ms。浏览器总会将时间精度舍入到最小间隔的倍数。 3. 页面活动状态也会影响计时器,在页面切换标签或者最小化浏览器窗口时,浏览器可能会将当前页面的定时器暂停,以节省资源。 4. 在移动设备或者资源受限的环境中,系统可能会对浏览器资源进行限制。 5. 延迟执行时间有最大值 2
4 min read
Webpack 学习
Node

Webpack 学习

1. 简介 1.1. Webpack 是什么? 官方解释:本质上,webpack 是一个用于现代 JavaScript 应用程序的静态模块打包工具。当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个 依赖图(dependency graph),然后将你项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源,用于展示你的内容。 Webpack 是一个模块打包工具(module bundler),因为平常多用来对前端工程打包,所以也是一个前端构建工具。其最主要的功能就是模块打包。 模块打包,通俗地说就是:找出模块之间的依赖关系,按照一定的规则把这些模块组织合并为一个 JS 文件。 Webpack 认为一切都是模块,JS 文件、CSS 文件、jpg/png 图片等等都是模块。Webpack 会把所有的这些模块都合并为一个 JS 文件,这是它最本质的工作。
13 min read