前端技术架构与工程知识框架笔记总结
2022-10-26 17:43:35 0 举报
AI智能生成
前端技术架构与工程知识框架笔记总结
作者其他创作
大纲/内容
人工智能
神经网络与深度学习
超智能体
基础
前端工程师手册
JS
JS秘密花园
JavaScript标准参考教程
JavaScript Promise迷你书
You-Dont-Know-JS
CSS
性能优化
资源请求
http2
内容优化
webp
gzip
服务器
nginx
资源加载
cdn
Http缓存
代码运行
用户体验
懒加载
前端工程/架构
SPA
PC
H5
网站
Native App
windows
Android
IOS
编码能力
设计模式
设计模式Java版
图说设计模式
设计模式三言两语
JavaScript模式
函数式编程
JS函数式编程指南
underscore函数式编程
源码
vue
vue-analysis
egg.js
开源项目
chrome github目录插件
前端监控
Web安全
Web前端黑客技术揭秘
白帽子讲web安全
XSS 蠕虫 & 病毒 即将发生的威胁与最好的防御
那些年我们一起学XSS
技术栈
React
Vue
React Native
小程序
electron
Node.js
koa
egg.js
3. 组件化/设计子模块
组件化旨在解决的主要现实问题
解耦和复用
组件和模块的定义和边界
自然语言
component 是比 module 粒度更细、更小的片段
软件编程
前端领域内模块和组件的语义为:<br><br><ul><li>模块和组件均为可分离的、有独立功能的一种封装对象<br></li><li><b>模块强调功能性,并非一定与视图相关</b>。一个完整的应用程序由多个模块组成<br></li><li><b>组件强调组合性,是一个视图片段的逻辑抽象</b>。粒度比模块细,一个模块可包含一个或多个组件<br></li></ul>
应用程序
模块
组件
对象
编程语言基元
Web Components 规范解读
是 W3C 推出的一套<font color="#924517">用于封装具有复用性、互用性前端组件</font>的<b>技术规范</b>,旨在提供一种<b><font color="#c41230">标准的组件化模式</font></b>。
是一系列技术的集合
自定义元素(Custom Elements)
创建自定义 HTML 元素或扩展内置元素
前端组件三要素
结构
表现
行为
缺点
缺少与全局隔离的命名空间
Shadow DOM
创建隔离作用域,实现 DOM、样式和逻辑的封装
与 iframe 的区别
iframe 封装了一个<b>完整的执行上下文</b>
Shadow DOM 封装了一个较轻量级的<b>局部作用域</b>
缺点
CSS 代码和 HTML 结构混在在组件的内部逻辑中,<br>长字符串令代码过于臃肿,缺乏良好的可读性和可复用性<br>
HTML template
是一个有既定格式的处理器,输入数据输出 HTML 字符串
扩展组件
slot 机制
缺点
使用时,要引入 JS 文件并在 HTML 文档中编写 <template> 结构才能使用自定义元素 <my-dialog>。<br><font color="#924517">组件源码和业务代码耦和在了一起</font>。
更友好的编码方式
优化
将组件源码和业务代码分离,外层业务代码只需要引入一个 JS 文件即可使用对应的组件
对于组件本身,基于结构、表现和行为分离的原则,保持其 CSS、JS 和 HTML 代码的相对独立性
分离后的组件源码需要经过转换后才能正常工作
compile.js
编译器
需要使用 node 中的 fs 模块读取文件
runtime.js
能在运行时将<template>元素注入 HTML 文档中
组件源码的组织结构
多文件组件
CSS、JS 和 HTML 模版分别为独立的文件
单文件组件
将 JS、CSS 和 HTML 汇总在一个文件中编写
其中使用到了 jsdom 将文本转化为 document 对象
优缺点
缺点
核心围绕 DOM 展开,数据传递依靠 DOM 的属性,Shadow DOM 和 <template> 本质上也是 DOM。<br>自然而然具有 DOM 的一些特性和限制:<br><br><ul><li><span style="color: rgb(146, 69, 23); font-size: inherit;">DOM 属性只能传递 String 类型的数据</span><br></li><li><span style="font-size: inherit;">浏览器无法理解自定义元素的语义??</span><br></li><li><span style="font-size: inherit;"><b>DOM 操作性能消耗大</b></span><br></li></ul>
优点
<font color="#16884a">自定义元素的生命周期设计理念</font>
前端组件的设计模式
减少 DOM 操作
具体代码编写细节
利用<font color="#924517">浏览器执行帧机制</font>,尽可能<b>批量处理</b>对 DOM API 的调用
架构模式
借助 <font color="#924517">Canvas 取代一部分 DOM</font>
虚拟 DOM
生命周期的设计艺术
命名
由于 JS 的单线程特性,钩子函数的命名绝不能使用正在进行时
注意
<b><font color="#924517">DOM 自身的一些钩子函数,如 onload、onerror </font>等</b>,在对应事件完成之后被触发
总结
Web Components 规范对前端组件化的<b><font color="#924517">引导意义远大于现实意义</font></b>
为前端组件化制定了相对统一的模式和方向
自定义元素的生命周期理念也为组件的设计提供了优秀的参考
前后端分离
前后端分离的助力
前端技术的演进
交互逻辑复杂度的提升
是面向对象思想中关注点分离原则的一种实践模式
考虑因素
业务特征(核心)
人员配备
组织架构
关注点
HTML 渲染(前后端耦和最紧密的环节)
会话管理??指的是 session 管理?
用户认证和鉴权
跨域处理
关注点分离<br>(前后端分离在<br>业务、架构<br>和工程角度<br>的不同关注点)<br>
前后端的两个关联
数据接口
借助 AJAX 可以实现数据接口的松耦合
HTML 渲染
舍弃 SSR 的 SPA 完成了 HTML 渲染的绝对解耦,<br>但需要考虑两者对 SEO 和用户体验的影响
<font color="#924517">Node.js 中间层兼顾渲染和接口代理</font>,<br>但如果要达到更好的 SEO,则<b>需要保证客户端路由和 Node.js 服务路由之间的一一映射</b>和优雅降级;<br>为提高用户体验还<b>需考虑同构动态组件的客户端恢复。</b><br>其在架构上的复杂性远大于传统的 SSR Web 应用架构
业务关注点
所有软件产品的核心关注点
用户和市场
实施方向
推广产品争取更多用户
前端途径
SEO
对于<b>内容偏静态或完全静态的 Web 网站</b>来说,<br>SEO 是非常重要的市场推广途径之一<br>
如何<font color="#924517">在前后端解耦的同时兼顾 SSR 以保障 SEO</font>,是前后端分离架构设计过程中的<b>核心关注点之一</b>
其他途径
改进产品提高现有用户黏性
前端途径
保障产品功能的正确性和稳定性(根本)
提高交互流畅度、快速反馈用户操作,<br>即提高用户可见性能
前端性能优化方向
提高首屏渲染速度
普遍意义上,在首屏响应速度方面<b> SSR 比 CSR 表现更好</b>
缩短关键渲染路径(CRP)
用户在页面上的操作得到快速响应
在客户端建立<font color="#924517">完善的临时数据和路由管理体系</font>??<br><font color="#924517">的 SPA</font> 能够提供<b>更快速的操作反馈,<br></b>并且可以支持<b>离线场景,<br></b>这是采用 SSR 的常规 Web 架构不可比拟的优势
其他途径
在设计前后端分离架构之前必须确定的基本准则
依据自身业务对<b> SEO 和 性能 两项指标的偏重程度</b>来决定具体的架构模式
架构关注点
前后端耦和违背分层的理念,在于<b>将交互逻辑与业务逻辑混合在一起</b>
前后端分离在架构层面的核心优势是让前后端各自拥有高度的独立性和内聚性,<br><b>类似于黑盒或纯函数,只需保证输入与输出的匹配</b>(通常为接口)而无须关注彼此内部的逻辑<br>
工程关注点
提升效率,降低人力和时间成本
效率切入点
开发的保质高效产出
前后端并行开发
单元测试??
动静资源分离部署
bug 的保质快速解决
前后端开发者明确的职责划分
最常见的两种分离模式
SPA
SPA 这种极端分离模式<br>的基本架构模型和路由管理方案<br>
优点
实现了<b>前后端的绝对解耦</b>,接口是两个领域唯一的关联。<br>与前后端分离在架构与工程方面所有的关注点几乎完全契合
动态性优势??
<b>在浏览器环境下建立前端路由策略将所有子页面进行统筹管理,<br>页面之间的跳转被映射为组件的更换或函数的调用</b>,<br><span style="font-size: inherit;"><font color="#924517">向服务端发起的网络请求仍然只是接口的调用,将渲染完全从服务端剥离</font>。</span><br>
缺点
弱 SEO
虽然有途径可以弥补,但是难以达到 SSR 的水准,并且实施成本非常高。<br>所以<b>在现实工作中,SPA 项目大多不考虑 SEO,典型的是 Hybrid 应用和短期的活动页。</b>
首屏时间长
需要先等待 JS 文件加载完成,然后请求接口,最后渲染 HTML。<br>所以<font color="#924517">需要在性能优化上花费更多精力</font>,包括设计和技术,<br>如<b>骨架屏、JS 模块化按需加载、图片懒加载等</b>。<br>
前端路由<br>的实现方式
Hash 模式
使用 URL 的 hash 标识作为路由标记,通过监听 <b>hashchange</b> 事件实现回调逻辑
优点
<font color="#16884a">不需要服务端支持</font>,是前端完全自主的路由极致
<font color="#924517">hash 标识改变后,<br>浏览器并不会将其判定为新的 URL 进而以新 URL 发起网络请求</font><br>
<font color="#16884a">兼容性更优</font>
History 路由依赖 HTML5 规范新增的 History API 的 History 路由
History 模式
使用 URL 的 path 作为路径标记,借助 <b>History API </b>及其相关事件实现跳转和回调逻辑
<b>在前后端整体架构上</b>不同于 Hash 路由<br>最显著的一点是<font color="#924517">需要服务端的配合</font><br>
History 路由支持刷新的<b>前提条件</b>是<br><b><font color="#16884a">服务端将所有子路由的请求 rewrite </font><font color="#924517">(不是 redirect)</font><font color="#16884a">到根路由,</font><br>然后前端在浏览器环境下进行子路由恢复</b><br>
代码中借助了 CustomEvent API 实现自定义事件
优点
<font color="#924517">能被爬虫程序抓取到路径,</font><br><b>然而仅路径被抓取还远不足以支撑 SEO,</b><br>因为页面的本质仍然是 CSR 的 SPA<br>我的理解:<b>既然没有实际的用处,那就不算是优点</b>
Node.js 中间层
以 Node.js 作为<b>中间渲染层<br></b>的同构 JS 编程基本模式<br>
优点
更好的 SEO
接口仍然是前后端唯一的关联,<br>但具体的关联方式可以根据 Node.js 中间层<br><b>是否具有代理功能</b>分为两种<br>
无代理 Node.js 服务器
输出
Node.js 服务器只输出 html
有代理 Node.js 服务器
输出
输出 html 文件,并且会代理 js 文件??
优势
后端开发人员不必在跨域问题上花费精力(虽然并不复杂)
可以承担一定的验证功能??
可以通过汇总多个接口在一定程度上降低交互逻辑的复杂度??
Node.js 中间层的目的
将渲染从后端解耦
<b>为前后端</b>(<font color="#924517">这里的后端指 Node.js 中间层</font>)<br><b>同构 JavaScript 编程提供了可行性</b>(<font color="#16884a">对前端的革命性影响</font>)<br>
同构 JavaScript
目的
令 JS 编写的代码既可以在浏览器端工作,也可以在服务端工作
三层含义
语言同构<br>(最表象含义)
客户端和服务端使用同一种编程语言
组件同构
一个组件同时兼容客户端和服务端运行环境
功能同构<br>(最终目标)
客户端和服务端可以实现相同的功能??
主要功能
<font color="#924517">渲染</font>
工作本质
<font color="#924517">字符串处理</font>
接下来的内容没有看懂,工作中要用到 SSR 时先看 Vue 的 SSR 文档,之后再来理解此书的内容
对于常规??的前端项目而言,<br>如果硬件??和学习成本在可接受范围内,<br>兼顾 SEO、性能和客户端动态性的同构 JS 是非常理想的前后端分离架构模式<br>
性能
性能优化的两个方面
键入 URL 后尽可能快地将内容展示给用户<br>(首屏渲染速度)
可用多维度可量化的客观指标衡量
提高用户操作的反馈速度和流畅度
在动态交互场景下用户的感受有一定的主观色彩
Web 应用性能评估模型
根据 Web 应用特征对<br>客户端场景参数进行细化
设备特征
类型
PC
平板
手机
硬件配置
CPU
内存大小
操作系统及其版本
Windows
Android
iOS
浏览器特征
品牌及版本
网络情况
连接方式
光纤
WiFi
4G
运营商
地区
带宽
<b>为以上参数<font color="#924517">赋予固定的值</font></b>从而将应用限定在一致的客户端场景中,<br>然后<b>再逐指标进行对比</b>,这是制定性能评估模型<font color="#16884a">最基础的原则</font><br>
Web 应用程序的生命周期
首屏加载阶段<br>(加载性能)
从用户输入 URL 并按下回车键到浏览器屏幕被网页填满
优化目标
尽快完成首屏呈现
衡量指标
视觉角度<br>提高网站内容的渲染速度<br>
白屏时间
计时起点
将用户在浏览器地址栏中输入 URL 按下回车键那一刻
计时终点
有可视化的图像被渲染到浏览器视窗中的那一刻
期间浏览器的工作<br>(可参考 性能脑图 中 <br>浏览器如何工作部分)<br>
域名查询
注意:DNS 的解析工作由 DNS 服务器完成,<br>浏览器是请求发起方与响应接收方<br>
与 Web 服务器建立 TCP 连接
发送 HTTP 请求
接收并渲染响应的 HTML 文档
首屏时间
计时起点
解读1
用户按下回车键开始
解读2
白屏时间的终点时刻<br>(本书是按照此描述)
计时终点
浏览器视窗的第一屏首次完全渲染完毕的时刻
交互角度<br>缩短从打开网站到可交互之间的时间间隔<br>
可交互节点
网站首次可以响应用户操作的那一刻
这里的操作反馈指的是通过 JS 实现的交互功能
业务性能指标
首次有效绘制
<b><font color="#924517">优先级最高</font>的内容</b>被首次渲染的时间节点
广告可视节点
<b>更快将广告展示给用户</b>,能间接提高与广告商之间的议价
可交互阶段<br>(动态性能)
首屏内容全部加载完成后,网站便进入可交互阶段
衡量指标
反馈速度
尽可能快地响应用户的操作
动画帧率
在<b>涉及数据量庞大、计算密集且强交互</b>的应用中,<br>实现 50 帧以上的动画并不简单<br>
业务指标
关键渲染路径<br>(必要元素渲染路径)
性能指标类型
与业务无关的技术性能指标
业务性能指标<br>(有时候比技术性能指标要重要很多)<br>
浏览器运行 Web 应用的机制<br>
浏览器的大致架构
应用层
可视的交互功能模块
书签管理器
窗口管理器
...
不可见数据管理模块
历史记录管理
...
内核层<br>
渲染引擎<br>(优化 Web 应用性能<br>的<b><font color="#924517">主要突破点</font></b>)<br>
HTML、CSS、SVG 等语言的解释器
JS 引擎
布局、绘制等与渲染相关的模块
相对底层的功能模块集合
多媒体解码器
图形库
...
操作系统
提供一些浏览器所需的系统 API,比如多线程、文件 IO 等
加载性能与动态性能的症结所在
宏观结构
网络
减少 RTT<br>(Round-trip delay time,<br>通信往返时间)<br> 总数量<br>
keep-alive<br>(持久连接)
建立 TCP 连接成功之后始终保持连接状态以实现复用
避免了每次 HTTP 请求都关闭 TCP 连接的 4 次握手,<br>以及新请求重新建立 TCP 连接的 3 次握手,减少了 3 RTT 和慢启动 耗时<br>
<b>需要消耗更多的服务器资源,加重了服务器负载</b>,但与带来的收益相比,这些成本投入是值得的
并行请求
在 HTTP2.0 尚未普及之前,各浏览器为提高处理 HTTP 请求效率的方式非常简单粗暴,<br>目前主流浏览器支持<b><font color="#924517">每个域名同时打开 4-8 个 TCP 连接</font>。</b><br>
域名发散
以浏览器并行请求为前提,<b>为充分发挥并行请求的优势,</b><br>目前一种主流的优化方案是<font color="#924517">将 Web 服务接口根据业务归属到不同的子域名下,<br>静态资源托放的 CDN 服务器也划分出多个子域名</font>,这种方案被称为域名发散。<br>
缺点
维持多个持久连接必然需要<b>占用客户端以及服务端更多的资源(CPU 和内存等),</b><br>如果一个 Web 应用主要面向的是<font color="#924517">硬件配置相对较差的移动设备(手机)</font>,需要格外慎重
域名发散<b>并不意味着可以无节制增加子域名的数量</b>,域名的增加必然<b>产生更多的 DNS 查询和 TCP 慢启动</b>,<br>这些行为带来的延迟<font color="#924517">在本身就存在高延迟的移动网络环境下</font>被进一步放大。<br>
域名收敛
<b>移动端 Web 应用</b>常使用的一种优化方案是<b>合理减少域名数目</b>
目的
减少无线网络下大量 DNS 查询造成的高延迟
这在一定程度上放弃了并行请求的优势,<br><b>如果资源数量很多,可以使用 HTTP combo 减少请求数量,进而提升应用的加载性能</b><br>
HTTP combo
是一种应用层方案
实现原理
常规模式
http://static.app.com/a.js<br>http://static.app.com/b.js<br>
HTTP combo 模式
http://static.app.com/<b><font color="#924517">?a.js&b.js</font></b>
将多个静态文件作为 URL 参数发送给服务器,然后服务器将两个文件合并为一个 JS 文件回传给客户端。<br><font color="#924517">支持 combo 的服务器必须能够解析 URL 参数,解析工作可以在 Ngnix 层完成</font>。
缩短 RTT 时长
CDN
原理
广泛采用各种缓存服务器(存放频繁访问内容的服务器),将这些缓存服务器<b>分布到用户访问相对集中的地区或网络中</b>,<br>在用户访问网站时,利用<b>全局负载技术</b>将用户的访问<b>指向距离最近的工作正常的缓存服务器上</b>,<br>由缓存服务器直接响应用户请求。 <br>
被广泛应用于搭建静态文件服务
HTTP 2.0<br>(HTTP 脑图中的“演变”部分)
从底层解决问题的革新技术
网络优化策略
短时间内 HTTP 2.0 难得到普及<br>(这里和 mdn 文档中说的不一样),<br>所以网络优化策略仍主要面向HTTP1.1<br>
浏览器兼容性不理想??
服务器迁移成本太高??<br>要如何迁移??<br>
整体架构
持久连接
使用CDN
<b><font color="#924517">无法合并的小体积文件</font></b>使用 HTTP combo
控制域名数目
前端
压缩文件体积
减少请求文件数量
合并小体积文件,使用雪碧图和字体图标
按需加载,避免不必要的下载
合理使用缓存
渲染
查看性能脑图中的<br>“浏览器如何工作/4. 渲染”与<br>“js 的 async 与 defer attribute”<br>
代码层面
运算
指前端代码逻辑而非浏览器本身的运算能力
内存管理
极限运算性能
今天的<b>复杂图形类 Web 应用(如游戏、地图、WebVR 等)</b>也非常接近浏览器运算能力的瓶颈。<br>对于从事这些行业的前端开发者来说,必须想尽一切办法将浏览器的运算能力发挥到极致。
从 URL 到图像的完整流程<br>性能脑图中的“浏览器如何工作”部分
浏览器运行 Web 应用的机制<br>以及 GC 策略对性能优化的启示<br>
探索浏览器运算性能的极限
研究前提
<font color="#f1753f">业务是核心出发点</font>
前端架构与工程概述
架构与工程
工程
软件工程初衷是为了解决软件危机
典型的软件危机
成本超标
硬件成本
人员成本
时间成本
性能不理想或功能不稳定
开发过程混乱无序难以管理
代码不规范,维护成本高
在架构之外,从更宏观的角度完善开发和维护流程管控
目标
<ul><li>规范<br></li><li>有序<br></li><li>可控<br></li><li>高效<br></li><li>辅助<br></li></ul>
架构
目标
<ul><li>高可用<br></li><li>可扩展<br></li><li>高性能<br></li><li>安全<br></li></ul>
业务
业务逻辑
交互逻辑
前端架构师职责
<b>根据业务特征<br></b>设计<font color="#924517"><b>合理的前端技术架构</b></font><br>
<b>当架构难以满足日益增长的功能需求时,如果任其野蛮生长,系统碎片化会越来越严重、越来越无序,</b>最终达到一个难以继续维护和扩展的阈值,便会得到一种<font color="#924517">极端的结果:彻底重构</font>。<br><br><b>架构师需要<font color="#16884a">通过及时、有效的干预,保持系统的有序</font>。</b><br>
基本原则
<ul><li>通过<b>合理解耦</b>各个组件/层级的功能<b>提高系统的高效性和灵活性</b><br></li><li>所有组件/层级在完成各自功能的同时<b>组合为完整的软件系统</b><br></li></ul>
软件架构的两个基本要素
分治
分解问题,各个击破
聚合
合并模块,协同运行
前端架构的<br>几个层级<br>
编程语言
在<b><font color="#16884a">充分了解语言特性的前提下</font> 制定适用于业务类型的开发规范和技术栈</b>
HTML 与 CSS
是标记类语言,<b>原始语法简单且缺乏可编程性</b>,所以<b>通常会借助一些工具和框架,另源码具有可编程性,以便维护和迭代</b>。<br>前端架构师的工作之一便是<font color="#924517">选择适用于业务类型、同时可提高开发和维护效率的工具和框架,并制定相应的开发规范</font>。
JavaScript
灵活性
会给大型项目和复杂架构带来了一定隐患。所以很多情况下需要<font color="#924517">通过框架或规范去限制 JavaScript 的灵活性</font><br>
异步编程
避免回调地狱<b>令源码更利于迭代和维护并同时兼顾性能</b>
技术规范
内容
编码规范
源码组织结构
依赖管理
第三方技术选型
原则
<font color="#924517">一致性</font>
组件化
质量指标
封装性
怎样才叫做封装的好??目前觉得可以先看设计模式,然后再找其他的组件化资料
扩展性
可组合性
可复用性
分类
基础组件
业务组件
前后端分离
目标
将前端开发和后端开发解耦,<font color="#924517">实现开发、维护、部署甚至发布的相对独立性,提高开发效率和快速响应问题</font>
方案
SPA 架构
优点
成本低
可离线??
缺点
不利于传统的 SEO,适用于无 SEO 需求的应用,如 Hybrid 应用
Node.js 渲染层
优点
首屏速度快
SEO 友好
同构编程的可能性??
缺点
实施成本高
性能
用户角度
首屏加载时间
操作响应速度
技术角度
Web 应用整体架构的<b><font color="#924517">任何环节(包括软件和硬件)</font></b>都能影响网站的性能
服务器分布式架构
负载均衡
数据缓存层
前端角度
加载性能
执行性能
快速响应用户操作
⚠️ 注意:要在性能和功能之间进行权衡
<b>根据架构特征<br></b>搭建<font color="#924517"><b>高效的前端工程服务体系</b></font><br>
<font color="#f1753f">核心是成本控制</font>
降低<b>开发本身</b>所消耗的<font color="#16884a"><b>人力成本</b></font>
降低<b>跨团队协作</b>消耗的<b><font color="#16884a">沟通成本</font></b>
跨团队协作消耗的沟通成本<b>非常昂贵</b>
开发
三种开发模式<br>的成本消耗<br>
个人独立开发
重复性体力劳动
团队协作开发
历史代码交接、模块集成消耗的<b>人力和沟通成本</b>
跨团队协作开发
由<b>各团队技术规范差异和开发进度不同步</b>所消耗的<b><font color="#924517">时间、人力和沟通成本</font></b>
前端工程服务体系<br>针对开发阶段的目标<br>
<ul><li>减少重复性体力劳动<br></li><li>建立统一的技术规范<br></li><li>辅助跨团队并行开发<br></li></ul>
构建
编程语言
将源代码转换为客户端可执行代码
性能优化
压缩混淆、自动生成 CSS Sprite、动态模块按需加载
部署策略
给静态资源 URL 加入 Hash 指纹和 CDN 路径???等
开发效率
文档生成、动态构建???等
审查评估
规范审查、性能评估等
测试
困难与解决
GUI(图形用户界面(Graphical User Interface)) 应用普遍难以测试
得益于 React\Vue 等前端框架的流行,在 Node.js 环境中将 HTML 文档内容渲染为字符串,从而可以进行 UI 快照测试???
前端技术过于灵活
制定统一代码规范甚至编程范式对 JavaScript 的灵活性进行一定程度的限制,使其更容易测试
部署
简单讲是把代码“放”到指定的服务器上
监控与统计
前端稳定性监控
前端本身的交互逻辑
数据接口
一旦出现 bug,用户的第一反应是前端的问题。前端团队接受反馈调试发现是服务端的问题,然后反馈至相关团队。<font color="#924517">这是一个非常漫长的过程,并且会消耗大量的沟通成本。</font>
<b>如果可以在前端调用接口没有返回预期结果时(通过何种机制来判断接口是否返回了预期结果??)立即反馈至监控平台并且报告错误信息</b>,开发团队便可以在<b>第一时间定位到问题的症结,缩短修复问题的时间</b>
1. 编程语言/<font color="#924517">确立所选编程语言<br>的开发模式</font><br>
为什么要从架构层面思考编程语言
为了选择适用于业务的架构模式和技术选型
<b>根据<font color="#924517">语言特征</font>制定<font color="#924517">技术规范和开发范式</font></b>,提高个人和团队的开发与维护效率
由于前端语言的单一性,“编程语言仅仅是一种工具”的论调并不适用于前端
HTML
SSR
工作流程
<ol><li>浏览器向网站发起请求<br></li><li>服务器接收到请求后<b>先查询数据库中的动态数据,然后<font color="#924517">将数据</font><u><font color="#16884a">通过模板引擎</font></u><font color="#924517">编译为 HTML 字符串</font>返回给浏览器</b><br></li><li>浏览器接收到 HTML 后将其渲染为可视化的 UI<br></li></ol>
优势
支持 SEO
首屏时间短
有更深的技术沉淀和产业生态
应用场景
<b>交互简单、以静态内容为主并且有 SEO 需求</b>的业务产品
具体实现
传统模板引擎
<b>借助于服务端编程语言或框架搭配的 HTML 模板引擎将数据编译为 HTML 文档</b>,比如适用于 Java 的 FreeMarker、适用于 PHP的 Smarty 以及适用于<b><font color="#924517"> Node.js 的 Pug</font></b> 等。<br><br>模板引擎<b>可以被理解为一个功能强大的字符串处理工厂。</b>
优势
缓存
Pug 也提供了 pug.render() 系列的函数,它们把编译和渲染两个步骤合二为一。<br>当然,在<b><font color="#924517">每次执行 render 的时候,这样一个模板函数都需要被重新编译一遍</font>,这会在一定程度上影响性能</b>。<br>但同时,您也可以<b>在执行 render 的时候配合使用 cache 选项,它将会<font color="#16884a">把编译出来的函数自动存储到内部缓存中</font></b>。<br>
快速
适用场景
<ul><li>非 Node.js 技术栈<br></li><li>渲染速度要求高<br></li></ul>
React/Vue SSR
优势
同构编程<br>(这里的意思是<b>同一组件<br>在客户端和服务端都能被<br>编译成HTML字符串</b>)<br>
<ul><li>节约了一定的开发成本<br></li><li>在一定程度上加强前后端试图逻辑的统一性<br></li></ul>
劣势
必须依赖 Node.js 环境
技术栈迁移成本高
<font color="#924517">性能差</font>
SSR仅仅使用框架中将数据编译为字符串的几个API,其他只适用于浏览器环境的API(如生命周期钩子)便成了冗余
适用场景
<ul><li>Node.js 技术栈<br></li><li>渲染速度要求略低<br></li></ul>
CSR
工作流程
<ol><li>浏览器向网站发起请求<br></li><li>服务器接收到请求后立即返回静态的HTML部分,这部分内容通常是与用户无关的静态数据<br></li><li>浏览器解析HTML文档,待JavaScript脚本加载完成之后发起异步请求,获取动态数据<br></li><li>服务器接收到异步请求后查询数据库并将动态数据返回给浏览器<br></li><li>浏览器接收动态数据后使用JavaScript将数据编译为HTML字符串并渲染为可视化的UI<br></li></ol>
劣势
<span style="font-size: inherit;">首屏渲染速度慢</span><br>
<b><font color="#924517">服务器的硬件配置通常优于个人终端设备,同时搭配模板引擎的缓存功能</font></b>,SSR在速度上的优势要远远大于CSR。<br><br>随着<b>个人终端设备硬件性能的不断提升</b>,CSR与SSR在速度上的差距逐渐减小;<br><b>网络传输速度和浏览器性能的提升</b>也缩短了首屏等待时间。
弱SEO
优势
更好地支持前后端分离方案的实施
更好地支持离线场景??
<b><font color="#16884a">基于组件</font>的前端路由管理在<font color="#16884a">速度和灵活性</font>上优于<font color="#924517">依赖服务器路由驱动</font>的MVC模式</b>
骨架屏
是交互设计上的优化
饿了么自动化生成骨架屏方案
预渲染与其缺点
<b>所谓预渲染,就是在项目的构建过程中,通过一些渲染机制,比如 puppeteer 或则 jsdom 将页面在构建的过程中就渲染好,然后插入到 html 中,这样在页面启动之前首先看到的就是预渲染的页面了</b>。<br><br>但是该方案最终也抛弃了,<font color="#924517">预渲染渲染的页面数据是在构建过程中就已经打包到了 html 中, 当真实访问页面的时候,真实数据可能已经和预渲染的数据有了很大的出入</font>,而且预渲染的页面也是一个不可交互的页面,在页面没有启动之前,用户无法和预渲染的页面进行任何交互,<font color="#924517">预渲染页面中的数据反而会影响到用户获取真实的信息,当涉及到一些价格、金额、地理位置的地方甚至会导致用户做出一些错误的决定</font>。因此我们最终没有选择预渲染方案。<br>
如何构建骨架屏
基本方案
通过 puppeteer 在服务端操控 headless Chrome 打开开发中的需要生成骨架屏的页面,<br>在等待页面加载渲染完成之后,在保留页面布局样式的前提下,<br>通过对页面中元素进行删减或增添??,对已有元素通过层叠样式进行覆盖??,<br>这样达到在<font color="#16884a"><b>不改变页面布局下,隐藏图片和文字,通过样式覆盖,使得其展示为灰色块</b>。</font><br>然后将修改后的 HTML 和 CSS 样式提取出来,这样就是骨架屏了。??<br>
Puppeteer
Headless Chrome Node.js API
Headless Chrome
Headless Chrome is shipping in Chrome 59. <br>It's a way to run the Chrome browser in a headless environment. <br>Essentially, <b><font color="#16884a">running Chrome without chrome!<br></font></b> It brings all modern web platform features provided by Chromium and the Blink rendering engine <br>to the command line.<br>
Why is that useful?
A headless browser is a great tool for<b> automated testing</b> and <b>server environments </b><font color="#924517">where you don't need a visible UI shell.</font> <br>For example, you may want to run some tests against a real web page, create a PDF of it, or just inspect how the browser renders an URL.<br>
通过 webpack 将骨架屏打包到项目中
为什么在开发过程中生成骨架屏
<font color="#c41230">为了骨架屏的可编辑</font>
在开发过程中对骨架屏进行编辑,修改部分样式,中部骨架屏可以进行实时预览,<br>这<b><font color="#924517">之间的通信都是通过websocket 来完成的</font></b><br>
<div id="app"><!-- shell.html --></div><br>我们在项目构建的过程中,将骨架 插入到上面代码注释的位置,这样在应用启动前,展示的是骨架屏,<br>当应用启动后,将真实数据渲染的页面替换骨架屏页面。<br>
怎样将骨架屏打包到项目中
<font color="#924517">Webpack 在整个打包的过程中提供了众多生命周期事件,比如compilation 、after-emit 等,</font><br>我们<b>最终将骨架屏插入到 html 中就是在after-emit 钩子函数中进行的</b><br>
SEO<br>(Search Engine <br>Optimization)<br>
普遍的弥补方案
构建阶段预渲染SPA的静态内容到 index.html
优点
实施成本低,不涉及服务端开发
缺点
<font color="#924517">本质上与首页 ssr、动态内容 ajax 的模式大同小异</font>,<br><b>对于存在大量路由和动态数据的 SPA 项目而言,对 SEO 的提升微乎其微。</b><br>
服务器判断请求来源,<br>将爬虫请求重定向到预渲染服务器,<br>使用<font color="#924517"> Headless Chorme</font> 预渲染 index.html
优点
可以将完整的 HTML 文档提供给爬虫程序
缺点
部署成本昂贵
额外的开发工作
硬件设备支持
可以使用第三方云服务
prerender.io
优化
在构建阶段将 SPA 各页面提前解析并存放于预渲染服务器中
SPA 的路由管理<font color="#16884a">必须使用 HTML5 History 模式而非 Hash 模式</font>,<font color="#924517">并且需要服务器支持</font>。<br><b>对于需要兼容低版本浏览器的SPA项目来说,此方案性价比不高。</b>
Hash 模式使用的是 URL 的片段标识符,本身的语义是主文档的一个片段标记,并非路由标记。<br><font color="#c41230">Hash 改变后不会向服务器发起请求,所以无法给爬虫程序提供完整的子页面数据。</font>
总结
根据业务特征(<b>SEO 的重要程度</b>)<br>选择<br>
资讯类网站首页、内容详情等需要 SEO 的页面使用 SSR;<br>用户中心、管理后台等无须 SEO 的页面可以使用 CSR
CSS
css 本身的缺陷
书写繁琐(不支持嵌套)<br><br>样式易冲突(没有作用域概念)<br><br>缺少变量(不便于一键换主题)<br><br>...
preprocessor 和 PostCss
预处理器,<br>以 LESS 为例<br>
优点
嵌套语法
<font color="#00a650">更易于编写和维护</font>
变量、混合、模块、继承等特性
<font color="#16884a">弥补了 CSS 逻辑处理和复用性方面的不足</font>
缺点
大而全,导致代码规范难以约束?? 没有一些类似 jsLint 的工具来检测??
难扩展
<font color="#924517">只有极少数编译器支持开发者扩展自定义插件,</font><br><b>核心架构过于封闭,缺少插件生态</b><br>
PostCss
最初被定位为“CSS后处理器”,<br>但后续的演进并未被束缚在后处理器的范畴,<br><b><font color="#16884a">逐渐进化成一个全面的“CSS转化工具”</font></b><br>
<b>PostCss 的内核并不会对 CSS 做任何转化,</b><br>而是<font color="#924517">将原始的 CSS 代码转化为抽象语法树并传递给各个插件</font>,<br>插件根据用户配置对 AST 进行处理后还原为最终的 CSS 代码<br>
CSS Modules
CSS-in-JS
<b>jsx 已经将 js 和 html 框定到一个组件中,但是css 依然处于分离状态,<br>这就导致了每次引用组件却还需要显示引入 css。<br></b><br><b> css-in-js 是正式彻底组件化的解决方案。</b><br>
优点<br>
模块
原生 CSS 和 SASS、LESS 的模块实质上仅仅是子文件,并非真正意义上的模块。<br><font color="#924517">将 JS 的模块体系带入 CSS 开发领域可以有效弥补 CSS 模块体系的补不足</font>。
命名空间
CSS-in-JS <font color="#924517">在编译时(有些是在运行时)为组件产生唯一的 classname 以及对应的选择器规则</font><font color="#5c5c5c">,</font><br><b>将组件及其内部元素的样式限制在唯一的命名空间内,从而实现样式的隔离</b>
动态性
依据我目前的了解,这和“命名空间”的优点,CSS Modules 都有
一定程度上减少无效代码
大概率指的是 webpack 中对 js 的 tree-shaking 功能
总结
<font color="#16884a">非常适用于组件化架构</font>
缺点
一定程度上限制了代码的可移植性
指的是不好移植其他 CSS 技术方案的项目中??<br>不好进行CSS代码的复用??<br>这需要对此方案有更深入的了解,以后需要用到时再研究
昂贵的学习成本
额外工具引入
All-in-JS 模式目前仍存在争议
编程过程中<b>需要在 HTML、CSS、JS 三种上下文语境之间频繁切换,</b><br>在<font color="#924517">某种意义上背离了关注点分离原则</font>。
关注点分离
关注点分离是日常生活和生产中广泛使用的解决复杂问题的一种系统思维方法。<br>大体思路是<font color="#924517">先将复杂问题做合理的分解,再分别仔细研究问题的不同侧面(关注点),最后综合各方面的结果,合成整体的解决方案。<br></font><br>关注点分离是计算科学和软件工程在长期实践中确立的一项方法论原则。<br>此原则<b>在业界更多的时候以分而治之的面目出现</b>,即将整体看成为部分的组合体并对各部分分别加以处理。<br><b>模块化是其中最有代表性的具体设计原则之一。</b><br>
库
根据不完全统计,各种 CSS in JS 的库至少有47种
styled-components
css-in-js 库我都没有实际用过,以后需要了再好好调查选择与实践
<ol><li>首先,styled-components 所有语法都是标准 css 语法,同时支持 scss 嵌套等常用语法,覆盖了所有 css 场景。<br></li><li>在样式复写场景下,styled-components 支持在任何地方注入全局 css,就像写普通 css 一样<br></li><li>styled-components 支持自定义 className,两种方式,一种是用 babel 插件, 另一种方式是使用 styled.div.withConfig({ componentId: "prefix-button-container" }) 相当于添加 className="prefix-button-container"<br></li><li>className 语义化更轻松,这也是 class 起名的初衷<br></li><li>更适合组件库使用,直接引用 import "module" 即可,否则你有三条路可以走:像 antd 一样,单独引用 css,你需要给 node_modules 添加 css-loader;组件内部直接 import css 文件,如果任何业务项目没有 css-loader 就会报错;组件使用 scss 引用,所有业务项目都要配置一份 scss-loader 给 node_modules;这三种对组件库来说,都没有直接引用来的友好<br></li><li>当你写一套组件库,需要单独发包,又有统一样式的配置文件需求,如果这个配置文件是 js 的,所有组件直接引用,对外完全不用关注。否则,如果是 scss 配置文件,摆在面前还是三条路:每个组件单独引用 scss 文件,需要每个业务项目给 node_modules 添加 scss-loader(如果业务用了 less,还要装一份 scss 是不);或者业务方只要使用了你的组件库,就要在入口文件引用你的 scss 文件,比如你的组件叫 button,scss 可能叫 common-css,别人听都没听过,还要查文档;或者业务方在 webpack 配置中单独引用你的 common-css,这也不科学,如果用了3个组件库,天天改 webpack 配置也很不方便。<br></li><li>当 css 设置了一半样式,另一半真的需要 js 动态传入,你不得不 css + css-in-js 混合使用,项目久了,维护的时候发现某些 css-in-js 不变了,可以固化在 css 里,css 里固定的值又因为新去求变得可变了,你又得拿出来放在 css-in-js 里,实践过就知道有多么烦心。<br></li></ol>
Houdini
思想是将 CSS 引擎的部分功能权限开放给开发者,以便于开发者扩展和自定义 CSS 特性
浏览器厂商为什么愿意推出全新的 Houdini <br>也不实现 CSS 的标准规范<br>
CSS规范在浏览器核心竞争力中优先级较低
CSS 规范的实现是一个非常漫长且需要持续跟进的过程
Houdini 是一个“一劳永逸”的方案
厂商真实意图
将规范的实现交给开发者
优点
减轻浏览器厂商的工作压力
丰富 CSS 生态
一定程度上推动 CSS 规范的演进
JS
JS 的灵活性
优点
JS 引擎可以“帮忙”处理一些繁琐的工作,如类型转换。<br>开发者可以集中精力在逻辑处理上。
缺点
细节的疏忽容易造成一些低级失误
结论
在进行复杂架构设计时既要借助统一的规范、框架和工具对其灵活性加以约束,同时又不能矫枉过正
灵活性的主要表现<br>及其约束途径
语言本身的灵活性
技术选型
技术栈
底层技术栈
TS 或者 Flow
解决语言层面的问题
要解决的两个主要问题
静态类型
数据不可变性
实现层技术栈
根据学习曲线、生态等因素的综合评定
实现方案的多样性
代码规范
代码风格
检测与较正
eslint 等工具
方案选择
典型案例是 JS 异步编程
标准
可行性
可扩展性
易读性
可维护性
检测
人工审查
静态类型
<font color="#16884a">JS 是一种动态类型语言</font>,开发者在声明变量时无须指明变量的类型,<b>解释器根据变量的赋值判断其类型</b>
TS
是什么
TypeScript is an open-source language which builds on JavaScript, one of the world’s most used tools, by <b>adding static type definitions.</b><br><br>Types provide a way to describe the shape of an object, <b>providing better documentation</b>, and allowing TypeScript to validate that your code is working correctly.<br><br>Writing types can be optional in TypeScript, because<b> <font color="#f1753f">type inference allows you to get a lot of power without writing additional code.??</font></b><br>
是 JS 的超集,一种编译性编程<b><font color="#924517">语言</font></b>
<font color="#c41230">目前看来ts只是在编写代码的时候有提示作用,编译后的线上代码并不健壮</font>
Flow
JS 的一种静态类型检查<b><font color="#924517">工具</font></b>
不可变性
JS 函数的传参方式只有<font color="#16884a">值传参</font>
function fn(obj){<br> obj.a=1<br>}<br>let obj={a:0}<br>fn(obj)<br>console.log(obj) //{ a: 1 }<br>
传给 fn 的参数并非外部 obj 指针本身,而是它的一个<font color="#924517">拷贝指针</font>
兴起原因
redux 的流行,<b>在状态管理这种特定场景下,不可变性令数据可预测、可追踪</b>
在不可变性操作中,每次“改变”数据的操作等同于<font color="#924517">先复制原数据再改变其属性或值</font>,<br>表面上看上去性能非常低,尤其是对象类型的数据。<br>应用时<b>通常需要辅以性能优化的逻辑</b>,比如 immutable.js 使用一种叫做 structural sharing 的数据共享方案。<br>
异步编程
JS 异步编程的基本原理<br>(以 ajax 请求为例)<br>
<b>1. JS 引擎</b>首先调用发起 AJAX 请求的函数本身,<br>请求被发出之后顺序执行<b>任务队列</b>中的下一个任务<br>
JS 核心概念脑图中的 JS 引擎
<b><font color="#924517">2. 浏览器的网络模块</font></b>得到 HTTP 响应之后<b>通知 JS 引擎,</b><br><b><font color="#16884a">Event Loop</font></b> <b>检测调用栈为空闲时</b>将回调函数加入<b>任务队列</b>并执行<br>
回调函数、Promise、Generator、async/await 均是在此基础上的具象封装
在多个可行的异步编程方案<br>之间进行选择时主要考虑因素<br>
简洁性
错误处理方式
相对底层的异步编程模式
回调函数
缺点
回调地狱
Promise
优点
解决了回调函数的回调地狱
缺点
单纯用 Promise 取代回调函数会产生新的 then hell 问题
较上层的异步编程模式
Generator
async/await
async 函数返回值
返回一个<b> Promise</b>,它将会<b>用异步函数的<font color="#0076b3">返回值来 resolved</font></b>,<br>或者<b><u><i>用异步函数<font color="#0076b3">内部没有捕捉到的错误来 rejected</font></i></u>。</b><br>
在简洁性和错误处理上都优于 Generator
2. 制定技术规范
在前端编程领域内,技术规范尤其是编码风格<b><font color="#924517">不仅仅是一种约定,而且在一定程度上决定了应用程序的技术架构</font></b>
技术选型<br>相对理性的评定标准<br>
功能<br>(基本指标)
满足<b>现阶段</b>产品的需求
满足<b>可预见的后续版本</b>中可能增加的需求
功能的具体实现模式、API 的简洁性
性能
稳定性<br>(重要指标)
生态
一个框架/工具的生态系统<br>分为两部分<br>
与其组合为完整系统的扩展插件或框架,如 Redux 之于 React,Vuex 之于 Vue
针对应用架构
其开发和调试工具的丰富性
针对工程体系
学习曲线
作者
总体而言,相对于个人项目,知名公司和团队制作的框架/工具的品质更高,稳定性也更有保障
社区
社区的活跃度能够反映项目的受欢迎程度,一个框架/工具被更多人使用和讨论也有助于问题的解决
开源协议
使用开源软件之前务必仔细研究其许可协议
资源管理<br>
前端资源管理<font color="#924517">最基本的规则/下限规则</font>
源码文件、构建产出文件以及第三方模块文件目录分离
构建产出文件和第三方模块不参与版本管理
目录结构,归类文件
通用原则
源码文件单独目录存放
src
构建产出文件单独目录存放
dist
第三方框架/工具单独目录存放
vendors
工程配置文件单独目录存放
config
单元测试文件单独目录存放
test
媒体资源(图片/视频等)单独目录存放
assets
源码文件归类因子
按类型
不同类型文件归类到一起,html 文件放一起,css、js 文件分别放一起
随着交互逻辑复杂度的提升、业务和组件数量的增长,<br>在一定程度上限制了架构的可伸缩性,并且会对开发者的工作效率产生负面影响<br>
按组件
规范
业务资源目录命名语义化,并且首字母大写
公共组件统一存放在二级目录 _components 内,且按组件归类源码文件
优点
<b>强化了文件的语义</b>,每个文件的作用一目了然
一定程度上<b>提高了架构的可伸缩性</b>,有益于开发和维护效率的提升
改造的成本非常低,基本不会涉及架构逻辑层面的改动
命名规范,强化语义
两项基本原则
语义性(核心)
一致性
编码风格
良好编码风格的基本原则
统一性
底线
两个方面
保证团队成员使用统一的编码风格
在版本迭代中保持风格一致
<b>新成员或项目交接后的开发者更容易理解历史代码并遵循既定的编程风格进行迭代</b>,<br>可减少由于版本更新积累的历史包袱<br>
语义化
语义化的范畴<b><font color="#924517">不仅仅是命名,</font><font color="#16884a">明确参数的类型和结构</font><font color="#5c5c5c">(ts在这点上很有帮助)</font>同样属于语义化的一部分</b>
恰到好处的注释
分为两部分
使用既定的格式对代码的元素进行说明,比如函数参数和返回类型
在语义化之外,通过自然语义描述以帮助开发者更容易理解源码
注释不宜过长,冗长且无营养的注释反而有碍于开发者理解代码
兼顾美观性
有强主观色彩。<br>只要不违法语法规则,团队成员保持形式统一,就是美观的代码。<br>
可以使用 prettier 来自动化规范统一代码风格
HTML
尽量使用语义化的 HTML 标签
JS
高性能与易读性
<font color="#924517">JS 语言的一些API或语法之间有性能差异</font>
数组循环操作
原始的 for 或 for...of 循环
<font color="#924517">随着数据量的增长,for...of 相比 reduce 的性能优势越来越明显</font>
forEach、map、reduce 等可读性更好的API
<font color="#16884a">可读性为性能让步通常体现在<b>大数据、计算密集型项目</b>上</font>,典型的是<font color="#924517">图形类应用,比如数据可视化、地图、游戏、WebVR 等。<br></font>图形编程类项目的数据规模的计算量往往超出常规前端项目几个量级,计算量接近设备硬件或浏览器的性能瓶颈,<b>提高计算逻辑的性能</b>是唯一的突破口。
CSS
CSS编程范式与面向对象
<font color="#924517">通过命名模拟既定的编程范式</font>
较普遍的做法是给HTML元素的 classname、id、data 等属性(以 classname 为主)的<b>名称施加某种命名规范</b>,<br><b>将 CSS 带入对应的编程范式语境之下,遵循编程范式的一些系统性的既定原则</b>来提高 CSS 代码的开发和维护效率。<br>
OOCSS
Object Oriented CSS(面向对象的 CSS )
理念
将网页的完整 UI 分解为一系列组件,每个组件的颗粒度尽可能细,从而最大程度地被复用
<font color="#924517">将每个 classname 视为一个功能单一的 CSS 组件</font><font color="#000000">,业务组件通过</font><font color="#924517"><b>组合</b></font><font color="#000000">多个 CSS 组件实现综合的样式效果</font>
UI 组件和 CSS 组件
CSS 组件
语义指向对应的样式,如 f12(font-size:12px)、m5(margin:5px)这类classname
通常要放在 UI 组件 classname 之前
UI 组件
语义指向UI组件功能,如 content 这类 classname
优点
<b>可组合性高</b>,非常适用于<b>可高度扩展</b>的前端项目,比较典型的是Strikingly之类的<b><font color="#924517">建站工具</font></b>
Strikingly
缺点
一个复杂样式的 HTML 元素 classname 太过冗长
不适合常规的前端项目
绝大多数组件都是业务指向性的,不需要很高的灵活性,所以 OOCSS 最大优势得不到体现,反而将其缺点暴露无遗
BEM
是 Block、Element、Modifier 的简称,<b>是 OOCSS 方法论的一种实现模式</b>
三种实体
Block
一个逻辑或功能独立的组件,如 logo 组件
Element
Block 内部的子组件,不能被外部访问
Modifier
描述一个 Block 或 Element 的表现或者行为
命名格式
block-name__<element-name>--<modifier-name>_modifier-value
实体命名均使用小写字母
只使用一个 classname 作为选择器,[0 0 1 0] 规则
优点
<b>非常适用于公共组件,可令组件的样式定制具有很高的灵活性</b>,<br>因为 [0 0 1 0] 选择器的权重非常低
自由主题
安全
灰帽 Python 之旅
大学霸 Kali Linux 安全渗透教程
Kali Linux 秘籍 中文版
Kali Linux 无线渗透测试入门指南 中文版
Kali Linux Web 渗透测试秘籍 中文版
python 安全编程教程
量化交易
Python 量化交易教程
程序员基本修养
基础
97 Things Every Programmer Should Know
HTTP API Design Guide
程序员的自我修养
数据结构与算法
数据结构与算法/leetcode/lintcode题解<br>
编程之法:面试和算法心得
数据挖掘十大算法详解
Git
<h3>Git Community Book 中文版</h3>
Git权威指南
GotGitHub
git-recipes
计算机网络
网络基本功系列
Linux
鸟哥的Linux私房菜:基础学习篇
鸟哥的Linux私房菜:服务器架设篇
完全用 GNU/Linux 工作
高级Bash脚本编程指南
Python
Python 核心编程 第二版
操作系统
操作系统思考 中文版
编程思想
程序设计思想和方法
0 条评论
下一页