0%

今天在玩耍typescript的时候,发现了一个有趣的问题,tsconfig.json中的outDir配置导致tsc命令无法编译,tsconfig.json的配置是这样的:

Read more »

今天来看一下如何在React项目中使用Jest进行单元测试。

创建React项目

我们使用Vite来创建React项目,命令如下:

1
npm create vite@latest react-app-jest --template react-ts

使用VSCode打开项目

使用如下命令打开项目

1
2
cd react-app-jest
code .
Read more »

今天来研究一下如何在Angular应用中集成Lit Element。Lit Element是一个轻量级的Web Component库,基于标准的Web Component API,因此可以在任何支持Web Component的框架中使用,比如React、Vue、Angular等。

使用Angular CLI创建Angular项目

如果你已经安装了Angular CLI,可以直接使用以下命令创建一个新的Angular项目:

1
ng new lit_element-app-angular

如果你没有安装过Angular CLI,也没关系,可以使用以下命令创建Angular项目:

1
npx @angular/cli@latest new lit_element-app-angular

在cli创建项目的过程中可能会提示你选择CSS预处理器,我们直接选择CSS即可,CLI还会询问是否启用服务端渲染,我们选择否。

安装Lit Element依赖

待项目创建好以后,我们使用如下命令用VSCode打开项目,首先使用cd lit_element-app-angular进入项目目录,然后使用code .表示用VSCode打开当前目录。

1
2
cd lit_element-app-angular
code .

打开VSCode中的Terminal,运行以下命令安装lit

1
npm install lit

创建Lit Element组件

src目录下创建一个components目录,然后在components目录下创建一个my-element.ts文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { LitElement, css, html } from 'lit';
import { customElement, property } from 'lit/decorators.js';

@customElement('my-element')
export class MyElement extends LitElement {
@property({ type: String }) name = 'World';

static override styles = css`
:host {
display: block;
padding: 16px;
color: var(--my-element-text-color, black);
}
`;

override render() {
return html`<p>Hello, ${this.name}!</p>`;
}
}

使用my-element组件

首先:在src/app/app.component.ts中引入my-element.ts并添加CUSTOM_ELEMENTS_SCHEMA,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import '../components/my-element'; // 引入my-element组件
@Component({
selector: 'app-root',
imports: [RouterOutlet],
templateUrl: './app.component.html',
styleUrl: './app.component.css',
schemas: [CUSTOM_ELEMENTS_SCHEMA], // 添加CUSTOM_ELEMENTS_SCHEMA
})
export class AppComponent {
title = 'lit_element-app-angular';
}

然后:在src/app/app.component.html中使用my-element组件:

1
2
<my-element name="World"></my-element>
<router-outlet />

更新tsconfig设置

打开项目根目录下(package.json所在目录)的tsconfig.app.json文件,添加以下配置:

1
2
3
4
5
6
{
"compilerOptions": {
"experimentalDecorators": true,
"useDefineForClassFields": false
}
}

运行项目

1
npm run start

在浏览器中访问http://localhost:4200,你应该能看到如下效果:

1
Hello, World!

话说Angular集成Lit简直是分分钟的事,比React简单太多了。为什么国内用Angular的人这么少呢?不理解…

分支的本质是什么?

分支的本质是一个指向某个commit的指针。所以未commit的修改是没有分支的概念的,只有commit才有分支的概念。

下面的命令中我们使用git checkout来切换分支,新版本的git推荐使用git switch来切换分支。但是git checkout命令还有其他功能,比如检出某个版本,所以git switch命令并不能完全替代git checkout命令。

Read more »

VSCode是时下最令行的前端开发工具,用好VSCode能极大的提高我们的开发效率,而搜索是日常开发中必不可少的操作,今天我们一起来聊聊VSCode中的搜索技巧。

普通的搜索我们就不谈了,今天主要介绍一下正则表达式搜索和一些小技巧。

匹配换行符

  • [.|\n]* - 可以匹配任意字符,包括换行符。
  • [\s\S] - 注意这种方式不好用。

