diff --git a/docs/1.前端/1.基础/BFC 块级格式化上下文.md b/docs/1.前端/1.基础/BFC 块级格式化上下文.md
index 56313fa1..53d0f2d0 100644
--- a/docs/1.前端/1.基础/BFC 块级格式化上下文.md
+++ b/docs/1.前端/1.基础/BFC 块级格式化上下文.md
@@ -1,16 +1,14 @@
---
title: BFC 块级格式化上下文
-createTime: 2022-03-26T11:46:50.024Z
-permalink: /article/o5g7ggvf
+createTime: 2018/05/17 12:28:33
+permalink: /article/o5g7ggvf/
author: pengzhanbo
-top: false
-tags:
+tags:
- html
-type: null
---
## 概念
-BFC, Block Formating Context。是 W3C CSS2.1规范中的一个概念。 是页面中的一块块级渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和作用。
+BFC, Block Formatting Context。是 W3C CSS2.1规范中的一个概念。 是页面中的一块块级渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和作用。
具有BFC特性的元素,可以看做是一个被隔离了的独立容器,容器内的元素不会在布局上影响到外面的元素,并且BFC具有普通容器所没有的一些特性。
diff --git a/docs/1.前端/1.基础/CSS at-rule.md b/docs/1.前端/1.基础/CSS at-rule.md
index 02c6be7b..dbc6c1db 100644
--- a/docs/1.前端/1.基础/CSS at-rule.md
+++ b/docs/1.前端/1.基础/CSS at-rule.md
@@ -1,12 +1,10 @@
---
title: CSS At-Rules
-createTime: 2022-03-26T11:46:50.024Z
-permalink: /article/btkqop1a
+createTime: 2018/10/06 08:16:38
+permalink: /article/btkqop1a/
author: pengzhanbo
-tags:
+tags:
- css
-top: false
-type: null
---
## @charset
diff --git a/docs/1.前端/1.基础/CSS media媒体查询.md b/docs/1.前端/1.基础/CSS media媒体查询.md
index 55eb4e63..a489c01c 100644
--- a/docs/1.前端/1.基础/CSS media媒体查询.md
+++ b/docs/1.前端/1.基础/CSS media媒体查询.md
@@ -1,12 +1,10 @@
---
title: CSS 媒体查询
-createTime: 2022-03-26T11:46:50.024Z
-permalink: /article/fe5ruia1
+createTime: 2018/08/18 08:43:02
+permalink: /article/fe5ruia1/
author: pengzhanbo
-tags:
+tags:
- css
-top: false
-type: null
---
开发响应式网站时,常常需要使用到 media 媒体查询。这里总结下媒体查询的使用方法。
diff --git a/docs/1.前端/1.基础/CSS选择器.md b/docs/1.前端/1.基础/CSS选择器.md
index 1eb5d687..c8d129ad 100644
--- a/docs/1.前端/1.基础/CSS选择器.md
+++ b/docs/1.前端/1.基础/CSS选择器.md
@@ -1,12 +1,10 @@
---
title: CSS选择器
-createTime: 2022-03-26T11:46:50.024Z
-permalink: /article/8vev8ixl
+createTime: 2018/09/20 03:29:20
+permalink: /article/8vev8ixl/
author: pengzhanbo
-tags:
+tags:
- css
-top: false
-type: null
---
## Basic Selectors 基础选择器
diff --git a/docs/1.前端/1.基础/DOCTYPE 文档类型声明.md b/docs/1.前端/1.基础/DOCTYPE 文档类型声明.md
index 282a12ea..46d81447 100644
--- a/docs/1.前端/1.基础/DOCTYPE 文档类型声明.md
+++ b/docs/1.前端/1.基础/DOCTYPE 文档类型声明.md
@@ -1,12 +1,10 @@
---
title: 文档类型声明
-createTime: 2022-03-26T11:46:50.025Z
-permalink: /article/s8udp6vp
+createTime: 2018/03/14 01:06:52
+permalink: /article/s8udp6vp/
author: pengzhanbo
-tags:
+tags:
- html
-top: false
-type: null
---
Web世界中,随着历史的发展,技术的迭代,发展出了许多不同的文档,只有了解文档的类型,浏览器才能正确的解析渲染文档。
diff --git a/docs/1.前端/1.基础/HTML5新特性.md b/docs/1.前端/1.基础/HTML5新特性.md
index 7d2b1be1..93f6c32f 100644
--- a/docs/1.前端/1.基础/HTML5新特性.md
+++ b/docs/1.前端/1.基础/HTML5新特性.md
@@ -1,12 +1,10 @@
---
title: HTML5新特性
-createTime: 2022-03-26T11:46:50.025Z
-permalink: /article/8rv45yuy
+createTime: 2018/02/17 12:49:58
+permalink: /article/8rv45yuy/
author: pengzhanbo
-tags:
+tags:
- html
-top: false
-type: null
---
## 语义标签
diff --git a/docs/1.前端/1.基础/WebComponent-template.md b/docs/1.前端/1.基础/WebComponent-template.md
index 29fff30f..2df5e385 100644
--- a/docs/1.前端/1.基础/WebComponent-template.md
+++ b/docs/1.前端/1.基础/WebComponent-template.md
@@ -1,14 +1,12 @@
---
title: WebComponent——template
lang: zh-CN
-tags:
- - html
+tags:
+ - WebComponent
- javascript
-createTime: 2022-03-26T11:46:50.025Z
-permalink: /article/5fmy4kla
+createTime: 2018/8/2 11:15:27
+permalink: /article/5fmy4kla/
author: pengzhanbo
-top: false
-type: null
---
在web开发领域中,模板并不少见。从服务器端的模板语言,如`Django`、`jsp`等,应用十分广泛,存在了很长时间。又如前端,早期例如`art(artTemplate)`,以及近年来,大多数的MV*框架涌现,绝大多数在展现层使用了同样的渲染机制:模板。
diff --git a/docs/1.前端/1.基础/WebComponent自定义元素.md b/docs/1.前端/1.基础/WebComponent自定义元素.md
index e122af64..26937359 100644
--- a/docs/1.前端/1.基础/WebComponent自定义元素.md
+++ b/docs/1.前端/1.基础/WebComponent自定义元素.md
@@ -1,13 +1,11 @@
---
title: WebComponent——custom elements
-tags:
- - html
+tags:
+ - WebComponent
- javascript
-createTime: 2022-03-26T11:46:50.025Z
-permalink: /article/m63fd7lf
+createTime: 2018/08/01 11:15:27
+permalink: /article/m63fd7lf/
author: pengzhanbo
-top: false
-type: null
---
diff --git a/docs/1.前端/1.基础/javascript模块化.md b/docs/1.前端/1.基础/javascript模块化.md
new file mode 100644
index 00000000..9c9dc4dd
--- /dev/null
+++ b/docs/1.前端/1.基础/javascript模块化.md
@@ -0,0 +1,239 @@
+---
+title: javascript模块化 发展历程
+createTime: 2022/04/10 03:00:41
+author: pengzhanbo
+permalink: /article/javascript-modules/
+---
+
+javascript模块化的发展,距今已有10个年头左右。
+
+## 无模块化
+
+在早期,javascript作为一门脚本语言,仅为协助表单校验等界面辅助增强,那时候的前端也比较简单, javascript不需要模块化。
+
+## 命名空间
+
+后来随着 javascript 需要承担更多的功能,代码量开始上升,为了避免全局命名冲突等问题,提出了使用命名空间的方案,将符合某种规则或者约定的代码,放到同一个命名空间下。 这算是 javascript模块化最早期的雏形。
+
+``` js
+YAHOO.util.Event.stopPropagation(e);
+```
+
+## 基本的模块化
+
+在这个时期,出现了比较清晰的模块定义,通过闭包来做模块运行空间
+``` js
+// 定义模块
+YUI.add('hello', function(Y) {
+ Y.sayHello = function() {
+ Y.DOM.set(el, 'innerHTML', 'hello!');
+ }
+}, '1.0.0',
+ requires: ['dom']);
+
+...
+// 使用模块
+YUI().use('hello', function(Y) {
+ Y.sayHello('entry'); //
hello!
+})
+```
+
+## CommonJs
+
+CommonJs 其实是一个项目,其目标是为 JavaScript 在网页浏览器之外创建模块约定, 在当年 javascript 的模块化思想还在官方的讨论中, 缺乏普遍可接受形式的javascript脚本模块单元。
+
+CommonJs规范和当时出现的NodeJs相得益彰,共同走入了开发者的实现。
+
+但 CommonJs 其实是面向网页浏览器之外的(如NodeJs,即面向服务端的模块化规范),并不适用于浏览器端。
+
+### CommonJs 规范简介
+
+在CommonJs 规范中, 每个文件都是一个模块,有自己的作用域,在文件中定义的变量、函数、类等,都是私有的,对其他文件不可见。
+
+在每个模块中,有两个内部变量可以使用, `require` 和 `module`
+
+- `require` 用于加载某个模块。
+- `module` 表示当前模块,是一个对象。这个对象中保存了当前模块的信息。`exports` 是 `module` 上的一个属性,保存了当前模块要导出的接口或者变量,使用 `require` 加载的某个模块获取到的值就是那个模块使用 `exports` 导出的值。
+
+::: code-tabs
+
+@tab a.js
+``` js
+var name = 'Mark';
+var age = 18;
+
+module.exports.name = name;
+module.exports.getAge = function () {
+ return age;
+}
+```
+
+@tab:active b.js
+``` js
+var moduleA = require('./a.js')
+console.log(moduleA.a); // Mark
+// 使用了未导出的变量,获取不到值
+console.log(moduleA.age) // undefined
+console.log(moduleA.getAge()); // 18
+```
+:::
+
+
+在NodeJs环境中,CommonJs的模块由于在服务器环境下,可以从本地进行加载,即 同步加载。
+
+## AMD、CMD
+
+::: note 注释
+在我的印象中, CommonJs规范 和 AMD规范 出现的时间点 相差不远。
+
+*AMD 早于 CommonJs*
+
+按我个人理解,CMD 在当年算是从 AMD 衍生出来的一个方案。
+:::
+::: warning 注意
+CommonJs 和 CMD 是两种方案!不是一样的!
+:::
+
+### AMD规范
+AMD规范,即 异步模块定义([Asynchronous Module Definition](https://github.com/amdjs/amdjs-api/wiki/AMD))。
+
+AMD 采用 __异步加载模块__ 的方式。
+
+AMD规范仅定义了一个 `define` 函数,它是一个全局变量:
+```
+define(id?, dependencies?, factory);
+```
+- `id` 描述的是当前模块的标识符;
+- `dependencies` 则是当前模块的依赖数组, 它们会在 factory工厂方法被调用前被加载并执行,
+ 并且执行的结果必须以依赖数组定义的顺序,依此顺序作为参数传入 factory工厂方法。
+- `factory`为模块初始化要执行的函数或者对象。如果函数返回一个值,则该值应该设置为该模块的输出值。
+
+### CMD规范
+
+CMD规范,即 公共模块定义([Common Module Definition](https://github.com/cmdjs/specification/blob/master/draft/module.md))
+
+CMD规范 定义了 一个 `define` 函数,它是一个全局变量:
+
+```
+define(id?, dependencies?, factory);
+```
+
+- `id` 描述的是当前模块的标识符;
+- `dependencies` 是当前模块的依赖数组, 他们会在 factory 工厂方法被调用前完成加载,但并不立即执行。
+- `factory`为模块初始化要执行的函数或者对象。
+ - 如果是一个函数,则函数接受三个参数:
+ ``` js
+ define(function (require, exports, module))
+ ```
+ `require` 用于同步加载并执行已经定义好的其他模块;获取模块的输出值,
+ `exports`是`module.exports`的别名,用于导出当前模块的输出值;`module`存储了当前模块的信息。
+ - 如果是一个对象,则直接作为当前模块的输出值。
+
+::: tip 两者的差异
+
+AMD规范 和 CMD规范 从规范定义上来看,主要的差异为:
+
+- AMD 的模块在加载后是立即执行的,并且会按照依赖顺序依次传入 factory,
+ 而 CMD的模块在加载后并不立即执行,而是在 factory方法中,通过 `require` 方法调用执行模块获取结果;
+:::
+
+### 规范的实现
+
+- AMD流行的实现库是 [require.js](https://github.com/requirejs/requirejs);
+- CMD流行的实现库是 [sea.js](https://github.com/seajs/seajs);
+
+::: warning 提示
+由于在当下已经越来越少会去选择使用 `require.js` 以及 `sea.js`, 这里就不多对这两个库做介绍说明。
+:::
+
+## NodeJs前端工具链
+
+得益于 NodeJs 的能力,开源社区在模块化方面又再次向前继续迈进。 特别是在推出了 `NPM` 包管理工具后,前端的工具、模块化出现了井喷式发展。
+
+### grunt gulp
+
+既然 CommonJs 不适用于 浏览器端的一个主要原因是同步加载和异步加载之间的问题,那么借助于 `grunt` 或 `gulp` 提供的前端工具,在开发时,还是以文件一模块,然后构建时,将模块文件打包在一起,那么由于都是在同一个文件中,则模块之间的加载则可以是同步的。
+
+在这个时期,`grunt`、`gulp` 并没有提供直接的模块化打包能力,但是在其基础上,通过插件实现了文件合并,从而能够在开发时,以 某种模块规范进行项目架构和管理,再进行打包构建。
+
+### webpack NPM
+
+真正让 前端模块化得到质的飞跃的,是 NPM的推出,内置到了 NodeJS 中。
+
+而 webpack 的出现,这块 真正意义上的 模块打包工具,配合 NPM, 让模块化越来越得以更方便的运用于应用开发中。
+
+webpack 作为一个 模块打包器, 在内部根据 CommonJs规范实现了 模块加载器,使得应用于浏览器端的javascript代码,也能够像 Node端的 javascript代码,拥有类似甚至相同的文件组织结构。
+
+实现了一文件一模块,模块之间通过 `require` 函数进行 访问。
+
+而 NPM的推出与流行,在前端引入了 `package` 包的概念,模块以包的形式进行管理, 让越来越多的开发者,能够共享各自开发的模块,开发者可以通过 NPM 安装其他开发者已开发好的模块,然后通过 `webpack` 实现开发时加载这些模块。
+
+webpack 内部实现了 不同的 模块化规范,包括 匿名函数闭包`iife`, `AMD`, `CMD`,`CommonJs`等。
+
+`webpack` 不仅将 javascript 作为模块,而是将一切资源都作为模块进行处理。
+
+### 其他的模块打包工具
+
+- [rollup](https://github.com/rollup/rollup) 轻量且快速的模块打包工具
+- [parcel](https://github.com/parcel-bundler/parcel) 零配置的开箱即用的模块打包工具
+- [vite](https://github.com/vitejs/vite) 基于rollup的前端工具
+- more...
+
+### 其他包管理工具
+
+- [yarn](https://classic.yarnpkg.com/lang/en/)
+- [pnpm](https://pnpm.io/)
+- more...
+
+::: info 说明
+与`npm` 对比,都是社区对于 包管理 的不同理念、不同实践 下所产生的工具。
+三者互相发展,并都有各自的特色。
+:::
+
+## ES Modules
+
+[ES Modules](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Modules)
+
+随着 javascript的发展,ECMAScript将模块加载添加到了标准之中,浏览器也开始支持 模块加载。
+
+使用 Javascript 模块依赖于 `import` 和 `export` 进行导入和导出。
+
+在 `html` 导入 javascript模块脚本是,需要在 `
+```
+::: code-tabs
+
+@tab moduleA.js
+``` js
+import { name, getAge } from './moduleB.js';
+
+console.log(name);
+console.log(getAge());
+```
+
+@tab moduleB.js
+``` js
+export const name = 'Mark';
+
+const age = 18;
+
+export function getAge() {
+ return age;
+}
+```
+:::
+
+
+
+## Deno模块加载
+
+Deno与 Node在模块加载上最大的差别, 就是 放弃了 项目中的`node_modules` 作为第三方包的存放目录,也抛弃了 类似于 NPM 的中心化管理的 模块管理工具。
+
+Deno 推荐使用的是 去中心化的模块加载管理,支持直接从远程的任意站点加载提供的模块。
+
+如从 官方的 [deno.lang](https://deno.land/),或者从 [unpkg.com](https://unpkg.com/) 加载第三方模块。
+
+::: info 说明
+这种去中心化模块管理的模块加载方案,相对来说会比较依赖于网络环境,虽然远程的模块首次加载后也会被缓存,但进行生产部署时,往往生产服务器跟公网是隔离的,在这种情况下,就需要自建一个内部服务器作为代理,托管第三方的模块包。
+:::
diff --git a/docs/1.前端/1.基础/meta 标签说明.md b/docs/1.前端/1.基础/meta 标签说明.md
index eb14ea54..e5b9ce6c 100644
--- a/docs/1.前端/1.基础/meta 标签说明.md
+++ b/docs/1.前端/1.基础/meta 标签说明.md
@@ -1,12 +1,10 @@
---
title: meta 标签说明
-createTime: 2022-03-26T11:46:50.025Z
-permalink: /article/bp1nxjs6
+createTime: 2018/03/15 01:21:48
+permalink: /article/bp1nxjs6/
author: pengzhanbo
-tags:
+tags:
- html
-top: false
-type: null
---
标签提供关于 HTML 文档的元数据。它不会显示在页面上,但是对于机器是可读的。可用于浏览器(如何显示内容或重新加载页面),搜索引擎(关键词),或其他 web 服务。
diff --git a/docs/1.前端/1.基础/原型链与继承.md b/docs/1.前端/1.基础/原型链与继承.md
index a89dcaf8..575ccaf8 100644
--- a/docs/1.前端/1.基础/原型链与继承.md
+++ b/docs/1.前端/1.基础/原型链与继承.md
@@ -1,17 +1,15 @@
---
title: 继承与原型链
-createTime: 2022-03-26T13:40:54.727Z
-permalink: /article/extends-prototype
+createTime: 2018/07/06 09:40:54
+permalink: /article/extends-prototype/
author: pengzhanbo
-tags:
+tags:
- javascript
-top: false
-type: null
---
当谈到继承时,javascript只有一种结构:对象。
-每个实例对象(object)都有一个私有属性(\_\_proto\_\_)指向它的构造函数的原型对象(__prototype__)。
-该原型对象也有自己的原型对象((\_\_proto\_\_),层层向上,直到有一个的原型对象为null。根据定义,null没有原型,并作为这个原型链的最后一个环节。
+每个实例对象(object)都有一个私有属性`__proto__`指向它的构造函数的原型对象 __prototype__。
+该原型对象也有自己的原型对象`__proto__`,层层向上,直到有一个的原型对象为null。根据定义,null没有原型,并作为这个原型链的最后一个环节。
@@ -20,3 +18,165 @@ type: null
## 基于原型链的继承
### 继承属性
+
+`javascript` 对象是动态的属性"包裹"(指自身的属性)。同时,对象还有一个指向一个原型对象的链。
+当访问一个对象的属性时,不仅会在该对象上查找,也会在该对象的原型上查找,进而在该对象的原型的原型上查找,
+依次层层向上查找,直到找到匹配的属性,或者到达原型链的末尾。
+
+::: info ECMAScript标准
+`obj.[[Prototype]]`符号用于指向`obj`的原型。从`ES6`开始`[[Prototype]]`
+可以通过`Object.getPrototypeof()`和 `Object.setPrototypeof()` 访问器进行访问。
+等同于许多浏览器实现的属性`__proto__`。
+:::
+
+从代码示例来分析继承属性:
+
+在这个示例中,定义了一个函数`Foo`, 它拥有自身属性 `a`和`b`。
+
+然后创建一个 `Foo` 的示例 `foo`。
+``` js
+function Foo() {
+ this.a = 1
+ this.b = 2
+}
+let foo = new Foo()
+
+Foo.prototype.c = 3
+Foo.prototype.d = 4
+
+// 输出自身的所有属性
+console.log(foo) // { a: 1, b: 2 }
+
+// 自身拥有属性 a
+console.log(foo.a) // 1
+// 自身拥有属性 b
+console.log(foo.b) // 2
+// 自身没有属性 c, 但其原型上有属性 c
+console.log(foo.c) // 3
+// 自身没有属性 d,但其原型上有属性 d
+console.log(foo.d) // 4
+
+```
+在这个示例中, 整个原型链如下
+``` js
+// { a: 1, b: 2 } => { c: 3, d: 4 } => Object.prototype => null
+```
+
+### 继承方法
+
+在`Javascript` 中,并没有其他基于类的语言所定义的 方法。
+任何函数都可以添加到对象上做为对象的属性。
+函数属性的继承与其他属性的继承没有差别。
+
+当继承的函数被调用时,`this`指向的是当前继承的对象,而不是继承的函数所在的原型对象。
+
+``` js
+var o = {
+ a: 1,
+ f: function() {
+ return this.a + 1
+ }
+}
+
+// 此时 函数f 中的 this 指向了 o
+console.log(o.f()) // 2
+
+var p = Object.create(0)
+p.a = 3
+
+// p从o上继承了函数f, 此时函数f中的 this 指向了 p
+console.log(p.f()) // 4
+```
+
+## 创建对象和生成原型链
+
+### 使用语法结构创建的对象
+``` js
+var o = { a: 1 }
+// 原型链: o => Object.prototype => null
+
+var arr = ['a', 'b']
+// 原型链: arr => Array.prototype => Object.prototype => null
+
+function f() {}
+// 原型链: f => Function.prototype => Object.prototype => null
+```
+
+### 使用构造器创建对象
+``` js
+function Person() {
+ this.a = 1
+}
+Person.prototype = {
+ f: function () {
+ return this.a
+ }
+}
+var p = new Person()
+// 原型链: p => Person.prototype => Object.prototype => null
+```
+
+### 使用`Object.create`创建的对象
+``` js
+var a = { a: 1 }
+var b = Object.create(a)
+// 原型链 b => a => Object.prototype => null
+
+var c = Object.create(null)
+// 原型链 c => null
+```
+
+
+## 扩展原型链的方法
+
+### 构造器创建对象,原型赋值给另一个构造函数原型
+``` js
+function foo() {}
+foo.prototype = {
+ a: 'foo'
+}
+
+function bar() {}
+
+var proto = new foo()
+proto.b = 'bar'
+bar.prototype = proto
+
+var p = new bar()
+console.log(p.a) // foo
+console.log(p.b) // bar
+```
+
+### Object.create
+``` js
+function foo() {}
+foo.prototype = {
+ a: 'foo'
+}
+function bar() {}
+
+var proto = Object.create(foo.prototype)
+proto.b = 'bar'
+bar.prototype = proto
+
+var p = new bar()
+console.log(p.a) // foo
+console.log(p.b) // bar
+
+```
+
+``` js
+function foo() {}
+foo.prototype = {
+ a: 'foo'
+}
+
+function bar() {}
+
+var proto = Object.create(foo.prototype, { b: 'bar' })
+bar.prototype = proto
+
+var p = new bar()
+console.log(p.a) // foo
+console.log(p.b) // bar
+```
diff --git a/docs/1.前端/1.基础/正则表达式使用手册.md b/docs/1.前端/1.基础/正则表达式使用手册.md
index 3fb9556b..b09884f3 100644
--- a/docs/1.前端/1.基础/正则表达式使用手册.md
+++ b/docs/1.前端/1.基础/正则表达式使用手册.md
@@ -1,10 +1,10 @@
---
title: 正则表达式
lang: zh-CN
-createTime: 2022-03-26T11:46:50.025Z
-permalink: /article/e8qbp0dh
+createTime: 2018/11/26 11:15:27
+permalink: /article/e8qbp0dh/
author: pengzhanbo
-tags:
+tags:
- javascript
top: false
type: null
@@ -56,7 +56,7 @@ _以下讨论以正则表达式字面量来创建正则表达式_
元字符也叫特殊字符,是正则表达式规定的,对符合特定的单一的规则的字符的描述。
| 字符 | 含义 |
|:----:|-----|
-|\\|在非特殊字符的前面加反斜杠,表示这个字符是特殊的,不能从字面上解释。比如在`\d`描述的不是一个普通的字符`d`,而是正则表达式中的数值`0-9`。
如果在特殊字符前面加反斜杠,这表示将这个字符转义为普通字符,比如`?`在正则中有其特殊含义,前面加反斜杠\?,这可以将其转为普通的`?`。|
+| \\ |在非特殊字符的前面加反斜杠,表示这个字符是特殊的,不能从字面上解释。比如在`\d`描述的不是一个普通的字符`d`,而是正则表达式中的数值`0-9`。
如果在特殊字符前面加反斜杠,这表示将这个字符转义为普通字符,比如`?`在正则中有其特殊含义,前面加反斜杠\?,这可以将其转为普通的`?`。|
|^|匹配文本开始的位置,如果开启了多行标志,也会匹配换行符后紧跟的位置。
比如`^a`会匹配`abc`,但不会匹配到`bac`。|
|$|匹配文本结束的位置,如果开启了多行标志,也会匹配换行符前紧跟的位置。
比如`b$`会匹配`acb`,但不会匹配到`abc`。|
|*|匹配前一个表达式0次到多次。
比如,`ab*`会匹配到`abbbbbbc`中的`abbbbbb`,以及`acbbbbb`中的`a`。|
diff --git a/docs/1.前端/1.基础/浏览器端的事件循环.md b/docs/1.前端/1.基础/浏览器端的事件循环.md
index 8cc786e5..e9cd6d59 100644
--- a/docs/1.前端/1.基础/浏览器端的事件循环.md
+++ b/docs/1.前端/1.基础/浏览器端的事件循环.md
@@ -1,9 +1,189 @@
---
title: Event Loop 浏览器端的事件循环
-createTime: 2022-03-26T11:46:50.000Z
-permalink: /article/browser-event-loop
+createTime: 2021/06/03 01:53:17
+permalink: /article/browser-event-loop/
author: pengzhanbo
-top: false
-type: null
+tags:
+ - javascript
---
+事件循环,即 Event-Loop。
+
+## 什么是 Event-Loop ?
+
+Event-Loop 是一个执行模型,在 [html5规范](https://html.spec.whatwg.org/multipage/webappapis.html#event-loops) 中进行了浏览器端的 Event-Loop 的明确定义。
+
+## 宏任务与微任务
+
+javascript 有两种异步任务,分别是`宏任务`和`微任务`
+
+### 宏任务
+
+宏任务,`macro task`,也叫 `tasks`,一些异步任务的回调会依次进入 `macro task queue`,等待后续被调用。
+
+这些异步任务包括:
+- setTimeout
+- setInterval
+- setImmediate (Node独有)
+- requestAnimationFrame (浏览器独有)
+- I/O
+- UI rendering
+
+### 微任务
+
+微任务, `micro task`, 也叫 `jobs`,另一些异步任务的回调会依次进入`micro task queue`,等待后续被调用。
+
+这些异步任务包括:
+- process.nextTick(Node独有)
+- Promise
+- Object.observe
+- MutationObserver
+
+## 事件循环 Event Loop
+
+1. 执行全局 `script` 代码,这些代码有一些是同步语句,有一些是异步语句(如: setTimeout);
+2. 全局`script`同步代码执行完毕后,调用栈Stack会清空;
+3. 从微任务`micro task queue` 中取出位于队首的任务,放入调用栈Stack中执行,执行完后`micro task queue`长度减一;
+4. 继续取出微任务`micro task queue`位于队首的任务,放入调用栈Stack中执行,
+ 以此类推,直到把`micro task queue`中的所有任务都执行完毕。__注意,如果在执行micro task的过程中,产生了`micro task`那么会加入到队列的末尾,也会在这个周期被调用执行__;
+5. `micro task`中的所有无人都执行完毕,此时 `micro task queue` 为空队列,调用栈Stack也为空;
+6. 取出宏队列 `macro task queue` 中位于队首的任务,放入Stack中执行;
+7. 执行完毕后,调用栈Stack为空;
+8. 重复第3-7个步骤;
+9. 以此继续循环重复;
+
+::: tip 重点
+1. 宏任务`marco task` 一次只从队列中取出一个任务执行,执行后就去执行微任务队列中的任务;
+2. 微任务队列中所有的任务都会依次取出来执行,直到`micro task queue`为空,
+ 且当前微任务执行过程中产生新的`micro task`,也会加入到当前`micro task queue`;
+3. `UI Rendering`由浏览器自定判断决定执行节点。但是只要执行`UI Rendering`,它的节点是在执行完所有
+ `micro task`之后,下一个`macro task`之前,紧跟着执行`UI Rendering`
+:::
+
+尝试从代码层面来分析 event-loop:
+
+::: note 抖个机灵
+代码人看代码应该比看流程图要来得好理解了吧(bushi)
+:::
+
+``` js
+// 执行器
+// 接收一段javascript代码
+class Execution {
+ constructor(code) {
+ this.code = code
+ this.macroTaskQueue = []
+ this.microTaskQueue = []
+ }
+
+ // 启动执行
+ exec() {
+ // 首次运行,将 传入的 code 推入到 Track中执行
+ // 并获取其中的 宏任务和 微任务
+ const { macroTaskQueue, microTaskQueue } = this.run(this.code)
+ // 将宏任务和微任务 推入到 各自的 队列中
+ this.macroTaskQueue.push(...macroTaskQueue)
+ this.microTaskQueue.push(...microTaskQueue)
+ // 开始执行微任务
+ this.runMicroTaskQueue()
+ }
+
+ // 执行微任务队列
+ runMicroTaskQueue() {
+ // 遍历 微任务队列中的所有任务
+ // 当当前的 微任务队列清空时,遍历才结束
+ while (this.microTaskQueue.length) {
+ // 取出 队首的微任务
+ const task = this.microTaskQueue.shift()
+ // 将 当前微任务 推入到 执行栈中执行
+ // 并将返回的 宏任务和微任务 继续 推入到 各自的队列中
+ const { macroTaskQueue, microTaskQueue } = this.run(task)
+ this.macroTaskQueue.push(...macroTaskQueue)
+ this.microTaskQueue.push(...microTaskQueue)
+ }
+ // 当前微任务执行完毕,继续执行宏任务
+ this.runMacroTaskQueue()
+ }
+
+ // 执行宏任务队列
+ runMacroTaskQueue() {
+ // 从 宏任务队列队首 取出一个 宏任务
+ const task = this.macroTaskQueue.shift()
+ // 将当前 宏任务 推入到 执行栈中执行
+ // 并将返回的 宏任务和微任务 继续 推入到 各自的队列中
+ const { macroTaskQueue, microTaskQueue } = this.run(task)
+ this.macroTaskQueue.push(...macroTaskQueue)
+ this.microTaskQueue.push(...microTaskQueue)
+ // 再一次执行 微任务队列中的任务
+ this.runMicroTaskQueue()
+ }
+
+ // 执行栈调用
+ run(task) {
+ // track 函数表示 执行栈
+ // 执行完毕返回 产生的 微任务队列 和 宏任务队列
+ const { macroTaskQueue, microTaskQueue } = track(task)
+ return { macroTaskQueue, microTaskQueue }
+ }
+}
+const execute = new Execution(scriptCode)
+execute.exec()
+```
+
+`event-loop` 概念性的内容大体就这么多,接下来从示例中来实际执行情况。
+
+## 示例
+
+::: warning 注意
+以下示例是在 `Chrome` 中执行后获得的结果,在其他浏览器的表现并不一定完全相同。
+:::
+
+
+可以尝试自己心中执行这段代码后的打印顺序,再切换到`Console`中看实际的运行结果,是否符合你的预期结果。
+
+::: code-tabs
+
+@tab javascript
+``` js
+console.log('script')
+
+setTimeout(() => {
+ console.log('timeout 1')
+ Promise.resolve().then(() => {
+ console.log('promise 1')
+ })
+})
+
+new Promise((resolve) => {
+ console.log('promise resolver')
+
+ Promise.resolve().then(() => {
+ console.log('promise 3')
+ })
+
+ resolve('promise 2')
+}).then((data) => {
+ console.log(data)
+})
+
+setTimeout(() => {
+ console.log('timeout 2')
+})
+
+console.log('end')
+```
+
+
+@tab Console
+``` txt
+script
+promise resolver
+end
+promise 3
+promise 2
+timeout 1
+promise 1
+timeout 2
+```
+:::
+
diff --git a/docs/1.前端/1.基础/详解Promise.md b/docs/1.前端/1.基础/详解Promise.md
index cf8b94ed..3ccec921 100644
--- a/docs/1.前端/1.基础/详解Promise.md
+++ b/docs/1.前端/1.基础/详解Promise.md
@@ -1,10 +1,10 @@
---
title: 详解 Promise
-createTime: 2022-03-26T11:46:50.026Z
-permalink: /article/q40nq4hv
+createTime: 2020/11/22 12:58:28
+permalink: /article/q40nq4hv/
author: pengzhanbo
-sticky: true
-type: null
+tags:
+ - javascript
---
## 概述
@@ -47,6 +47,8 @@ Promise 创建后,必然处于以下几种状态
*then()* 接收两个函数参数(也可以仅接收一个函数参数 onFulfilled)。
- onFulfilled 函数参数,表示当 promise的状态从 `pending` 更新为`fulfilled` 时触发,并将成功的结果 value 作为`onFulfilled`函数的参数。
- onRejected 函数参数,表示当promise的状态从 `pending` 更新为`rejected` 时触发,并将失败的原因 reason 作为 `onRejected`函数的参数。
+
+ *then()* 方法返回的结果会被包装为一个新的promise实例。
#### `.catch(onRejected)`
*catch()* 可以相当于 *.then(null, onRejected)*,即仅处理当promise的状态从 `pending` 更新为`rejected` 时触发。
@@ -90,6 +92,162 @@ promise
})
```
+## Promise代码实现
+```js
+const PENDING = "pending";
+const FULFILLED = "fulfilled";
+const REJECTED = "rejected";
+const microtask = globalThis.queueMicrotask || ((cb) => setTimeout(cb, 0));
+
+function LikePromise(resolver) {
+ if (typeof resolver !== "function") {
+ throw new TypeError(`Promise resolver ${resolver} is not a function`);
+ }
+ this.state = PENDING;
+ this.value = undefined;
+ this.reason = undefined;
+ this.fulfillQueue = [];
+ this.rejectQueue = [];
+
+ const that = this;
+
+ function reject(reason) {
+ if (that.state === PENDING) {
+ that.state = REJECTED;
+ that.reason = reason;
+ that.rejectQueue.forEach((cb) => cb(reason));
+ }
+ }
+
+ function resolve(value) {
+ if (that.state === PENDING) {
+ that.state = FULFILLED;
+ that.value = value;
+ that.fulfillQueue.forEach((cb) => cb(value));
+ }
+ }
+
+ try {
+ resolver(resolve, reject);
+ } catch (e) {
+ reject(e);
+ }
+}
+
+function resolvePromise(promise, x, resolve, reject) {
+ if (promise === x) {
+ reject(new TypeError("chaining cycle"));
+ } else if (x !== null && (typeof x === "object" || typeof x === "function")) {
+ let used = false;
+ try {
+ const then = x.then;
+ if (typeof then === "function") {
+ then.call(
+ x,
+ (y) => {
+ if (used) return;
+ used = true;
+ resolvePromise(promise, y, resolve, reject);
+ },
+ (r) => {
+ if (used) return;
+ used = true;
+ reject(r);
+ }
+ );
+ } else {
+ if (used) return;
+ used = true;
+ resolve(x);
+ }
+ } catch (e) {
+ if (used) return;
+ used = true;
+ reject(e);
+ }
+ } else {
+ resolve(x);
+ }
+}
+
+LikePromise.prototype.then = function (onFulfilled, onRejected) {
+ onFulfilled =
+ typeof onFulfilled === "function" ? onFulfilled : (value) => value;
+ onRejected =
+ typeof onRejected === "function"
+ ? onRejected
+ : (reason) => {
+ throw reason;
+ };
+ const that = this;
+ const promise = new LikePromise((resolve, reject) => {
+ if (that.state === FULFILLED) {
+ microtask(() => {
+ try {
+ const x = onFulfilled(that.value);
+ resolvePromise(promise, x, resolve, reject);
+ } catch (e) {
+ reject(e);
+ }
+ });
+ } else if (that.state === REJECTED) {
+ microtask(() => {
+ try {
+ const x = onRejected(that.reason);
+ resolvePromise(promise, x, resolve, reject);
+ } catch (e) {
+ reject(e);
+ }
+ });
+ } else {
+ that.fulfillQueue.push(() => {
+ microtask(() => {
+ try {
+ const x = onFulfilled(that.value);
+ resolvePromise(promise, x, resolve, reject);
+ } catch (e) {
+ reject(e);
+ }
+ });
+ });
+ that.rejectQueue.push(() => {
+ microtask(() => {
+ try {
+ const x = onRejected(that.reason);
+ resolvePromise(promise, x, resolve, reject);
+ } catch (e) {
+ reject(e);
+ }
+ });
+ });
+ }
+ });
+ return promise;
+};
+
+LikePromise.prototype.catch = function (onRejected) {
+ return this.then(null, onRejected);
+};
+
+LikePromise.prototype.finally = function (onFinally) {
+ return this.then(
+ (value) => LikePromise.resolve(onFinally()).then(() => value),
+ (reason) =>
+ LikePromise.resolve(onFinally()).then(() => {
+ throw reason;
+ })
+ );
+};
+
+LikePromise.resolve = function (value) {
+ return new LikePromise((resolve) => resolve(value));
+};
+
+LikePromise.reject = function (reason) {
+ return new LikePromise((_, reject) => reject(reason));
+};
+```
+
## `Promise` 静态方法
diff --git a/docs/1.前端/10.开发/1px解决方案.md b/docs/1.前端/10.开发/1px解决方案.md
index 668648aa..5191ff4b 100644
--- a/docs/1.前端/10.开发/1px解决方案.md
+++ b/docs/1.前端/10.开发/1px解决方案.md
@@ -1,13 +1,12 @@
---
title: 1px解决方案
-createTime: 2022-03-26T11:46:50.026Z
-permalink: /article/tz7ncicn
+createTime: 2019/05/15 10:41:32
+permalink: /article/tz7ncicn/
author: pengzhanbo
-tags:
+tags:
- html
- css
- develop
-banner: /images/big-banner.jpg
---
在日常移动端前端应用开发中,经常遇到一个问题就是 1px的线在移动端 Retina屏下的渲染并未达到预期。以下总几种不同场景下的 1px解决方案。
diff --git a/docs/1.前端/10.开发/lerna使用.md b/docs/1.前端/10.开发/lerna使用.md
index 60c7ec73..532ccf7b 100644
--- a/docs/1.前端/10.开发/lerna使用.md
+++ b/docs/1.前端/10.开发/lerna使用.md
@@ -1,13 +1,13 @@
---
title: lerna使用
-createTime: 2022-03-26T11:46:50.027Z
-permalink: /article/i1wc1uld
+createTime: 2021/11/26 06:28:37
+permalink: /article/i1wc1uld/
author: pengzhanbo
-top: false
-type: null
---
-
+::: center
+{ style="width: 50%" }
+:::
## 概述
diff --git a/docs/1.前端/10.开发/pnpm.md b/docs/1.前端/10.开发/pnpm.md
new file mode 100644
index 00000000..1feac4f0
--- /dev/null
+++ b/docs/1.前端/10.开发/pnpm.md
@@ -0,0 +1,280 @@
+---
+title: pnpm 包管理器
+createTime: 2022/05/10 03:50:47
+author: pengzhanbo
+permalink: /article/84nu27cz/
+---
+
+`pnpm` 是一款新兴不久的包管理器,相比于 `npm` 和 `yarn`,`pnpm` 拥有更快的安装速度,同时节约磁盘空间。
+
+
+
+## 介绍
+
+
+
+`pnpm` 是一个类似于 `npm` 、`yarn` 的包管理器。
+
+`pnpm` 安装的包都会被存储在硬盘的某个相同位置,软甲包通过硬链接到这个位置,实现共享同一版本的依赖,
+对于同一依赖的不同版本,`pnpm update` 时,只会向存储中心添加新版本更新的文件,而不是仅仅应为一个文件的改变而复制整个新版本包的内容。
+
+`pnpm` 内置支持 `monorepo`,即单仓库多包。
+
+## 比较
+
+### pnpm/yarn/npm
+
+| 功能 | pnpm | yarn | npm |
+| -- | :--: | :--: | :--: |
+| 工作空间支持(monorepo)| ✔️ | ✔️ | ✔️ |
+| 隔离的`node_modules` | ✔️ - 默认 | ✔️ | ❌ |
+| 提升的`node_modules` | ✔️ | ✔️ | ✔️ -默认 |
+| 自动安装peers | ✔️ - `auto-install-peers=true` | ❌ | ✔️ |
+| Plug'n'Play | ✔️ | ✔️ - 默认 | ❌ |
+| 零安装 | ❌ | ✔️ | ❌ |
+| 修复依赖项 | ✔️ | ✔️ | ❌ |
+| 管理nodejs版本 | ✔️ | ❌ | ❌ |
+| 有锁文件 | ✔️ - `pnpm-lock.yaml` | ✔️ - `yarn.lock` | ✔️ - `package-lock.json` |
+| 支持覆盖 | ✔️ | ✔️ - `resolutions` | ✔️ |
+| 内容可寻址存储 | ✔️ | ❌ | ❌ |
+| 动态包执行 | ✔️ - `pnpm dlx` | ✔️ - `yarn dlx` | ✔️ - `npx` |
+| Side-effects cache | ✔️ | ❌ | ❌ |
+
+### 区别
+
+与 `yarn/npm` 不同的是,`pnpm` 并非采用 *扁平的`node_modules`* 来管理依赖项,
+而是基于符号链接的`node_modules` 结构。
+
+`node_modules` 中每个包的每个文件都是来自内容可寻址存储的硬链接。 假设安装了依赖于 `bar@1.0.0` 的 `foo@1.0.0`。 `pnpm` 会将两个包硬链接到 `node_modules` 如下所示:
+
+```sh
+node_modules
+└── .pnpm
+ ├── bar@1.0.0
+ │ └── node_modules
+ │ └── bar -> /bar
+ │ ├── index.js
+ │ └── package.json
+ └── foo@1.0.0
+ └── node_modules
+ └── foo -> /foo
+ ├── index.js
+ └── package.json
+```
+这是 `node_modules` 中的唯一的“真实”文件。 一旦所有包都硬链接到 `node_modules`,
+就会创建符号链接来构建嵌套的依赖关系图结构。
+
+`bar` 将被符号链接到 `foo@1.0.0/node_modules` 文件夹,然后处理依赖关系,`foo` 将被符号链接至根目录的 `node_modules` 文件夹:
+
+```sh
+node_modules
+├── foo -> ./.pnpm/foo@1.0.0/node_modules/foo
+└── .pnpm
+ ├── bar@1.0.0
+ │ └── node_modules
+ │ └── bar -> /bar
+ └── foo@1.0.0
+ └── node_modules
+ ├── foo -> /foo
+ └── bar -> ../../bar@1.0.0/node_modules/bar
+```
+
+这种布局的好处在于,只有真正在依赖项中的包才能访问。
+如果是平铺的 `node_modules` 结构,所有被提升的包都可以访问。
+
+### 优势
+
+- 节约磁盘空间
+
+ 包存储在全局存储中,pnpm 创建从全局存储到项目下 `node_modules` 文件夹的 硬链接,硬链接指向磁盘上原始文件所在的同一位置。不同软件包可以共享相同依赖项所占用的空间。
+
+ 如果是单个依赖的不同版本,如版本更新,`pnpm` 仅安装版本更新的文件,而不是全量安装整个新版本的包。
+
+- 安装速度快
+
+ 软件包中安装依赖时,如果检索到在本地的全局存储中已安装过该依赖,那么不会从网络下重新安装,而是直接创建硬链接到软件包中。
+
+- 内置支持 monorepo
+
+ 支持 单仓库多包,通过 `pnpm-workspace.yaml` 配置工作空间,通过 `workspace:*` 协议引用工作空间的依赖包。
+
+## 安装
+
+### 通过 npm 安装
+
+```sh
+npm install -g pnpm
+```
+
+### 通过 Corepack 安装
+
+从 v16.13 开始,Node.js 发布了 `Corepack` 来管理包管理器。 这是一项实验性功能,因此需要通过运行如下脚本来启用它:
+
+```sh
+corpack enabled
+```
+
+这将自动在系统上安装 pnpm。 但是,它可能不是最新版本的 pnpm。
+若要升级,请检查 [最新的 pnpm 版本](https://github.com/pnpm/pnpm/releases/tag/v7.9.1) 并运行:
+
+```sh
+corepack prepare pnpm@ --activate
+```
+### 使用独立脚本安装
+
+在 POSIX 系统上,即使没有安装 Node.js,也可以使用以下脚本安装 pnpm:
+
+```sh
+curl -fsSL https://get.pnpm.io/install.sh | sh -
+```
+
+如果没有安装 `curl` ,也可以使用 `wget`:
+
+```sh
+wget -qO- https://get.pnpm.io/install.sh | sh -
+```
+
+在 Windows 系统中,如果使用 Powershell:
+
+```sh
+iwr https://get.pnpm.io/install.ps1 -useb | iex
+```
+
+### 使用 Homebrew 安装
+
+```sh
+brew install pnpm
+```
+
+### 使用 Scoop 安装
+
+```sh
+scoop install nodejs-lts pnpm
+```
+
+## 使用
+
+`pnpm` 在使用上 与 `npm` 、`yarn` 的使用上差别不大,但需要注意的区别,`pnpm` 会严格校验所有参数,
+比如,`pnpm install --target_arch x64` 会执行失败,因为 `--target_arch x64` 不是 `pnpm install` 的有效参数。
+
+### 常用命令
+
+#### `pnpm install`
+
+别名 `pnpm i`
+
+等效于 `npm install` / `yarn`
+
+用于安装项目所有依赖。
+
+[pnpm install 官方文档](https://pnpm.io/zh/cli/install)
+
+#### `pnpm add `
+
+安装软件包及其依赖的任何软件包。 默认情况下,任何新软件包都安装为生产依赖项。
+
+[pnpm add 官方文档](https://pnpm.io/zh/cli/add)
+
+#### `pnpm remove`
+
+别名: `rm` `uninstall` `un`
+
+从 `node_modules` 和项目的 `package.json` 中删除相关 packages。
+
+[pnpm remove 官方文档](https://pnpm.io/zh/cli/remove)
+
+#### `pnpm update`
+
+别名: `up` `upgrade`
+
+`pnpm update` 根据指定的范围更新软件包的最新版本。
+
+在不带参数的情况下使用时,将更新所有依赖关系。 您可以使用一些模式来更新特定的依赖项。
+
+[pnpm update 官方文档](https://pnpm.io/zh/cli/update)
+
+更多命令请查阅[官方文档](https://pnpm.io/zh/cli/add)
+
+### 配置
+
+#### `.npmrc`
+
+`pnpm` 从命令行、环境变量和 `.npmrc` 文件中获取其配置。
+
+`pnpm config` 命令可用于更新和编辑 用户和全局 .npmrc 文件的内容。
+
+四个相关文件分别为:
+
+- 每个项目的配置文件(`/path/to/my/project/.npmrc`)
+- 每个工作区的配置文件(包含 `pnpm-workspace.yaml` 文件的目录)
+- 每位用户的配置文件( `~/.npmrc` )
+- 全局配置文件( `/etc/.npmrc` )
+
+#### `pnpm-workspace.yaml`
+
+`pnpm-workspace.yaml` 定义了 工作空间 的根目录,并能够使工作空间中包含 / 排除目录 。 默认情况下,包含所有子目录。
+
+``` yaml
+packages:
+ # 定义 packages 目录下的所有子目录都为一个 package
+ - 'packages/*'
+ # 定义 components 目录下的所有子目录都为一个 package
+ - 'components/**'
+ # 排除任何目录中的 test 目录下的所有目录
+ - '!**/test/**'
+```
+
+## 工作空间
+
+pnpm 内置了对单一存储库(也称为多包存储库、多项目存储库或单体存储库)的支持, 你可以创建一个 workspace 以将多个项目合并到一个仓库中。
+
+一个 workspace 的根目录下必须有 `pnpm-workspace.yaml` 文件, 也可能会有 `.npmrc` 文件。
+
+### Workspace 协议 (workspace:)
+
+默认情况下,如果可用的 packages 与已声明的可用范围相匹配,pnpm 将从工作区链接这些 packages。 例如,如果 `bar` 中有 `"foo":"^1.0.0"` 的这个依赖项,则 `foo@1.0.0` 链接到 `bar。` 但是,如果 `bar` 的依赖项中有 `"foo": "2.0.0"`,而 `foo@2.0.0` 在工作空间中并不存在,则将从 `npm registry` 安装 `foo@2.0.0` 。 这种行为带来了一些不确定性。
+
+幸运的是,pnpm 支持 workspace 协议 `workspace:` 。 当使用此协议时,pnpm 将拒绝解析除本地 workspace 包含的 package 之外的任何内容。 因此,如果设置为 `"foo": "workspace:2.0.0"` 时,安装将会失败,因为 `"foo@2.0.0"` 不存在于此 workspace 中。
+
+使用示例:
+
+工作空间中存在以下项目:
+```sh
++ packages/
+ + foo/
+ + bar/
+ + qar/
+ + zoo/
+```
+
+如果各个项目以其目录名作为其 package name,那么可以在其他项目中如下引入依赖:
+
+``` json
+{
+ "dependencies": {
+ "foo": "workspace:*",
+ "bar": "workspace:~",
+ "qar": "workspace:^",
+ "zoo": "workspace:^1.5.0"
+ }
+}
+```
+
+::: tip
+引入依赖的包名,是由包的 `package.json name` 确定,而不是 workspace 目录下的目录名确定。
+:::
+
+### 发布 Workspace
+
+当以上示例进行发布时,会被转换为
+```json
+{
+ "dependencies": {
+ "foo": "1.5.0",
+ "bar": "~1.5.0",
+ "qar": "^1.5.0",
+ "zoo": "^1.5.0"
+ }
+}
+```
+这个功能允许你发布转化之后的包到远端,并且可以正常使用本地 workspace 中的 packages,而不需要其它中间步骤。包的使用者也可以像常规的包那样正常使用,且仍然可以受益于语义化版本。
diff --git a/docs/1.前端/10.开发/前端路由.md b/docs/1.前端/10.开发/前端路由.md
new file mode 100644
index 00000000..7bbdd88b
--- /dev/null
+++ b/docs/1.前端/10.开发/前端路由.md
@@ -0,0 +1,135 @@
+---
+title: 前端路由
+createTime: 2019/09/13 04:13:56
+author: pengzhanbo
+permalink: /article/xhb2iacu/
+---
+
+在现代前端中,SPA应用是一种主流的前端应用交互方案,其中,前端路由是实现SPA应用的关键技术之一。
+
+
+
+## 路由
+
+**路由(Router)** 一般指的是 URI 中 pathname + basename + hash + query 所组成的 路径。
+
+在前端中, **路由** 一般指的是 **随着浏览器中的地址栏的变化,呈现不同的内容给用户**。
+浏览器地址栏的变化,即是 访问链接的变化,具体指的就是 pathname + basename + hash + query 部分的变化。
+
+示例:
+
+```
+/a/b
+/a/b/#/hash
+/a/b/#/hash?c=1
+```
+
+对于前端路由,一般会选择 监听 hash 部分的变化, 或者监听 pathname 部分的变化,从而一般有两种路由模式:
+
+
+### hash 模式
+
+通过监听 地址栏中 hash 部分的变化,从而呈现不同的内容。
+
+::: center
+**https://example.com/index.html ==#/a/b/==**
+:::
+
+在浏览器中,通过注册 **hashchange** 事件,监听 **hash** 变化。
+
+``` js
+window.addEventListener('hashchange', () => {
+ const hash = window.location.hash;
+ console.log(hash) // #/a/b/
+})
+```
+
+通过 hash 实现路由的优势在于, hash 仅依赖于浏览器,且hash的变化不会直接导致页面刷新,天然适合于实现 前端路由。
+
+### history 模式
+
+通过监听 地址栏中 pathname 部分的变化,从而呈现不同的内容。
+
+history模式是依赖于 浏览器端的 History API 而实现。
+History API 允许我们对浏览器会话历史记录进行访问并操作。
+
+::: center
+**https://example.com ==/a/b/==**
+:::
+
+History API 通过 history.pushState() 和 history.replaceState() 方法,新增或者替换历史记录,
+通过 popState 事件监听历史记录的变化。
+
+
+直接操作历史记录的变化,结果会改变浏览器地址栏的显示内容,但不会引起浏览器刷新页面。
+但是由于变化的部分一般是 `pathname + basename` 的部分,如果手动刷新页面,可能会导致浏览器通过当前路径
+向服务器发起请求找不到对应的资源而返回404,所以一般需要在服务器端的HTTP服务器进行配置,将相关的路径请求资源,
+都指向同一个html资源文件。
+
+> [History API](https://developer.mozilla.org/zh-CN/docs/Web/API/History_API)
+
+### 其他模式
+
+除了上述两种一般用于浏览器端中的路由模式,为了满足其他的场景,比如 在SSR场景下,需要在服务端模拟路由在生成页面内容,
+或者在 electron 桌面应用中。一般会基于 memory 实现一种 仅通过 memory 的变化的路由的模式。
+
+在这个模式中,通过一个普通的 JavaScript 字符串或者对象,来实现模拟 路由路径地址以及相关功能。
+
+## Router解析
+
+前端路由在不同的库或者框架中实现,一般会采用一套通用的解析规则,在实现细节上有所差异。
+
+一个路由地址,一般包含如下几个部分:
+
+- **path** 表示路由的路径
+- **params** 表示路由的路径动态匹配结果
+- **query** 表示路由携带的参数,未解析前为 queryString, 解析后为 queryObject
+
+如一个 路由地址: `/a/b/?c=1` 中, `/a/b/` 部分一般称为 **path** , `?c=1` 部分一般被称为 `query`。
+
+### 具名路由
+
+具名路由,也称 静态路由 指在声明一个路由时,对地址栏路径地址使用 全等匹配,仅当声明的路由与路径地址全等时,才命中路由。
+
+``` js
+// 浏览器地址栏: https://example.com/a/b/
+// 声明路由:
+const routes = [
+ {
+ path: '/a/b', // 命中当前路由
+ },
+ {
+ path: '/a/c', // 不一致,未命中
+ },
+ {
+ path: '/a', // 不一致,未命中
+ },
+ {
+ path: '/a/b/c', // 不一致,未命中
+ }
+]
+```
+
+### 路由匹配
+
+路由匹配,指通过 一套匹配规则,对地址栏路径地址 进行 规则匹配,当命中匹配规则时,则命中路由。
+一般场景下, 通过 `/:pathname` 的格式来表示路由路径中的动态部分。
+
+如 `/user/:id`, 则可以匹配 `/user/123`,`/user/456` 等满足规则的地址栏路径。
+
+`/:pathname` 部分会被解析到 `params` 对象中,如上述的 通过`/user/:id`规则解析 `/user/123`,表示为:
+
+```js
+const currentRoute = {
+ path: '/user/123',
+ params: { id: 123 }
+}
+```
+
+### 其他
+
+在不同的框架或库中, 对路由解析会在基于上述的规则的基础上,进行补充和扩展,提供更加丰富的功能,以满足更多的场景。
+
+比如, **Vue-Router** 使用了 `path-to-regexp` 库作为其路由解析的依赖,该库提供了非常丰富且灵活的路径匹配功能,
+能够适配非常多的从简单到复杂的场景。**React-Router** 则在其内部实现了和扩展了相关的规则。
+
diff --git a/docs/1.前端/10.开发/微前端.md b/docs/1.前端/10.开发/微前端.md
new file mode 100644
index 00000000..142587f2
--- /dev/null
+++ b/docs/1.前端/10.开发/微前端.md
@@ -0,0 +1,285 @@
+---
+title: 谈谈微前端
+createTime: 2019/08/31 05:13:33
+author: pengzhanbo
+permalink: /article/vpqgx0t7/
+---
+
+微前端 是最近比较新兴的一个话题,它不具体指某个库某个框架,而是一个思想,一种概念,运用这种思想,
+根据自身的需求,从而实现适用于自身的 微前端 。
+
+
+
+> 本文根据最近我在公司内部举行的 微前端技术解决方案 分享而写。
+> 提供的 微前端方案 也应用于公司内部的项目,并取得了良好的反馈,获得广泛好评。
+> 本文不具体谈如何实现微前端,仅讲述微前端的概念,期望能够通过本文理解微前端。
+
+## 前言
+
+微前端 目前在行业内是一个新兴的思想。
+
+诞生这个思想的背景是,在公司内部,常常会有一类项目,这类项目很大、很重,
+涉及的业务内容多而杂,还涉及了跨部门共同维护,积累的庞大的技术债 等各种问题。
+这类项目在维护成本上、部署成本上等,都会花费巨大的开销,前端开发人员对于维护这类项目,苦不堪言,
+急需找到解决这类问题的方案。
+
+基于这样的背景下,开始探讨 解决方案的可行性, 微前端 正是基于此 开始慢慢 出现在人们的视野中。
+
+## 现状
+
+### 发展历程
+
+在 Web 的发展初期,还没有所谓的前端的概念,网页的内容也相对简单,大多仅涉及文字图片信息的展示和表单内容,
+这些工作可能网站负责人自己就包办了。
+然后微软推出了 **Ajax** 技术,引起了网页的技术变革,从此网站开始具备了动态交互性,
+能够在网页发起请求动态获取服务器的内容,这丰富了网页的可交互性,网页的开发也从UI界面和表单交互,进一步增加了
+数据和逻辑的开发,前端也慢慢的被划分一个相对独立的职能。
+
+而伴随着 nodejs 的出现,以及 angular 的出现,还包括 vue/react 等库,以及建立在 nodejs 上的生态,
+包括grunt、gulp、webpack 等工具的诞生,前端进入了一个喷井式爆发的时期,也是我们所处的时期。前端越来越专业化,
+包含的技术内容越来越丰富,依托于nodejs 以及众多的技术框架等,向着工程化进一步的发展,前端项目也越来越大。
+
+### 浮现的问题
+
+你是否维护过一个可能有着四五年以上历史的项目?是否维护过一个糅杂了各种各样的库的项目?
+是否维护过一个多个公司部门参与的跨团队联合开发的项目?
+
+对于很多人来说,入职的某个公司,最怕被安排去维护一个这样的项目。因为每一次维护迭代,就如同开盲盒一样,
+永远不知道有什么惊喜在等着自己。
+
+对于这类项目,可能存在的问题包括:
+
+- 跨部门,夸团队联合开发,如何沟通?如何协作?
+- 业务线多,页面多,如何管理?
+- 如何进行代码管理?
+- 如何进行分支管理?
+- 多部门进行迭代,如何把控版本?
+- 存在发布冲突,如何解决?
+- 如何进行测试?
+- 如何管理公共代码?
+- ...
+
+可能改动某一行代码,都会带来意想不到的结果,种种问题的积累,技术债的、业务债的,使得项目越来越臃肿,越来越难以维护。
+
+亟需寻找一种方案,能够解决这些问题。
+
+### iframe嵌入
+
+于是,在大多数时候,我们不得不去选择通过 iframe嵌入 的方式,先把臃肿的项目一点一点的拆开给回各个部门或者团队自行维护,
+再提供一个 系统门户应用,用 iframe嵌入 的方式,加上维护一个菜单列表与其他项目入口链接的映射,来糅合成一个 网站应用。
+
+
+
+通过 iframe嵌入,在一定程度上,满足了 各部门各团队各业务线 独立开发独立部署的需求,只需要提供对应的页面链接就可以接入到
+整个系统中。但也存在着一些问题
+
+**安全问题**
+
+然而,我们知道, iframe是存在安全问题的,如果攻击者使用 iframe访问一个 未知来源的链接,有可能被注入恶意脚本,从而盗取
+系统的隐私信息,这需要我们去严格配置 SCP,以及配置 sandbox,尽可能的保证 iframe 的安全性。
+
+**资源加载过多**
+
+而由于仅需要提供链接就可以嵌入,那么对于各自的项目来说,灵活度就很高,各个项目可以随意的选择各种技术框架来实现自己的业务,
+又或者即使使用了相同的技术框架,但各项目的资源相对独立,对于整个系统而言,需要加载的资源量会十分庞大,
+从而导致了页面访问速度变慢,经常会出现页面部分区域白屏等待时间过长等,这也带来了体验问题。
+
+**访问地图丢失**
+
+由于 iframe 嵌入的站点,独享访问历史记录,与外部的历史记录是相互独立的,即通过浏览器的 前进/回退 按钮来访问历史记录并
+不能得到预期的结果,这在一定程度上影响了用户的操作。
+
+## 寻找解决方案
+
+有没有什么其他的方案,来进一步解决这些问题呢?
+
+
+首先我们明确的知道,单项目管理目前来看不是一个可行的方案,需要在多项目管理上寻求解决方案。
+
+### 多项目公共业务组件
+
+对于多数的大型系统项目而言,大体上都采用以下布局结构:
+
+
+
+主体布局结构包括:
+
+- 导航栏 (可选)
+- 左侧菜单栏 (可选)
+- 内容区域
+- 页脚 (可选)
+
+在这种布局结构下,各个业务板块通常通过 导航栏 或者 左侧菜单栏 进行 导航切换,在 内容区域 展示 业务板块。
+即,总体上看,对于业务来说,导航栏、左侧菜单栏、页脚,这几个都是可能 共同的,主要的不同点在于 内容区域。
+
+那么我们可以把 共同的部分,如 导航栏、左侧菜单栏、页脚 这几个部分,抽离为公共业务组件,
+对于每个业务板块,独立为单独的项目进行开发维护,并在项目中引入这些 公共业务组件。
+公共业务组件其中主要负责之一是提供 链接到各个业务板块。
+
+
+
+这种方案具有如下的优点:
+
+- 整体系统根据业务板块拆分为了多个项目;
+- 实现了项目的独立性,可独立进行开发、发布;
+- 通过在主项目重载渲染,实现类似 **SPA应用** 的访问体验;
+
+但同样也带来了新的问题:
+
+- 公共业务组件
+
+ - 公共业务组件 如何进行管理;
+ - 公共业务组件 如何在业务板块项目之间保持同步更新;
+
+以及没有解决的问题:
+
+- 资源加载过多;
+
+ 各个业务板块项目重复加载公共业务组件,重复加载各种库资源。
+
+- 项目无法实现统一管理;
+
+### 主项目重载业务项目资源
+
+在上一个方案中,公共业务组件的引入解决了一部分问题,也带来了一部分问题,如何把公共业务组件进行统一管理,并保持一致性?
+
+我们回到 iframe方案,在这个 iframe方案中,有一个主项目用于管理这些 菜单栏、导航栏等。 同样的,可以借鉴这个思路,
+也抽象一个主项目,用于管理这些 公共业务组件,然后寻找另一种方式来加载渲染其他的业务板块项目。
+
+我们知道,业务板块的项目,也是通过链接去访问的,而每个链接都对应着一个 html 资源文件,通过加载这个资源,以及HTML内的 css资源、js资源等来渲染页面。那么,我们可以通过解析这个 html资源,然后将得到的 html内容、css文件、js文件,在主项目中加载后渲染到特定的区域,
+那么就可以做到在主项目中加载业务板块项目。
+
+
+
+在主项目中,实现一个 资源加载器与解析器,通过业务板块项目的访问链接,获取 html资源文件,并解析 html 的内容,包括:
+
+- `` 标签中的 ``, ``, `
+```
+
+### 示例6
+
+Hash 值相符的脚本才能执行:
+
+```
+Content-Security-Policy: script-src 'sha256-qznLcsROx4GACP2dm0UCKCzCG+HiZ1guq6ZZDob/Tng='
+```
+该hash值必须是 script 标签内容的 sha256 值,代码才能执行:
+``` html
+
+```
+
+## 违例报告
+
+启用 CSP 后,默认情况下,违例报告不会发送。我们可以通过配置 `report-uri` 策略指令,并提供至少一个URI地址去递交报告。
+
+```
+Content-Security-Policy: default-src 'self'; report-uri http://report.example.com/csp;
+```
+
+### 违例报告示例
+
+违例报告将以 JSON 对象的数据结构进行递交:
+
+``` json
+{
+ "csp-report": {
+ "document-uri": "http://example.com/index.html", // 发生违规的文档的 URI
+ "referrer": "", // 违规发生处的文档引用(地址)
+ "blocked-uri": "http://example.com/css/style.css", // 被 CSP 阻止的资源 URI。
+ "violated-directive": "style-src cdn.example.com", // 违反的策略名称。
+ // 在 Content-Security-Policy HTTP 头部中指明的原始策略。
+ "original-policy": "default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports"
+ }
+}
+```
+
+当服务器接收到 违例报告,可以通过分析报告内容,来进行自定义的处理。
diff --git a/docs/1.前端/8.HTTP/HSTS.md b/docs/1.前端/8.HTTP/HSTS.md
new file mode 100644
index 00000000..fe8ad940
--- /dev/null
+++ b/docs/1.前端/8.HTTP/HSTS.md
@@ -0,0 +1,90 @@
+---
+title: 为你的站点开启HSTS
+createTime: 2020/11/12 07:08:12
+author: pengzhanbo
+tags:
+ - http
+ - 安全
+permalink: /article/1w4onzn1/
+---
+
+`HTTP-Strict-Transport-Security` 简称为 `HSTS`,是一个 HTTP 响应头。
+用于通知浏览器应该只通过 HTTPS 访问该站点,并且以后使用 HTTP 访问该站点的所有尝试都应自动转换为 HTTPS。
+
+
+
+## 中间人劫持
+
+当用户在未知风险的网络环境中访问 某个网站的时候,如访问 `http://example.com`,在这个未知风险的网络环境中,
+可能会被其他人拦截到用户发出的网络请求,然后跳转到一个一模一样的钓鱼网站,或者在请求内容中,注入有危害的代码、广告等,
+这种攻击行为,被称为 **中间人劫持**。
+
+当 `example.com` 也支持 `https` 协议进行访问后,如果用户直接通过 `https` 协议访问,那么在一定程度上可以有效防止
+`中间人劫持`。
+
+如果用户依然通过 `http` 协议访问,虽然服务器可以重定向到 `https` 请求,然而在这个过程中,中间人依然可以
+通过拦截 `http` 请求,然后向服务器发起 `https` 请求获取内容,再注入新的内容 返回给用户。
+
+用户在浏览器地址栏中 输入 `example.com`, 浏览器默认发起的是 `http` 请求,这导致了我们很难要求用户在通过域名访问
+网站时,一定要输入 `https://example.com`。
+
+为了限制 `中间人劫持` 这种潜在的攻击手段,一种处理方式就是 强制浏览器使用 `https` 协议访问网站。
+为此,我们需要给网站开启 `HSTS`。
+
+## HSTS
+
+`HSTS` 通过声明 `HTTP` 头部字段 `HTTP-Strict-Transport-Security` 来启用和配置策略:
+
+```
+Strict-Transport-Security: max-age=
+Strict-Transport-Security: max-age=; includeSubDomains
+Strict-Transport-Security: max-age=; preload
+```
+
+### 指令
+
+#### `max-age=`
+
+设置在浏览器收到这个请求后的``秒的时间内凡是访问这个域名下的请求都使用 HTTPS 请求。
+
+#### `includeSubDomains` 可选
+
+如果这个可选的参数被指定,那么说明此规则也适用于该网站的所有子域名。
+
+#### `preload` 可选
+
+查看 [预加载 HSTS](https://www.chromium.org/hsts/) 获得详情。不是标准的一部分。
+
+### 浏览器处理
+
+> 当网站已开启 `HSTS`
+
+用户在第一次通过 `https` 协议访问网站时,服务器响应`Strict-Transport-Security` 头,浏览器记录下信息,
+在以后重新访问访问网站时,会把访问这个网站的 `http` 请求自动替换为 `https`。
+
+当 `HSTS` 头设置的过期时间到了,后面通过 `HTTP` 的访问恢复到正常模式,不会再自动跳转到 `HTTPS。`
+
+每次浏览器接收到 `Strict-Transport-Security` 头,它都会更新这个网站的过期时间,所以网站可以刷新这些信息,防止过期发生。
+
+Chrome、Firefox 等浏览器里,当尝试访问该域名下的内容时,会产生一个 307 Internal Redirect(内部跳转),自动跳转到 HTTPS 请求。
+
+
+## 预加载
+
+如果用户首次访问网站时,依然使用的是 `http` 协议,浏览器会忽略`Strict-Transport-Security`,而且中间人依然可以劫持请求内容,删除 `Strict-Transport-Security`。
+
+为了进一步处理这个问题, `Google`、`Firefox` 等浏览器厂商,维护了一个 `HSTS` 预加载服务。
+
+你可以将你已开启了 `HSTS` 的 站点域名,提交到 预加载服务中,浏览器将会永不使用非安全的方式连接到你的域名。
+
+但是,这不是 HSTS 标准的一部分,也不该被当作正式的内容。
+
+[`HSTS`预加载服务](https://hstspreload.org/)
+
+
+## 示例
+
+当前域名,以及所有子域名,开启 `HSTS`, 过期时间为 一年。
+```
+Strict-Transport-Security: max-age=31536000; includeSubDomains
+```
diff --git a/docs/1.前端/8.HTTP/浏览器HTTP缓存机制.md b/docs/1.前端/8.HTTP/浏览器HTTP缓存机制.md
new file mode 100644
index 00000000..223272f3
--- /dev/null
+++ b/docs/1.前端/8.HTTP/浏览器HTTP缓存机制.md
@@ -0,0 +1,331 @@
+---
+title: HTTP缓存机制
+createTime: 2019/08/24 12:18:39
+author: pengzhanbo
+permalink: /article/c3ez957l/
+---
+
+::: note
+老生常谈!老生常谈!老生常谈啊!
+:::
+
+## 什么是HTTP缓存
+
+当客户端向服务器发起资源请求时,会先抵达浏览器缓存,如果浏览器有要请求的资源的副本,
+那么就可以直接从浏览器缓存中提取而不是从原始服务器中获取这个资源。
+
+http缓存都是从对同一资源的第二次请求开始的。
+- 第一次请求时,服务器返回资源,并在`response header`中回传资源的缓存参数;
+- 第二次请求时,浏览器会根据这些缓存参数,判断是否使用浏览器缓存的资源副本还是从服务器获取资源。
+
+## HTTP缓存分类
+
+HTTP缓存,根据是否需要重新向服务器发起请求,可分为两大类:
+- 强缓存: 强制缓存,在缓存有效时间内,不再向服务器发起资源请求,直接使用浏览器缓存的资源副本
+- 协商缓存:在缓存有效时间内,需要向服务器询问资源是否需要更新,如果需要更新,则从服务器获取新的资源,
+ 如果不需要更新,则继续使用浏览器缓存的资源副本;
+
+::: tip 另一种缓存分类
+根据资源是否可以被单个用户或多个用户使用来分类,还可以分为 私有缓存和共享缓存。
+
+这种一般是对于 代理服务器的,即 浏览器发起请求 -> 代理服务器 -> 原始服务器。
+
+- 私有缓存: 在代理服务器中,仅针对单个用户使用的资源缓存,其他用户发起的对同一个资源的首次请求,仍然需要从原始服务器获取资源
+ 并为该用户建立新的缓存资源。
+
+- 共享缓存:只要有一个用户发起的对同一个资源的首次到达代理服务器的请求,代理服务器对该资源缓存后,其他用户请求代理服务器上的资源,
+ 在缓存有效时间内,代理服务器不再向原始服务器获取新的资源,返回代理服务为缓存的资源副本。
+:::
+
+
+## 主要的HTTP Headers
+
+- 通用首部字段
+
+ | 字段 | 说明 |
+ | -- | -- |
+ | Cache-Control | 控制缓存行为 |
+ | Pragma | http1.0时代的产物,值为 no-cache 时禁用缓存 |
+
+- 请求头部字段 Request Headers
+
+ | 字段 | 说明 |
+ | -- | -- |
+ | If-Match | 比较 ETag 是否一致 |
+ | If-None-Match | 比较 ETag 是否不一致 |
+ | If-Modified-Since | 比较资源最后更新时间是否一致 |
+ | If-Unmodified-Since | 比较资源最后更新时间是否不一致 |
+
+- 响应头部字段 Response Headers
+
+ | 字段 | 说明 |
+ | -- | -- |
+ | ETag | 资源匹配信息 |
+
+- 实体头部字段
+
+ | 字段 | 说明 |
+ | -- | -- |
+ | Expires | http1.0时代的产物,实体主体过期时间 |
+ | Last-Modified | 资源的最后一次更新时间 |
+
+
+
+::: warning 提醒
+`Pragma`、`Expires` 这两个header是 http1.0中的内容,在 http1.1及往后的版本中逐步被弃用。
+
+但为了能够对浏览器向下兼容,大多数网站在设置 缓存机制时,仍然在 response headers 中保留这两个字段的声明。
+
+本文同样也会对这两个字段进行说明,以及为什么http1.1后会使用 `Cache-Control` 代替。
+:::
+
+::: warning 提醒
+在某些技术文章分享中,常常会直接把这些headers字段各自分类到 强缓存 或 协商缓存中,
+个人认为这种简单粗暴的划分方式是有待商榷,就比如`Cache-Control`的不同取值,其行为会根据值表现为强缓存或协商缓存。
+:::
+
+### Pragma
+
+`Pragma` 字段仅有一个 `no-cache`的可选值,会告知客户端不要对该资源进行缓存读取,应该每次都向服务器发送资源请求。
+
+在客户端使用时,通常做法是在 HTML中加上一个 meta 标签:
+``` html
+
+```
+::: danger 警告
+- 这个标签声明仅有 IE才能识别含义,其他主流浏览器不兼容。
+- 在IE浏览器中,虽然能够识别含义,但并不一定会在请求Request Header中加上Pragma,但确实会让当前页面每次都发起新请求。
+ (仅限页面html文件,页面内使用的其他资源不受影响。)
+:::
+
+在服务端配置为 Response Header 时,浏览器读取到该字段,会禁用缓存行为,后续的对同一资源的请求会重新发起请求而不使用缓存。
+
+::: warning 提醒
+由于`Pragma` 在浏览器端的兼容问题,在服务器端又有其他字段能更好的控制缓存行为,Pragma 字段基本已经被抛弃,不再使用,
+
+*除了部分网站出于兼容性考虑,还会带上该字段。*
+:::
+
+
+### Expires
+
+在 http1.0中,Pragma 用于禁用缓存,也需要有一个字段用于启用缓存和定义缓存时间。Expires 就是用于这个目的。
+
+Expires 的值是一个 GMT时间, 如:`Thu Jun 07 2018 14:26:45 GMT`,用于告诉浏览器资源的缓存过期时间,如果还没有超过该时间
+则不发起新的资源请求。
+
+在客户端,可以使用 meta标签来告知浏览器缓存时间
+``` html
+
+```
+如果希望不走缓存,每次页面请求都发起新的请求,可以把 content 设置为 -1 或 0。
+
+::: danger 提醒
+跟 Pragma 字段一样, 该 meta 标签只有 IE 能够正确识别。
+而且该方式仅是告知 IE 缓存时间的标记,并不能在 Request Header 中找到该字段。
+:::
+
+服务端在 Response Headers 中设置 Expires 字段,则在任何浏览器中都能正确设置资源缓存时间;
+
+::: info 说明
+如果同时使用 Pragma 和 Expires 字段, 则 Pragma 优先级会更好,页面会发起新的请求
+:::
+
+::: warning 提醒
+Expires 字段虽然能够定义缓存有效时间,但是这个时间的设置是相对于本地时间的。
+如果在服务端定义,则这个时间是相对于服务端时间的,
+这个时间返回到客户端, 客户端是拿着客户端的本地时间与返回的服务端时间做对比。
+那么就会导致一种情况,当用户更改了客户端的时间,如超过了 Expires定义的缓存时间,那么缓存就立即失效了。
+
+也正是应该存在着这样的问题,Expires并不能保证缓存能够达到预期的表现,所以也被逐步弃用。
+:::
+
+### Cache-Control
+
+`Cache-Control` 是从 `http1.1` 开始支持的 header 属性,该属性的值描述了使用缓存的行为以及缓存的有效时间。
+
+`Cache-Control` 可以在 发起请求时,在`Request Headers` 中声明该属性,(如果资源请求是通过代理服务器再到原始服务器,)
+通知代理服务器对资源的缓存方式,以及是否向原始服务器请求最新的资源。
+
+`Cache-Control` 做为 `Response Headers` 属性返回时,通知浏览器对该资源的缓存方式和有效时间。
+
+Cache-Control 语法如下:
+```
+Cache-Control:
+```
+
+- 作为 `Request Headers` 时, `cache-directive` 支持以下可选值
+
+| 字段名称 | 说明 |
+| -- | -- |
+| no-cache | 告知(代理)服务器不直接使用缓存,要求从原始服务器发起请求 |
+| no-store | 所有内容都不会被保存到缓存或 Internet临时文件中 |
+| max-age=delta-seconds | 告知服务器 客户端希望接收一个存在时间(age)不大于 delta-seconds 秒的资源|
+| max-stale\[=delta-seconds] | 告知(代理)服务器 客户端愿意接收一个超过缓存时间的资源,若有定义delta-seconds,则为delta-seconds秒,若没有则为超过任意时间 |
+| min-fresh=delta-seconds | 告知(代理)服务器 客户端希望接收一个在delta-seconds秒内被更新过的资源 |
+| no-transform | 告知(代理)服务器 客户端希望获取一个实体数据没有被转换(如压缩)过的资源 |
+| only-if-cached | 告知(代理)服务器 客户端希望获取缓存的资源(若有),而不用向原服务器发起请求 |
+
+- 作为 `Response Headers`时,`cache-directive` 支持以下可选值
+
+| 字段名称 | 说明 |
+| -- | -- |
+| public | 表明任何情况下都需要缓存该资源 |
+| private[="file-name"] | 表明返回报文中全部或部分(若指定了*file-name*的字段数据)仅开放给某些用户(服务器指定的*share-use*)做缓存使用,其他用户则不能缓存这些数据 |
+| no-cache | 不直接使用缓存,要求向服务器发起(新鲜度校验)请求 |
+| no-store | 所有内容都不会被保存到缓存或 Internet临时文件中 |
+| max-age=delta-seconds | 告知客户端该资源在*delta-seconds*秒内是新鲜的,无需向服务器发起请求 |
+| s-max-age=delta-seconds| 同 max-age,但仅应用于 共享缓存 |
+| no-transform | 告知客户端缓存文件时不得对实体数据做任何改变 |
+| must-revalidate | 当前资源一定是向原始服务器发去验证请求的,若请求失败会返回504(而非代理服务器上的缓存) |
+| proxy-revalidate | 和 must-revalidate类似,但仅应用于 共享缓存 |
+
+
+- 可以直接在 HTML页面的`` 中通过 meta标签来给请求头加上 `Cache-Control` 字段:
+
+ ``` html
+
+ ```
+
+- `Cache-Control` 允许自由组合可选值:
+ ```
+ Cache-Control: max-age=3600, must-revalidate
+ ```
+ 这段声明表示,该资源必须从原始服务器获取,且其缓存有效时间为一个小时,在后续的一个小时内,用户重新访问该资源都无需发送请求。
+
+### 缓存校验
+
+`Pragma`、`Expires`、`Cache-Control` 字段能够让客户端决定是否向服务器发送请求,缓存未过期的从本地缓存获取资源,缓存过期的从服务器端获取资源。
+
+但是,客户端向服务器发送了请求,是否以为着一定要读取并返回该资源的实体内容?
+
+- 如果一个资源在客户端的缓存时间过期了,但服务器并没有更新过这个资源,那服务端是否一定要重新把资源的实体内容返回?
+
+- 如果这个资源过大,虽然缓存过期,但又没有更新过,返回实体内容是否会浪费带宽和时间?
+
+对于这些问题,其实只要采取某种策略,让服务器知道客户端现在保存的缓存文件跟服务端的资源文件是一致的,
+然后通知客户端该资源可以继续使用缓存文件,不需要重新返回资源实体内容。
+那么就可以解决上述的问题,同时为HTTP请求带来优化和加速。
+
+http1.1 新增了 `Last-Modified`、`ETag`、 `If-Match`、`If-None-Match`、`If-Modified-Since`、
+`If-Unmodified-Since` 这些字段,用于对缓存资源的校验,提高缓存的复用率。
+
+### Last-Modified
+
+服务器将资源发送给客户端时,会将资源的最后更新时间以如下格式加载实体首部,一起返回给客户端。
+
+客户端会为该资源标记上该信息,下次在请求时,会把该信息添加在请求报文中发送给服务端去做检查。
+如果客户端上报字段时间值和服务端的对应资源的最后修改时间一致,则说明改资源没有被修改过,直接返回 304状态码。
+
+客户端在上报 Last-Modified 时,可以使用的 Request Headers 字段有两个:
+
+- `If-Modified-Since`: 该字段格式如下
+ ```
+ If-Modified-Since:
+ ```
+ 字段告诉服务端,如果客户端上报的最后修改时间和服务器上的最后修改时间一致,则直接返回304和响应报头即可。
+
+ 当前各浏览器默认使用该字段用来向服务端上报保存的 Last-Modified 值。
+
+- `If-Unmodified-Since`: 该字段格式如下
+ ```
+ If-Unmodified-Since:
+ ```
+ 字段告诉服务端,如果客户端上报的最后修改时间和服务端上的最后修改时间不一致,
+ 则应当返回 412(Precondition Failed)状态码给客户端。
+
+Last-Modified 由于是使用的资源最后修改时间来确定资源是否有被修改,
+但是在实际情况中,往往存在着一个资源被修改了但实际内容没有发生改变,
+而由于资源最后修改时间已经发生改变,依然会返回整个实体内容给客户端,而其实内容跟客户端缓存内容一致。
+
+### ETag
+
+为了解决 `Last-Modified` 可能存在的不准确的问题,http1.1 还推出了 ETag 实体首部字段。
+
+服务器会通过某种算法,给资源计算得出一个唯一标识符,在把资源响应给客户端的时候,会在实体首部加上该字段一起返回给客户端。
+```
+ETag: ETag-Value
+```
+
+客户端为资源标记上该信息,下次在请求时,会把该信息添加在请求报文中发送给服务端去做检查。
+服务端只需要比较客户端传来的ETag和对应的该资源的ETag是否一致,就可以判断资源相对于客户端资源是否被修改过。
+如果ETag是一致的,那么就直接返回304状态码,否则就返回新的资源实体内容给客户端。
+
+客户端在上报 ETag 时,可以使用的 Request Headers 字段有两个:
+
+- `If-None-Match` 该字段格式如下
+ ```
+ If-None-Match:
+ ```
+ 字段告诉服务端,如果ETag没有匹配上,需要重新返回新的资源实体内容,否则直接返回 304 状态码。
+
+ 当前各浏览器默认使用该字段用来向服务端上报保存的 ETag 值。
+
+- `If-Match` 该字段格式如下
+ ```
+ If-Match:
+ ```
+ 字段告诉服务端,如果ETag没匹配到,或者收到了`"*"`值而当前没有该资源实体,
+ 则应当返回412(Precondition Failed)状态码给客户端。否则服务器直接忽略该字段。
+
+::: tip 提醒
+如果 `Last-Modified` 和 `ETag` 同时被使用,则要求它们的验证必须同时通过才返回 304,
+若其中一个没有通过,则服务器会按照常规返回资源的实体以及200状态码。
+:::
+
+## 次要的 HTTP Headers
+
+以下的字段虽然跟缓存有关系,但没有那么重要。
+
+### Vary
+
+`Vary` 表示 服务端会以什么基准字段来区分、筛选缓存版本。
+
+首先考虑一个问题,服务端有一个请求地址,如果是IE用户则返回针对IE开发的内容,否则返回另一个主流浏览器版本的内容。
+
+一般来说,服务端获取到请求的 `User-Agent` 字段做处理即可。
+但是如果用户请求的是代理服务器而非原始服务器,且代理服务器如果直接把缓存的IE版本资源发给了非IE的客户端,那就出问题了。
+
+而 Vary 则是用于处理这类问题的头部字段,只需要在响应报文加上:
+```
+Vary: User-Agent
+```
+字段告知代理服务器需要以 User-Agent 这个请求头部字段来区别缓存版本,确定传递给客户端的版本。
+
+Vary 字段也接受条件组合的形式
+```
+Vary: User-Agent, Accept-Encoding
+```
+字段告知代理服务器需要以 User-Agent 和 Accept-Encoding 两个请求头部字段来区别缓存版本。
+
+### Date、Age
+
+Date 字段表示原始服务器发送该资源的响应报文时间(GMT时间)。
+该字段的作用可以帮助我们判断该资源命中的是原始服务器还是代理服务器。
+
+- 如果`Date`的时间与当前时间差别较大,或者连续F5刷新发现Date值没有变化,那么说明当前请求命中的是代理服务器的缓存。
+- 如果每次刷新页面,浏览器每次都会重新发起这条请求,那么其Date的值会不断变化,说明该资源是直接从原始服务器返回的。
+
+Age 字段表示某个文件在代理服务器中存在的时间(秒),如果文件被修改或替换,Age会重新从0开始累计。
+
+
+## 浏览器表现
+
+### 强缓存
+
+对于强缓存的资源:
+
+- 当用户第一次访问该资源时,服务器返回 200状态码,以及资源实体内容。
+
+- 如果用户访问完第一次后,在没有关闭浏览器的前提下,进行了第二次或更多次资源访问,那么浏览器不再请求服务器,
+ 而是从 浏览器的内存缓存区取出资源,并且 状态码 标记为 `200 (memory cache)`
+
+- 如果用户访问完第一次后,关闭浏览器后,重新打开浏览器,进行第二次或更多次资源访问,那么浏览器也不会请求服务器,
+- 而是从 浏览器的磁盘缓存区取出资源,并且 状态码 标记为 `200(disk cache)`
+
+### 协商缓存
+
+- 当用户第一次访问该资源时,服务器返回 200状态码,以及资源实体内容。
+
+- 如果用户进行第二次访问时,进行缓存校验。 或在缓存时间内,或 资源未被修改,那么 直接返回 304状态码
+- 如果用户进行第二次访问时,服务器资源已被更新,则返回 状态码 200 ,以及新的资源实体内容。
diff --git a/docs/1.前端/9.框架/一些好玩的库或者框架汇总.md b/docs/1.前端/9.框架/一些好玩的库或者框架汇总.md
new file mode 100644
index 00000000..6e5f3e3c
--- /dev/null
+++ b/docs/1.前端/9.框架/一些好玩的库或者框架汇总.md
@@ -0,0 +1,165 @@
+---
+title: 一些好玩的库或者框架汇总
+createTime: 2022/05/27 09:16:16
+author: pengzhanbo
+permalink: /article/ci39ae1o/
+---
+
+这里收集了一些各种类型的好玩的库或者框架。
+
+
+
+----
+
+## Client Framework
+
+### Lit
+
+[{style="width:40px"}](https://lit.dev/)
+
+**lit** 是一个简单的、高效的、用于构建 web component 的轻量级库。
+
+它替代了 [polymer](https://github.com/Polymer/polymer) 成为 WebComponent/customElement开发的首选库。
+
+::: code-tabs
+@tab my-element.ts
+```ts
+import { LitElement, html, css } from 'lit';
+import { customElement, property } from 'lit/decorators.js';
+
+@customElement("my-element")
+export class MyTimer extends LitElement {
+ static styles = css`...`;
+
+ @property() count = 0;
+
+ render() {
+ return html`${this.count}
`;
+ }
+}
+```
+@tab index.html
+```html
+
+...
+
+
+
+```
+:::
+
+
+### solid-js
+
+[solid-js](https://www.solidjs.com/)
+
+一个用于构建用户界面,简单高效、性能卓越的JavaScript库。
+
+Solid 站在 React, Knockout 等巨人的肩膀上。如果你之前用 React Hooks 开发过,Solid 应该看起来很自然。事实上,Solid 模型更简单,没有 Hook 规则。每个组件执行一次,随着依赖项的更新,钩子和绑定会多次执行。
+
+Solid 遵循与 React 相同的理念,具有单向数据流、读/写隔离和不可变接口。但是放弃了使用虚拟 DOM,使用了完全不同的实现。
+
+> 号称比 react 还 react 的库
+
+```ts
+import { render } from "solid-js/web";
+import { onCleanup, createSignal } from "solid-js";
+
+const CountingComponent = () => {
+ const [count, setCount] = createSignal(0);
+ const interval = setInterval(
+ () => setCount(count => count + 1),
+ 1000
+ );
+ onCleanup(() => clearInterval(interval));
+ return Count value is {count()}
;
+};
+
+render(() => , document.getElementById("app"));
+```
+
+### inferno
+
+[inferno](https://www.infernojs.org/) 是一个快速的、类似于 React 的库,用于在客户端和服务器上构建高性能用户界面。
+
+```tsx
+import { render, Component } from 'inferno';
+
+class MyComponent extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ counter: 0
+ };
+ }
+ render() {
+ return (
+
+
Header!
+ Counter is at: { this.state.counter }
+
+ );
+ }
+}
+
+render(
+ ,
+ document.getElementById("app")
+);
+```
+
+### cycle-js
+
+[cycle.js](https://cycle.js.org/)
+
+Cycle.js是一个极简的JavaScript框架,提供了一种函数式,响应式的人机交互接口。
+
+Cycle.js 有别于其他如 React/Vue 等框架,它提供的是一套完整的开发范式,需要在其范式基础上进行开发,相对来说并不
+容易入门,但其函数式、响应式的思想,会带来非常好的启示和学习。
+
+```js
+import {run} from '@cycle/run'
+import {div, label, input, hr, h1, makeDOMDriver} from '@cycle/dom'
+
+function main(sources) {
+ const input$ = sources.DOM.select('.field').events('input')
+
+ const name$ = input$.map(ev => ev.target.value).startWith('')
+
+ const vdom$ = name$.map(name =>
+ div([
+ label('Name:'),
+ input('.field', {attrs: {type: 'text'}}),
+ hr(),
+ h1('Hello ' + name),
+ ])
+ )
+
+ return { DOM: vdom$ }
+}
+
+run(main, { DOM: makeDOMDriver('#app-container') })
+```
+
+
+### svelte
+
+[svelte](https://svelte.dev/)
+
+Svelte 是一种全新的构建用户界面的方法。传统框架如 React 和 Vue 在浏览器中需要做大量的工作,而 Svelte 将这些工作放到构建应用程序的编译阶段来处理。
+
+与使用虚拟(virtual)DOM 差异对比不同。Svelte 编写的代码在应用程序的状态更改时就能像做外科手术一样更新 DOM。
+
+```html
+
+
+
+```
diff --git a/docs/10.面试/面试2.md b/docs/10.面试/面试2.md
index 9d88785a..06aabfef 100644
--- a/docs/10.面试/面试2.md
+++ b/docs/10.面试/面试2.md
@@ -1,6 +1,6 @@
---
title: 面试2
-createTime: 2022-04-03T17:48:00.400Z
+createTime: 2022/04/03 17:48:00
author: pengzhanbo
permalink: /article/exavsmm1
---
diff --git a/docs/10.面试/面试题-JS篇.md b/docs/10.面试/面试题-JS篇.md
index 7f208078..571bc330 100644
--- a/docs/10.面试/面试题-JS篇.md
+++ b/docs/10.面试/面试题-JS篇.md
@@ -1,8 +1,8 @@
---
title: 面试题以及个人答案 JS篇
-tags:
+tags:
- 面试
-createTime: 2022-03-26T11:46:50.028Z
+createTime: 2022/03/26 11:46:50
permalink: /article/4ml7z17g
author: pengzhanbo
top: false
diff --git a/docs/10.面试/面试题—css篇.md b/docs/10.面试/面试题—css篇.md
index fcbdc997..5a8bdc91 100644
--- a/docs/10.面试/面试题—css篇.md
+++ b/docs/10.面试/面试题—css篇.md
@@ -1,8 +1,8 @@
---
title: 面试题以及个人答案 CSS篇
-tags:
+tags:
- 面试
-createTime: 2022-03-26T11:46:50.028Z
+createTime: 2022/03/26 11:46:50
permalink: /article/565o1wn0
author: pengzhanbo
top: false
diff --git a/docs/README.md b/docs/README.md
index 45bbc3fd..fee6a896 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -3,6 +3,5 @@ home: true
banner: /images/big-banner.jpg
motto: 世间的美好总是不期而遇,恬静而自然。
author: pengzhanbo
-createTime: '2022/03/26 07:46:50'
+createTime: 2022/03/26 07:46:50
---
-
diff --git a/docs/notes/README.md b/docs/notes/README.md
index 111b5538..f8c8781d 100644
--- a/docs/notes/README.md
+++ b/docs/notes/README.md
@@ -1,7 +1,6 @@
---
title: README
-createTime: '2022/04/04 11:13:30'
+createTime: 2022/04/04 11:13:30
author: pengzhanbo
permalink: /note/
---
-
diff --git a/docs/notes/vuepress-plugin/caniuse/README.md b/docs/notes/vuepress-plugin/caniuse/README.md
index fa7666ae..8efb2716 100644
--- a/docs/notes/vuepress-plugin/caniuse/README.md
+++ b/docs/notes/vuepress-plugin/caniuse/README.md
@@ -1,6 +1,6 @@
---
title: plugin-caniuse
-createTime: '2022/05/13 01:02:51'
+createTime: 2022/05/13 01:02:51
author: pengzhanbo
permalink: /note/vuepress-plugin/caniuse/
---
diff --git a/docs/notes/vuepress-plugin/netlify-functions/API.md b/docs/notes/vuepress-plugin/netlify-functions/API.md
index 86c3a54d..6943f8d1 100644
--- a/docs/notes/vuepress-plugin/netlify-functions/API.md
+++ b/docs/notes/vuepress-plugin/netlify-functions/API.md
@@ -1,6 +1,6 @@
---
title: API
-createTime: 2022-05-14T10:43:53.200Z
+createTime: 2022/05/14 10:43:53
author: pengzhanbo
permalink: /note/vuepress-plugin/netlify-functions/api/
---
@@ -83,4 +83,3 @@ __类型:__ `{ directory: string }`
一般来说,它的值都设置为 `path.resolve(__dirname, 'functions')`
-
diff --git a/docs/notes/vuepress-plugin/netlify-functions/README.md b/docs/notes/vuepress-plugin/netlify-functions/README.md
index 3f5052d0..ea7df1bb 100644
--- a/docs/notes/vuepress-plugin/netlify-functions/README.md
+++ b/docs/notes/vuepress-plugin/netlify-functions/README.md
@@ -1,6 +1,6 @@
---
title: 指南
-createTime: '2022/05/13 01:28:38'
+createTime: 2022/05/13 01:28:38
author: pengzhanbo
permalink: /note/vuepress-plugin/netlify-functions/
---
diff --git a/docs/notes/vuepress-plugin/netlify-functions/functions开发指南.md b/docs/notes/vuepress-plugin/netlify-functions/functions开发指南.md
index 87d4a4fa..5b15a64e 100644
--- a/docs/notes/vuepress-plugin/netlify-functions/functions开发指南.md
+++ b/docs/notes/vuepress-plugin/netlify-functions/functions开发指南.md
@@ -1,6 +1,6 @@
---
title: functions开发指南
-createTime: 2022-05-14T10:43:53.201Z
+createTime: 2022/05/14 10:43:53
author: pengzhanbo
permalink: /note/vuepress-plugin/netlify-functions/develop-functions/
---
diff --git a/docs/notes/vuepress-plugin/netlify-functions/介绍.md b/docs/notes/vuepress-plugin/netlify-functions/介绍.md
index 9de4ad9c..6f6ea714 100644
--- a/docs/notes/vuepress-plugin/netlify-functions/介绍.md
+++ b/docs/notes/vuepress-plugin/netlify-functions/介绍.md
@@ -1,6 +1,6 @@
---
title: 介绍
-createTime: 2022-05-14T10:43:53.202Z
+createTime: 2022/05/14 10:43:53
author: pengzhanbo
permalink: /note/vuepress-plugin/netlify-functions/intro/
---
diff --git a/docs/notes/vuepress-plugin/netlify-functions/使用.md b/docs/notes/vuepress-plugin/netlify-functions/使用.md
index 158e05d0..274204c7 100644
--- a/docs/notes/vuepress-plugin/netlify-functions/使用.md
+++ b/docs/notes/vuepress-plugin/netlify-functions/使用.md
@@ -1,6 +1,6 @@
---
title: 使用
-createTime: 2022-05-14T10:43:53.203Z
+createTime: 2022/05/14 10:43:53
author: pengzhanbo
permalink: /note/vuepress-plugin/netlify-functions/usage/
---
diff --git a/docs/notes/vuepress-plugin/netlify-functions/功能.md b/docs/notes/vuepress-plugin/netlify-functions/功能.md
index fbd035cc..5d248cfa 100644
--- a/docs/notes/vuepress-plugin/netlify-functions/功能.md
+++ b/docs/notes/vuepress-plugin/netlify-functions/功能.md
@@ -1,6 +1,6 @@
---
title: 功能
-createTime: 2022-05-14T10:43:53.204Z
+createTime: 2022/05/14 10:43:53
author: pengzhanbo
permalink: /note/vuepress-plugin/netlify-functions/feature/
---
diff --git a/docs/notes/vuepress-theme-plume/README.md b/docs/notes/vuepress-theme-plume/README.md
index 0dfb6a9d..e1727a2c 100644
--- a/docs/notes/vuepress-theme-plume/README.md
+++ b/docs/notes/vuepress-theme-plume/README.md
@@ -1,6 +1,6 @@
---
title: vuepress-theme-plume
-createTime: '2022/04/08 08:52:12'
+createTime: 2022/04/08 08:52:12
author: pengzhanbo
permalink: /note/vuepress-theme-plume/
article: true
diff --git a/docs/notes/vuepress-theme-plume/markdown增强.md b/docs/notes/vuepress-theme-plume/markdown增强.md
index e56591d7..3f4199e7 100644
--- a/docs/notes/vuepress-theme-plume/markdown增强.md
+++ b/docs/notes/vuepress-theme-plume/markdown增强.md
@@ -1,6 +1,6 @@
---
title: markdown增强
-createTime: 2022-05-14T10:43:53.216Z
+createTime: 2022/05/14 10:43:53
author: pengzhanbo
permalink: /note/vuepress-theme-plume/markdown-enhance/
---
diff --git a/docs/notes/vuepress-theme-plume/notes配置.md b/docs/notes/vuepress-theme-plume/notes配置.md
index f0dd24ff..9185eb46 100644
--- a/docs/notes/vuepress-theme-plume/notes配置.md
+++ b/docs/notes/vuepress-theme-plume/notes配置.md
@@ -1,6 +1,6 @@
---
title: notes配置
-createTime: 2022-05-14T10:43:53.218Z
+createTime: 2022/05/14 10:43:53
author: pengzhanbo
permalink: /note/vuepress-theme-plume/notes-config/
---
diff --git a/docs/notes/vuepress-theme-plume/主题插件配置.md b/docs/notes/vuepress-theme-plume/主题插件配置.md
index f5b92eca..f8789b44 100644
--- a/docs/notes/vuepress-theme-plume/主题插件配置.md
+++ b/docs/notes/vuepress-theme-plume/主题插件配置.md
@@ -1,6 +1,6 @@
---
title: 主题插件配置
-createTime: 2022-05-14T10:43:53.219Z
+createTime: 2022/05/14 10:43:53
author: pengzhanbo
permalink: /note/vuepress-theme-plume/plugins-config/
---
diff --git a/docs/notes/vuepress-theme-plume/主题配置.md b/docs/notes/vuepress-theme-plume/主题配置.md
index 5f1f701a..0ba8d031 100644
--- a/docs/notes/vuepress-theme-plume/主题配置.md
+++ b/docs/notes/vuepress-theme-plume/主题配置.md
@@ -1,6 +1,6 @@
---
title: 主题配置
-createTime: 2022-05-14T10:43:53.219Z
+createTime: 2022/05/14 10:43:53
author: pengzhanbo
permalink: /note/vuepress-theme-plume/theme-config/
---
diff --git a/docs/notes/vuepress-theme-plume/基础功能.md b/docs/notes/vuepress-theme-plume/基础功能.md
index 3dc9e537..c567f5ee 100644
--- a/docs/notes/vuepress-theme-plume/基础功能.md
+++ b/docs/notes/vuepress-theme-plume/基础功能.md
@@ -1,6 +1,6 @@
---
title: 基础功能
-createTime: 2022-05-14T10:43:53.220Z
+createTime: 2022/05/14 10:43:53
author: pengzhanbo
permalink: /note/vuepress-theme-plume/basis-power/
---
diff --git a/docs/notes/vuepress-theme-plume/快速开始.md b/docs/notes/vuepress-theme-plume/快速开始.md
index f9d08c91..367ee0d2 100644
--- a/docs/notes/vuepress-theme-plume/快速开始.md
+++ b/docs/notes/vuepress-theme-plume/快速开始.md
@@ -1,6 +1,6 @@
---
title: 快速开始
-createTime: 2022-05-14T10:43:53.221Z
+createTime: 2022/05/14 10:43:53
author: pengzhanbo
permalink: /note/vuepress-theme-plume/quick-start/
---
diff --git a/docs/notes/vuepress-theme-plume/编写文章.md b/docs/notes/vuepress-theme-plume/编写文章.md
index b4e11e0d..873b1a61 100644
--- a/docs/notes/vuepress-theme-plume/编写文章.md
+++ b/docs/notes/vuepress-theme-plume/编写文章.md
@@ -1,6 +1,6 @@
---
title: 编写文章
-createTime: 2022-05-14T10:43:53.221Z
+createTime: 2022/05/14 10:43:53
author: pengzhanbo
permalink: /note/vuepress-theme-plume/write-article/
---
diff --git a/docs/notes/vuepress-theme-plume/页面配置.md b/docs/notes/vuepress-theme-plume/页面配置.md
index 0cd85e8c..4713a448 100644
--- a/docs/notes/vuepress-theme-plume/页面配置.md
+++ b/docs/notes/vuepress-theme-plume/页面配置.md
@@ -1,6 +1,6 @@
---
title: 页面配置
-createTime: 2022-05-14T10:43:53.222Z
+createTime: 2022/05/14 10:43:53
author: pengzhanbo
permalink: /note/vuepress-theme-plume/page-config/
---
diff --git a/packages/plugin-auto-frontmatter/src/node/readFiles.ts b/packages/plugin-auto-frontmatter/src/node/readFiles.ts
index 69e730c2..fa9e227a 100644
--- a/packages/plugin-auto-frontmatter/src/node/readFiles.ts
+++ b/packages/plugin-auto-frontmatter/src/node/readFiles.ts
@@ -11,7 +11,7 @@ export const readMarkdownList = async (
): Promise => {
const files: string[] = await fg(['**/*.md'], {
cwd: sourceDir,
- ignore: ['node_modules/', '.vuepress/'],
+ ignore: ['node_modules', '.vuepress'],
})
return files
diff --git a/packages/theme/src/node/autoFrontmatter.ts b/packages/theme/src/node/autoFrontmatter.ts
index dd8dc3d0..9fd601ae 100644
--- a/packages/theme/src/node/autoFrontmatter.ts
+++ b/packages/theme/src/node/autoFrontmatter.ts
@@ -12,14 +12,14 @@ export default function (
const pkg = require('./package.json') || {}
return {
- glob: [],
+ include: [],
formatter: [
{
- glob: '**/{readme,README,index}.md',
+ include: '**/{readme,README,index}.md',
formatter: {},
},
{
- glob: '*',
+ include: '*',
formatter: {
author(author: string) {
if (author) return author
diff --git a/packages/tsconfig.build.json b/packages/tsconfig.build.json
index 11966cdf..6c7a7811 100644
--- a/packages/tsconfig.build.json
+++ b/packages/tsconfig.build.json
@@ -5,12 +5,14 @@
},
"files": [],
"references": [
+ { "path": "./plugin-auto-frontmatter/tsconfig.build.json" },
{ "path": "./plugin-baidu-tongji/tsconfig.build.json" },
+ { "path": "./plugin-blog-data/tsconfig.build.json" },
{ "path": "./plugin-caniuse/tsconfig.build.json" },
{ "path": "./plugin-copy-code/tsconfig.build.json" },
{ "path": "./plugin-netlify-functions/tsconfig.build.json" },
{ "path": "./plugin-page-collection/tsconfig.build.json" },
{ "path": "./plugin-windicss/tsconfig.build.json" },
- { "path": "./plugin-blog-data/tsconfig.build.json" }
+ { "path": "./theme/tsconfig.build.json" }
]
}