一般情况下我们都是进行单行搜索,但是有些情况下我们需要跨行搜索,比如下面的React代码:

1
2
3
4
useEffect(() => {
const lang = LocalStorageUtil.getLanguage();
i18n.changeLanguage(lang);
}, []);

如果我想搜索所有依赖数组为空的useEffect调用,该怎么写这个正则表达式呢?大家可以先试试,反正我试了半天也没写出来,后来还是差DeepSeek才搞定,答案如下:

1
useEffect\((.|\n)*?,\s*\[\s*\]\s*\)

我们来解析一下这个正则表达式:

  • useEffect - 匹配useEffect字符串
  • \( - 匹配(字符,因为(是正则表达式中的特殊字符,所以需要转义。
  • (.|\n)*? - 匹配任意字符,包括换行符,*?表示非贪婪匹配,尽可能少的匹配字符。
  • , - 匹配,字符
  • \s* - 匹配,[]之间的任意空格字符,包括空格、制表符、换行符等,*表示匹配0次或多次。
  • \[\s*\] - 匹配空的依赖数组,因为[]是正则表达式中的特殊字符,所以需要转义。
  • \s*\) - 匹配最后的右括弧,\s*表示[]与右括弧之间可能有空格。

这里面的关键是:(.|\n) - 它匹配任意字符包括换行符。

匹配markdown中的表格

在Markdown中,使用如下方式来生成表格。

1
2
3
4
| Name  | Age |
| ----- | --- |
| Tom | 18 |
| Jerry | 20 |

如果我们要查找所有的markdown表格,那么我们只需要找出如下特征字符串即可

1
|------|-----|

可以使用如下的正则表达式:

1
\|\s*-+

我们来解析一下这个正则表达式:

  • \| - 匹配|字符,因为|是正则表达式中的特殊字符,所以需要转义。
  • \s* - 匹配|-之间的任意空格字符。
  • -+ - 匹配-字符,+表示匹配1次或多次。

这样,我们就可以查出所有的markdown表格了。你学会了吗?

今天我们一起来学习一下如何使用TypeScript创建Lit Element应用,如果还不熟悉什么是Lit Element,可以看一下这里

话不多说,直接上干货。

前提条件

在开始之前,请确保你已经安装了以下软件:

  • Node.js
  • npm - 一般来说,安装了Node.js,npm也就顺带安装好了。

创建项目

我们使用时下最流行的Vite来创建一个新的项目,Vite是一个快速的前端构建工具,可以帮助我们快速搭建开发环境。

打开命令行,运行以下命令:

1
2
3
4
npm create vite@latest my-lit-app-typescript --template vanilla-ts
cd my-lit-app-typescript
npm install
npm install lit

添加Lit Element组件

src目录下创建一个新的文件夹components,然后在该文件夹下创建一个新的文件my-element.ts,并添加以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { LitElement, html, css } from 'lit';
import { customElement } from 'lit/decorators.js';
import { property } from 'lit/decorators.js';

@customElement('my-element')
export class MyElement extends LitElement {
@property({ type: String }) name = 'World';

static styles = css`
h1 {
color: blue;
}
`;

render() {
return html`<h1>Hello, ${this.name}!</h1>`;
}
}

在上面的代码中,我们创建了一个名为my-element的自定义元素,它继承自LitElement。我们使用了@customElement装饰器来定义这个元素,并使用@property装饰器来定义一个属性name

运行项目

使用VSCode打开项目,运行以下命令启动开发服务器:

1
npm run dev

不出意外,你会遇到@customElement("my-element")无法识别的错误:

1
Uncaught SyntaxError: Invalid or unexpected token (at my-element.ts:3:1)

这是因为@customElement是装饰器语法,这个语法还未被浏览器正式支持,目前处于state 3,在未来的版本中可以支持,所以暂时需要在tsconfig.json中添"experimentalDecorators": true配置才行。关于Decorator的更多信息,可以看这里

1
2
3
4
5
6
7
{
"compilerOptions": {
// ...
"experimentalDecorators": true,
// ...
}
}

再次运行程序,不出意外,你会遇到如下错误:

1
following properties on element my-element will not trigger updates as expected because they are set using class fields: name. Native class fields and some compiled output will overwrite accessors used for detecting changes. See https://lit.dev/msg/class-field-shadowing for more information

只需要在tsconfig.json中添加如下配置即可:

1
2
3
4
5
6
7
{
"compilerOptions": {
// ...
"useDefineForClassFields": false
// ...
}
}

再次运行程序,这次页面上可以看到Hello, Philip了,Happy Coding!

Lit Element是一款基于Web Component的轻量级库,今天来学习一下如何在原生JavaScript中使用Lit Element

使用Vite创建项目

首先我们使用Vite创建一个原生JavaScript项目,在命令行下运行如下命令:

1
npm create vite@latest my-lit-element-app --template vanilla

执行这条命令后,Vite会询问用户选择一个模板,我们选择vanilla模板。接下来,Vite会询问我们使用JavaScript还是TypeScript,我们选择JavaScript

然后执行如下命令进入项目目录并安装依赖。

1
2
cd my-lit-element-app
npm install

安装Lit Element

运行以下命令来安装lit

1
npm install lit

创建Lit Element组件

在项目的src目录下创建一个新的文件夹components,然后在该文件夹下创建一个新的文件my-element.js,并添加以下代码:
在下面的代码中,我们创建了一个名为my-element的自定义元素,它继承自LitElement

1
2
3
4
5
6
7
8
9
10
import { LitElement, html, css } from 'lit';
import { customElement } from 'lit/decorators.js';
import { property } from 'lit/decorators.js';

class MyElement extends LitElement {
render() {
return html`<h1>Hello, ${this.name}!</h1>`;
}
}
customElements.define('my-element', MyElement);

使用Lit Element组件

src/main.js中导入我们刚刚创建的组件,并在页面中使用它:

1
2
3
4
5
6
7
import './style.css';
import './components/my-element.js';

const app = document.querySelector('#app');
app.innerHTML = `
<my-element></my-element>
`;

在上面的代码中,我们在页面中使用了my-element组件,使用web component就是使用普通的html标签一样。

运行项目

删除项目中的src/counter.js文件,因为我们不需要它们。
最后,在命令行中运行以下命令来启动开发服务器:

1
npm run dev

然后在浏览器中打开http://localhost:5173,页面上显示Hello, world!

Vanilla JavaScript中无法使用装饰器

需要注意的是,如果你使用原生JS开发Lit Element组件,是不能使用装饰器的,至少目前的JS还不支持,比如下面这些装饰器都无法使用:

  • @customElement
  • @property
  • @state

如果你使用了这些装饰器,浏览器会报错,以@customElement为例,报错信息如下:

1
my-element.js:5 Uncaught SyntaxError: Invalid or unexpected token (at my-element.js:5:1)

一个代替的方案是使用如下的方式:下面的代码中,我们使用了static properties来定义属性,使用constructor来初始化属性。
需要注意的是@click - 这是Lit的模板中的事件绑定语法,而非装饰器,所以@click是可以被原生JS支持的,有Lit在运行是转义为addEventListener来实现的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { LitElement, html } from 'lit';

class MyElement extends LitElement {
static properties = {
name: { type: String }, // 替代 @property({ type: String }) name = 'Philip';
count: { state: true }, // 替代 @state() private count = 0;
};

constructor() {
super();
this.name = 'Philip';
this.count = 0;
}

render() {
return html`
<p>Hello, ${this.name}!</p>
<button @click=${() => this.count++}>Count: ${this.count}</button>
`;
}
}

customElements.define('my-element', MyElement);

@是Lit用作事件绑定的语法,除了@click,还有@input@change@submit等事件绑定语法。

今天我们来学习一下如何在React项目中使用Lit Element,Lit Element是一个轻量级的Web Component库,因为基于标准的Web Component API, 所以它可以在任何支持Web Component的框架中使用,比如React、Vue、Angular等。

使用Vite创建React项目

首先使用Vite创建React项目,在命令行下运行如下命令:

1
npm create vite@latest lit-app-react-ts --template react-ts

提示framework的时候选择react,语言选择typescript

安装Lit Element

接下来运行以下命令来安装lit

1
npm install lit

更改tsconfig设置

tsconfig.json中添加以下配置:

1
2
3
4
5
6
{
"compilerOptions": {
"experimentalDecorators": true,
"useDefineForClassFields": false,
}
}

创建Lit Element组件

src目录下创建一个components目录,然后在components目录下创建一个my-element.ts文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { LitElement, css, html } from 'lit';
import { customElement, property } from 'lit/decorators.js';

@customElement('my-element')
export class MyElement extends LitElement {
@property({ type: String }) name = 'World';

static styles = css`
:host {
display: block;
padding: 16px;
color: var(--my-element-text-color, black);
}
`;

render() {
return html`<p>Hello, ${this.name}!</p>`;
}
}

在App.tsx中使用Lit Element组件

src/App.tsx中引入并使用my-element组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import './App.css';
import './components/my-element.ts';

function App() {

return (
<>
<h1>Hi</h1>
<my-element name="World"></my-element>
<p>This is a paragraph</p>
</>
)
}

export default App

运行项目

1
2
3
cd my-react-lit-app
npm install
npm run dev

公司的项目是基于React,今天周末闲着没事用Vite搭建了一个React项目,在运行的时候,突然发现,即使typescript类型不匹配,程序竟然也没有报错,于是突发奇想,能不能在类型不匹配的时候停止运行并报错呢?

代码很简单,首先我定义了一个Card组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React, {ReactNode} from 'react'

interface CardProps {
title: string;
content: string;
children?: ReactNode;
}

export function Card(props: CardProps) {
return (
<div className="card">
<h2>{props.title}</h2>
<p>{props.content}</p>
<p>{props.footer}</p>
{props.children}
</div>
)
}

在返回的组件中,我故意使用了一个CardProps中没有的属性 - footer。此时运行程序,你会发现一切正常!
这有点不合逻辑呀,应该报错才是,于是对着AI一番操作,找到如下方法:

首先安装vite-plugin-checker

1
npm install --save-dev vite-plugin-checker

然后在vite.config.ts中添加如下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
import {defineConfig} from 'vite'
import react from '@vitejs/plugin-react'
import checker from 'vite-plugin-checker';

// https://vite.dev/config/
export default defineConfig({
plugins: [
react(),
checker({
typescript: true,
}),
],
})

再次运行npm run dev,你会发现控制台给出类型不匹配的报错了, 浏览器中的页面也给出了报错,这才是我想要的结果呀!

后来我发现直接在tsconfig.json中添加noEmitOnError配置也可以达到类似效果:

1
2
3
4
5
6
{
"compilerOptions": {
"noEmitOnError": true,
// 其他配置...
}
}

基于Umijs的项目

如果你的项目是基于阿里巴巴的Umijs框架,那么可以添加如下配置(.umirc.ts 或 config/config.ts):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
export default {
// 其他配置...

// 启用 TypeScript 类型检查
mfsu: {
development: {
output: '.mfsu-dev',
},
},

// 开启类型检查
forkTSChecker: {
typescript: {
diagnosticOptions: {
semantic: true,
syntactic: true,
},
mode: 'write-references',
},
}
};

React中有很多方式书写CSS样式,内联样式,CSS模块,CSS-in-JS等。下面总结一下。

1. 内联样式

内联样式是最简单直观的方式,样式直接写到组件中。这种方式只适合比较简单的样式,如果样式比较复杂,建议采用CSS Module的方式,这样能够使组件文件更加清爽。

下面是一个内联样式的例子,divh1的样式直接写在组件中。

Read more »