├── .gitignore ├── LICENSE ├── README.md ├── React ├── event.md ├── index.md ├── virtual-dom.md └── webkit-painting.png ├── UI-design └── index.md ├── algorithm └── index.md ├── awesome-links └── index.md ├── browser ├── browsers.jpeg ├── cache.md └── compatibility.md ├── computer └── index.md ├── docker └── index.md ├── front-end-history ├── all-end.png ├── first-web-page.png ├── front-end-frames.jpg ├── front-end-history.md ├── full-stack-developer.png ├── google-mail.png ├── jsp.png ├── nodejs.png ├── spa.png └── web1.0.png ├── front-end-micro └── index.md ├── functionnal-programming └── index.md ├── graphics └── index.md ├── http ├── authorisation.md ├── cache.md ├── cros-origin.md ├── cross-domain-error.png ├── https.md ├── index.md └── option-request.png ├── interview └── index.md ├── monitor └── index.md ├── performance-optimization ├── browser-render.png ├── flight-status.jpeg ├── google-performance.png ├── image-20181109142635337.png ├── immutable.gif ├── index.md ├── layers-firfox.png ├── react-context.png ├── react-diff.png ├── react-fiber-1.png ├── react-fiber-2.png ├── react-fiber-3.jpg ├── setstate-dirty.png ├── skeleton-facebook.gif ├── skeleton-vs-loading.png ├── sprite-image.png ├── tree-dom.png ├── type-memory.png ├── webp-vs-jpg.png └── webp-vs-png.png ├── security ├── index.md └── sso.md ├── test └── index.md ├── the-way-of-coder └── index.md ├── tools ├── git.md ├── index.md └── webpack.md └── web-dev-basic ├── CSS ├── BEM.md ├── CSS Modules.md ├── css-history.png └── index.md ├── HTML.md ├── JavaScript ├── es6.md ├── event.md ├── event.md ├── index.md ├── memory-leak.md ├── module.md └── this.md ├── ajax-promise ├── index.md ├── static-vs-ajax.png ├── static-web.png └── web-interactive.png ├── code-style.md └── index.md /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # misc 4 | .DS_Store 5 | 6 | /coverage 7 | .idea 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 xiaosansiji 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cookbook-of-webdev 2 | 团队里又要来新鲜的小伙伴们了,超开心~ 3 | 4 | 但总也会很苦恼,同学们需要成长以尽快进入工作,老鸟们貌似总是琐事缠身,怎么办? 5 | 6 | 这里准备了一份 cookbook 给各位同学,里面有一些我觉得比较重要的技能,每篇文章里会有一些参考资料链接。 7 | 8 | > 偏前端:我现在主要做前端开发的工作,所以本 repo 也偏向前端开发相关的知识,欢迎 PR 补充后端开发知识。 9 | 10 | 下面列表先后次序并不代表阅读顺序,可以根据个人需求进行选择。如果从快速开始工作的需要来看,可以优先进行“前端开发技能”部分的学习,但在我看来,“计算机与网络基础”、“后端开发技能”与“web 性能”等章节同样非常重要,“前端开发”只能带你进入现代 web 开发的大门,能够走多远其他更取决于这些章节中所罗列知识的掌握情况。 11 | 12 | web 开发入门易,深入难,正在于此。 13 | 14 | 在这个 repo 里我会从一个普通前端开发者的角度来探讨下 CS 专业领域需要掌握的技能,受限于自己的知识水平,各文章中免不了有很多谬误,欢迎大家在 issue 中针对文章内容发起讨论,所有这些交流都将使得这个 repo 变得更加完善。 15 | 16 | 文章尽量遵循 [中文文案排版指北](https://mazhuang.org/wiki/chinese-copywriting-guidelines/) 规范,如有发现书写格式的问题,也欢迎指出。 17 | 18 | ------ 19 | 20 | ## 前端开发技能 21 | 22 | web 前端行业现在是在一个繁荣又混乱的时代,各类框架/库层出不穷,github 上好像每天都有新 repo 被创建,老铁们纷纷表示“老子学不动了!”,比如这位[deno issue 25](https://github.com/ry/deno/issues/25)。[^1]这其实并不是一件多么可怕的事情,新库不断出现一方面代表现在 web 前端社区活跃,另一方面其实也是因为 web 前端是一个相对较新的领域,业界正在“补课”,可能在前端开发成熟到 java 开发现有阶段时,就不会有各种轮子被重复创造了(虽然我觉得这并不一定是件好事)。 23 | 24 | 近期我们已经看到了这样的趋势,在最近的前端开发框架讨论中已经少了那么多戾气,大家在选择框架的时候更多在考虑自己团队已有的技术积累等,而不是比对各框架大小或执行速度(它们的执行速度都没有了质的差别),大型项目多采用 React/Vue/Angular ,小项目则看自己爱好。所以在下面讨论前端开发知识点时,我们尽量以框架无关的角度来分享,而为了新同学尽快进行团队项目前端开发,所以特别增加了“团队前端框架”(React + Redux 技术栈)章节以供参考。 25 | 26 | [^1]: 关于“学不动了”的 issue,理解但并不支持,请不要把 github 变成百度贴吧,技术讨论社区应该严谨认真,不是哗众取宠和耍机灵的地方。 27 | 28 | ### 前端进化史 29 | 30 | 在真正开始学习前,我们有必要了解下前端开发技术的演进历史,并且随着近年来“大前端”概念的扩展,我们有必要对本次讨论的技术范围进行一下说明。 31 | 32 | [查看](./front-end-history/front-end-history.md) 33 | 34 | ### 网页开发基础 35 | 36 | 这里我使用了“网页开发基础”这个题目,实际上“网页开发” [^2]就是在“前端开发”这个名字被广泛认同之前,我们这群工程师写在工牌上的名字。在 Jquery 时代,我们可以认为没有框架的概念[^3],我们更多是运用“三剑客”来实现美工的设计稿,它们是 HTML/CSS/JavaScript,这也是我们的基础技能,在我们职业生涯的任何一个时间点,我们都应该时不时将这些知识点拿出来复习一下。 37 | 38 | [查看](https://github.com/xiaosansiji/cookbook-of-webdev/blob/master/web-dev-basic/index.md) 39 | 40 | [^2]: 在这个头衔出现之前,其实都不存在单独的前端开发的岗位,页面只是传统后端工程师为实现用户接口(UI)而顺带完成工作而已。 41 | [^3]: 在今天这个时间点来看,Jquery 更应该算是一个 Liberay,而不能算是一个完整的开发框架,但这并不妨碍 Jquery 是一个伟大的产品。 42 | 43 | ### Ajax 、 Fetch 44 | 45 | [查看](./web-dev-basic/ajax-promise.md) 46 | 47 | ### 为什么我们需要框架 48 | 49 | ### React 技术栈 50 | 51 | ### 前端微服务化 52 | 53 | ### 测试 54 | 55 | ## HTTP 56 | 57 | [查看](./http/index.md) 58 | 59 | ## 网页设计能力 60 | 61 | ## 后端开发技能 62 | 63 | ## 工具使用 64 | 65 | ## web 站点性能优化 66 | 67 | [查看](https://github.com/xiaosansiji/cookbook-of-webdev/blob/master/performance-optimization/index.md) 68 | 69 | ## 函数式编程 70 | 71 | [在你身边你左右 --函数式编程别烦恼]: https://juejin.im/post/5b26a8b66fb9a00e925bcf30#heading-10 72 | 73 | ## 计算机与网络基础 74 | 75 | ## 技术人之路 76 | 77 | ## Awesome Links 78 | 79 | 这里有一些非常好的学习链接,帮助你学习到所有计算机相关知识,[查看](./awesome-links/index.md) 80 | 81 | 82 | 83 | # 84 | -------------------------------------------------------------------------------- /React/event.md: -------------------------------------------------------------------------------- 1 | # React 中的事件处理机制 2 | 3 | -------------------------------------------------------------------------------- /React/index.md: -------------------------------------------------------------------------------- 1 | # React 2 | 3 | ## 参考链接 4 | 5 | - [《React源码解析》系列完结!](https://juejin.im/post/5a84682ef265da4e83266cc4?utm_medium=fe&utm_source=weixinqun) 6 | - [React中的五种组件形式](https://scq000.github.io/2017/07/11/React%E4%B8%AD%E7%9A%84%E4%BA%94%E7%A7%8D%E7%BB%84%E4%BB%B6%E5%BD%A2%E5%BC%8F/) 7 | - [react-developer-roadmap](https://github.com/adam-golab/react-developer-roadmap) 8 | - [你真的理解setState吗?](https://juejin.im/post/5b45c57c51882519790c7441) 9 | - [React 16 加载性能优化指南](https://juejin.im/post/5b506ae0e51d45191a0d4ec9) 10 | - [React-HOC了解一下](https://juejin.im/post/5b87f9cb6fb9a019e308dee9) 11 | 12 | -------------------------------------------------------------------------------- /React/virtual-dom.md: -------------------------------------------------------------------------------- 1 | # React Virtual DOM 2 | 3 | ## 是什么 4 | 5 | ###HTML DOM 6 | 7 | HTML DOM 定义了访问和操作 HTML 文档的标准方法。 8 | 9 | DOM 提供了对 HTML 文档的结构化(树)表述,JavaScript 可以通过 DOM 访问和操作页面元素。 10 | 11 | 12 | 13 | 多说一句,DOM 并不是只能被 JavaScript 调用。 14 | 15 | ###React Virtual DOM 16 | 17 | React Virtual DOM 与 HTML DOM 有什么区别? 18 | 19 | 20 | 21 | ###Vue Virtual DOM 22 | 23 | ```javascript 24 | var child1 = React.createElement('li', null, 'First Text Content'); 25 | var child2 = React.createElement('li', null, 'Second Text Content'); 26 | var root = React.createElement('ul', { className: 'my-list' }, child1, child2); 27 | ``` 28 | 29 | ```javascript 30 |
31 | Welcome back, {{person.firstName}} {{person.lastName}}! 32 |
33 |
34 | Please log in. 35 |
36 | ``` 37 | 38 | 模板引擎 VS JSX:各种指令 => JavaScript 39 | 40 | ## 为什么 41 | 42 | 关于 Virtual DOM 快不快的讨论:[网上都说操作真实 DOM 慢,但测试结果却比 React 更快,为什么?](https://www.zhihu.com/question/31809713/answer/53544875) 43 | 44 | ![webkit-painting](/Users/sunzhe/code/cookbook-of-webdev/React/webkit-painting.png) 45 | 46 | ### DOM Diff 算法 47 | 48 | 为了解答 React Virtual DOM 为什么快及性能调优方案,我们有必要了解渲染过程背后的 Diff 算法 49 | 50 | ## show me the code 51 | 52 | 源码解读 53 | 54 | ## 性能调优 55 | 56 | ## 注意事项 57 | 58 | [React合成事件和DOM原生事件混用须知](https://juejin.im/post/59db6e7af265da431f4a02ef) 59 | 60 | class => className 61 | 62 | ## Diff 63 | 64 | [深入浅出React(四):虚拟DOM Diff算法解析](http://www.infoq.com/cn/articles/react-dom-diff) 65 | 66 | -------------------------------------------------------------------------------- /React/webkit-painting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/React/webkit-painting.png -------------------------------------------------------------------------------- /UI-design/index.md: -------------------------------------------------------------------------------- 1 | # 网站设计 2 | 3 | [Front-End-Design-Checklist]: https://github.com/thedaviddias/Front-End-Design-Checklist/blob/master/README.md 4 | 5 | -------------------------------------------------------------------------------- /algorithm/index.md: -------------------------------------------------------------------------------- 1 | # 算法基础 2 | 3 | [前端你应该了解的数据结构与算法](https://juejin.im/post/5b331bc7f265da598451fd88) -------------------------------------------------------------------------------- /awesome-links/index.md: -------------------------------------------------------------------------------- 1 | # 一些比较好的学习链接,持续更新 2 | 3 | - [Kickball/awesome-selfhosted](https://github.com/Kickball/awesome-selfhosted) 4 | - [shovanch/fullstack-web-developer-path](https://github.com/shovanch/fullstack-web-developer-path) 5 | - [wxyyxc1992Web-Series](https://github.com/wxyyxc1992/Web-Series) 6 | - [smyhvae/Web](https://github.com/smyhvae/Web) 7 | - [dypsilon/frontend-dev-bookmarks](https://github.com/dypsilon/frontend-dev-bookmarks) 8 | - [dexteryy/spellbook-of-modern-webdev](https://github.com/dexteryy/spellbook-of-modern-webdev) 9 | - [davidsonfellipe/awesome-wpo](https://github.com/davidsonfellipe/awesome-wpo) 10 | - [dypsilon/frontend-dev-bookmarks](https://github.com/dypsilon/frontend-dev-bookmarks) 11 | - [li-xinyang/FE_Note](https://github.com/li-xinyang/FE_Note) 12 | - [helloqingfeng/Awsome-Front-End-learning-resource](https://github.com/helloqingfeng/Awsome-Front-End-learning-resource) 13 | - [chokcoco/iCSS](https://github.com/chokcoco/iCSS) 14 | - [KieSun/InterviewMap](https://github.com/KieSun/InterviewMap) 15 | - [Hux Blog](http://huangxuan.me/) 16 | - [送给前端的你,推荐几篇前端汇总文章](https://zhuanlan.zhihu.com/p/22229868) 17 | - [前端每周清单半年盘点之 CSS 篇](https://zhuanlan.zhihu.com/p/29065136) 18 | - [有哪些值得关注的技术博客(前端篇)](https://zhuanlan.zhihu.com/p/22276837) 19 | - [2018上半年掘金微信群日报优质文章合集:前端篇](https://juejin.im/post/5b3adfe2e51d4555b17e85df) 20 | 21 | 22 | ## common 23 | 24 | - [bjut-hz/E-Books](https://github.com/bjut-hz/E-Books) 25 | - [wxyyxc1992Awesome-Links](https://github.com/wxyyxc1992/Awesome-Links) 26 | - [ossu/computer-science](https://github.com/ossu/computer-science) 27 | - [tuteng/Best-websites-a-programmer-should-visit-zh](https://github.com/tuteng/Best-websites-a-programmer-should-visit-zh) 28 | - [jwasham/coding-interview-university](https://github.com/jwasham/coding-interview-university) 29 | - [CyC2018/Interview-Notebook](https://github.com/CyC2018/Interview-Notebook) 30 | - [jobbole/awesome-programming-books](https://github.com/jobbole/awesome-programming-books) 31 | - [EZLippi/practical-programming-books](https://github.com/EZLippi/practical-programming-books) 32 | - [donnemartin/system-design-primer](https://github.com/donnemartin/system-design-primer) 33 | 34 | ## AI 35 | 36 | - [fengdu78/deeplearning_ai_books](https://github.com/fengdu78/deeplearning_ai_books) 37 | -------------------------------------------------------------------------------- /browser/browsers.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/browser/browsers.jpeg -------------------------------------------------------------------------------- /browser/cache.md: -------------------------------------------------------------------------------- 1 | # 浏览器缓存 2 | 3 | - [HTTP 缓存](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Caching_FAQ) 4 | 5 | -------------------------------------------------------------------------------- /browser/compatibility.md: -------------------------------------------------------------------------------- 1 | # 浏览器兼容性 2 | 3 | 浏览器是网页运行的平台,常用的浏览器有IE、火狐(Firefox)、谷歌(Chrome)、猎豹浏览器、Safari和Opera等。如下图所示: 4 | 5 | ![browsers](browsers.jpeg) 6 | 7 | 浏览器内核: 8 | 9 | | 浏览器 | 内核 | 10 | | ----------- | ------- | 11 | | IE | trident | 12 | | chrome / 欧鹏 | blink | 13 | | 火狐 | gecko | 14 | | Safari | webkit | 15 | 16 | PS:「浏览器内核」也就是浏览器所采用的「渲染引擎」,渲染引擎决定了浏览器如何显示网页的内容以及页面的格式信息。**渲染引擎是兼容性问题出现的根本原因。** 17 | 18 | [01-html标签图文详解(一)]: https://github.com/smyhvae/Web/blob/master/01-html/01-html%E6%A0%87%E7%AD%BE%E5%9B%BE%E6%96%87%E8%AF%A6%E8%A7%A3%EF%BC%88%E4%B8%80%EF%BC%89.md 19 | 20 | ## 参考链接 21 | 22 | - [如何机智地回答浏览器兼容性问题](https://juejin.im/post/5b3da006e51d4518f140edb2) -------------------------------------------------------------------------------- /computer/index.md: -------------------------------------------------------------------------------- 1 | # 计算机相关知识 2 | 3 | [前端&后端程序员必备的Linux基础知识](https://juejin.im/post/5b3b19856fb9a04fa42f8c71) 4 | 5 | [CyC2018/Interview-Notebook](https://github.com/CyC2018/Interview-Notebook/blob/master/notes/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md) -------------------------------------------------------------------------------- /docker/index.md: -------------------------------------------------------------------------------- 1 | # Docker 2 | 3 | ## 常用指令 4 | 5 | 查看镜像id:`docker images -q` 6 | 删除镜像:`docker rmi image_id` 7 | 删除所有镜像:`docker rmi $(docker images -q)` 8 | 创建容器:`docker run --name image_i` 9 | 查看所有容器:`docker ps -a` 10 | 查看运行容器:`docker ps` 11 | 查看容器id:`docker ps -q` 12 | 进入容器:`docker exec -it bash` ,基于 alpine 的镜像没有 /bin/bash 可用,可以使用 `docker exec -it sh` 13 | 退出容器:`exit` 14 | 删除容器:`docker rm ` 15 | 删除所有容器:`docker rm $(docker ps -aq)` 16 | 17 | 根据dockerfile打镜像:`docker build -t [-f ] <路径>` 18 | 给镜像改名字:`docker tag :` 19 | 发布镜像:`docker push ` -------------------------------------------------------------------------------- /front-end-history/all-end.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/front-end-history/all-end.png -------------------------------------------------------------------------------- /front-end-history/first-web-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/front-end-history/first-web-page.png -------------------------------------------------------------------------------- /front-end-history/front-end-frames.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/front-end-history/front-end-frames.jpg -------------------------------------------------------------------------------- /front-end-history/front-end-history.md: -------------------------------------------------------------------------------- 1 | # 前端进化史 2 | 3 | > 本章的目的是大家能够对前端开发的范围和技术演进有一个大体概念,算是入门科普读物,多故事,少干货。 4 | 5 | ## 什么是前端 6 | 7 | 维基百科是这样说的:前端(front-end)和后端(back-end)是描述进程开始和结束的通用词汇。前端作用于采集输入信息,后端进行处理。计算机程序的界面样式,视觉呈现属于前端。 8 | 9 | --- 10 | 11 | 这样好像什么都没说,我们从两方面来看这个问题。 12 | 13 | ### 团队内的角色定位 14 | 15 | - 视觉设计师(字体、颜色、间距、情调、视觉概念和主题) 16 | - UI/交互设计师/信息架构师(也就是线框、所有用户交互和 UI 功能、的指定,信息的架构) 17 | - 前端开发者(也就是编写运行在客户端/设备上的代码) 18 | - 后端开发者(也就是编写运行在服务端的代码) 19 | - QA 工程师 20 | - 数据库管理 21 | - 运维工程师 22 | 23 | 你可以清楚的看到在一个传统开发团队中,前端开发岗位的位置与分工。 24 | 25 | ### 各端包括的范围 26 | 27 | - PC web:IE/Edge/Chrome/Firefox... 28 | - 移动 web:H5 29 | - 移动 App:混合式开发 30 | - PC App:Electron + Node.js 31 | 32 | 大前端概念在业界逐渐普及,多个一线互联网企业也纷纷组建“大前端团队”,从开发技术/使用语言/开发模型等多个方面看,将 PC web、移动APP及微信小程序等开发工作交给一个统一的团队来迭代维护有其合理性,但受限于本人知识范围限制,在本 repo 中会偏重 PC web ,其他端开发只会略有涉及,希望后续能有其他同学协助完善其他对应章节。 33 | 34 | ## 前端演进史 35 | 36 | ![first-web-page](./first-web-page.png) 37 | 38 | Tim Berners-Lee 建立了世界上第一个网站,可以点击[这里](http://info.cern.ch/hypertext/WWW/TheProject.html)访问[^1],可以看出这个站点肯定不是某位“前端工程师”写的,实际上那时候并没有这个岗位。但请注意,虽然这个站点非常简陋,但已经体现了后续网页设计的很多基本原则,对 UI 设计感性的同学可以[点击](这里要放一个到“网页设计”md的链接)。 39 | 40 | [^1]: 这个站点最初上线时的 url 并不是这个,这里记录的是迁移后的地址,原地址已不可访问。 41 | 42 | 在 web 出现后的很多年里,都不存在独立的前端开发概念,直到 JavaScript 出现,我们的页面有了“逻辑”,也真正“动”了起来。 43 | 44 | 我非常喜欢[王下邀月熊](https://github.com/wxyyxc1992) 同学的这份 [Web 开发简史与运行机制](https://github.com/wxyyxc1992/Web-Series/blob/master/%E5%AF%BC%E8%AE%BA/%E5%BC%80%E5%8F%91%E7%AE%80%E5%8F%B2%E4%B8%8E%E5%8F%98%E8%BF%81.md) ,在此放一下王下做的前端发展历史总结表: 45 | 46 | | Era/ 时代 | Timeline/ 时间线 | Problems/ 问题 | Innovations/ 创新 | Dominant Browsers/ 主流浏览器 | 47 | | --------- | -------------- | ------------------- | ------------------------- | ---------------------------------------- | 48 | | 蛮荒时代 | 大概 1996 – 2004 | 基础 DOM 操作,用户交互 | JavaScript 本身,XHR 与 AJAX | Netscape Navigator, Microsoft Internet Explorer | 49 | | jQuery 时代 | 大概 2004 – 2010 | 增长的网页复杂度,大量的浏览器兼容需求 | 健壮的 DOM 操作,早期的 SPA 单页应用 | Microsoft IE,Mozilla Firefox | 50 | | SPA 时代 | 大概 2010-2014 | DHTML 过载,大规模数据操作,性能 | MVC 框架,双向数据流,DOM 自动化 | Google Chrome,Microsoft IE , Mozilla Firefox,Apple Safari | 51 | | 现代 | 大概 2014- 现在 | 性能,复杂应用的状态管理,可用性 | Virtual DOM,单向数据流,类型系统,测试 | Google Chrome,Apple Safari | 52 | 53 | ### jQuery 时代 54 | 55 | 如上,大约从 jQuery 时代开始,渐渐的开始有了前端开发岗概念,不过在这一阶段,后端工程师主导了整个 web 产品,在这些以ASP.Net JSP 为代表的技术栈中,前端工作只占很小的部分,重业务逻辑,弱展现弱交互。这时前端开发工程师在MVC中负责 View 层,样式开始多样起来,如下图所示,我们的前辈们主要在各类后端模板中写静态结构和样式: 56 | 57 | ![jsp](./jsp.png) 58 | 59 | 如上,把整个 HTML 结构写出来,动态内容交由后端工程师填写,俗称“挖坑”。 60 | 61 | 以 JSP 为例,当时的用户与后端交互大概是这样: 62 | 63 | ![web1.0](./web1.0.png) 64 | 65 | ### SPA 时代 66 | 67 | 后来大概在 2004 年出现了一款跨时代的产品:谷歌邮箱 68 | 69 | ![google-mail](./google-mail.png) 70 | 71 | Ajax 早在1996年就被发明了,但在谷歌邮箱中,我们看到了 SPA[^2] 的雏形,web的体验可以比肩原生 APP。 72 | 73 | [^2]: Single Page Application 单页应用 74 | 75 | 像谷歌邮箱这样的多操作、非刷新渲染的大型 web 项目,给前端开发带来了诸如模块化开发、状态管理等要求,而原先这些都只在后端或其他原生 APP 中才会出现,为了应对挑战,业界陆续出现了如 Backbone、Angular 等解决方案,网站正式进入 web2.0 时代,前端也迎来了生产力的大发展。 76 | 77 | 如下展示了 SPA 前后端分离架构的交互: 78 | 79 | ![spa](./spa.png) 80 | 81 | 可以看出 82 | 83 | - 前后端职责很清晰。前端工作在浏览器端,后端工作在服务端。清晰的分工,可以让开发并行,前端开发不需要后端环境,可以本地开发。后端则可以专注于业务逻辑的处理,输出 RESTful 等接口。 84 | - 前端开发的复杂度可控。前端代码很重,但合理的分层,让前端代码能各司其职。 85 | - 部署相对独立,产品体验可以快速改进。(前端体验的迭代速度一般高于后端接口) 86 | 87 | ### 现代 88 | 89 | 在 SPA 出现的时代,前端的架构和所面临的需求已经跟移动 APP 没有什么区别,所以业界也从移动开发领域借鉴了大量诸如 MVC、MVP 等设计思想,各类框架层出不穷[^3]。 90 | 91 | [^3]: 无论什么样的设计与分层,都是为了关注点的分离及由此带来的开发与迭代上的方便,在我们团队我们选择了 React + Redux 技术栈,感兴趣的同学可以参[这一章](这里需要链接到“前端框架选型”章节) 92 | 93 | ![front-end-frames](./front-end-frames.jpg) 94 | 95 | ## 全端时代 96 | 97 | 章节开头我们说过本 repo 会着重 PC web,但我们也必须要看到,web 的生产力现在已经远远突破了浏览器的限制,在各个“端”上都有上佳体现: 98 | 99 | ![all-end](./all-end.png) 100 | 101 | 长久以来,人们为了解决跨平台问题(无论是早期的 linux、Windows、MacOS 三国杀,还是后来的 IOS、Andorid 爱恨情仇)提出了多种多样的技术手段,如大名鼎鼎的 Qt 等,但一直忽略了最常见的 web[^4]:借助浏览器带来的平台无关性,web 几乎可以在任何需要用户界面的设备上提供一致的体验。 102 | 103 | [^4]: 其实并不是故意忽略,而是受限于当时的 web 展现效果及设备性能等因素。 104 | 105 | ## 大前端时代 106 | 107 | ![full-stack-developer](./full-stack-developer.png) 108 | 109 | > JavaScript run everywhere! 110 | 111 | JavaScript 的运行环境已经不仅仅局限在各种“端”上,在 nodejs 出现后,它同样可以运行在服务器上[^5]。 112 | 113 | [^5]: 与浏览器带来跨平台优势类似,nodejs 通过 v8 引擎提供了可直接在服务器运行的环境。曾经 nodejs 是 JavaScript 介入后端开发的唯一途径,但现在也有了其他选择,比如近期 nodejs 的早期作者 ry 开源的新玩具 [deno](https://github.com/ry/deno),期待其后续的发展。 114 | 115 | 现在的前端工程化的需求,离不开 nodejs 等后端语言的支持,比如我们想在后端接口还未开发完成的时候进行数据 mock,免不了要通过 nodejs 编写简单的 http 接口。 116 | 117 | 另一方面,单纯按照浏览器 - 服务器这样一刀切的按照运行环境划分前后端也不再适应很多实际开发场景,很多产品会在传统的浏览器端和服务器端中间加入 nodejs 层,去处理如权限校验、后端渲染、接口数据处理等事情,这些其实更适合前端工程师去做,接口只负责业务逻辑,不再掺杂页面逻辑。 118 | 119 | 因此我们的前后端划分则变成了这样: 120 | 121 | ![nodejs](./nodejs.png) 122 | 123 | ## 回顾 124 | 125 | > 从水下第一个生命的萌芽开始...到石器时代的巨型野兽...再到人类的第一次直立行走,你已经历许多。现在,开启你最伟大的探索吧:从早期文明的摇篮到浩瀚星宇! --《文明6》开场词 126 | 127 | 我们已经回顾了从刀耕火种的荒蛮到现在各类奇技淫巧的框架和类库带来的高生产力,这些并非只是茶余饭后的谈资,事实上只有了解了各类工具产生的时代,去了解他们各自解决的问题,才能更理性的看待现在各开发框架层出不穷的现状:不要再感叹“老子学不动了!”,为了用新框架而去用框架,那你最后什么也没学到,这一个个框架背后的设计理念才是你工作经验中最宝贵的财富。 128 | 129 | PS. 这篇文章来自于我去年一次团队内分享的 PPT,写的过程中借鉴了多篇网络上的文章(包括引用的图片在内),但是当时并没有保存链接,在此深表歉意。如果大家有发现图片等确切来自于某篇文章,请及时联系我,我会与原作者联系,在下方添加参考链接或删去对应内容,感谢! 130 | 131 | ## 参考链接 132 | 133 | - [Web 开发简史与运行机制](https://github.com/wxyyxc1992/Web-Series/blob/master/%E5%AF%BC%E8%AE%BA/%E5%BC%80%E5%8F%91%E7%AE%80%E5%8F%B2%E4%B8%8E%E5%8F%98%E8%BF%81.md) -------------------------------------------------------------------------------- /front-end-history/full-stack-developer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/front-end-history/full-stack-developer.png -------------------------------------------------------------------------------- /front-end-history/google-mail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/front-end-history/google-mail.png -------------------------------------------------------------------------------- /front-end-history/jsp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/front-end-history/jsp.png -------------------------------------------------------------------------------- /front-end-history/nodejs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/front-end-history/nodejs.png -------------------------------------------------------------------------------- /front-end-history/spa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/front-end-history/spa.png -------------------------------------------------------------------------------- /front-end-history/web1.0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/front-end-history/web1.0.png -------------------------------------------------------------------------------- /front-end-micro/index.md: -------------------------------------------------------------------------------- 1 | 参考链接 2 | 3 | [如何实现前端微服务化?]: https://segmentfault.com/p/1210000010459082/read 4 | [如何解构单体前端应用——前端应用的微服务式拆分]: http://baijiahao.baidu.com/s?id=1595295714541106181&amp;amp;amp;wfr=spider&amp;amp;amp;for=pc 5 | [微前端 - 将微服务理念延伸到前端开发中]: https://www.cnblogs.com/zhuanzhuanfe/p/7644846.html 6 | [微前端的那些事儿]: https://github.com/phodal/microfrontends 7 | 8 | 因为我们团队前端开发技术栈比较统一,也还不存在需要兼容遗留系统的问题,所以采用如下方案: 9 | 10 | - 抽取前端项目骨架/工具等公用部分 11 | - 各应用通过 git submodules 或 npm 私有镜像库拉取公用部分到各自代码目录 12 | - 各应用分别打包部署上线 13 | - 做泛域名下单点登录,共享用户登录状态 14 | - 使用 cookie/后端存储共享部分用户数据 15 | 16 | 对于后端微服务来说,必须要有注册中心来管理各服务访问地址,同样在前端我们通过路由来管理各应用下暴露出来的功能页面。 17 | 18 | -------------------------------------------------------------------------------- /functionnal-programming/index.md: -------------------------------------------------------------------------------- 1 | [JavaScript 函数式编程一](https://juejin.im/post/5b7014d5518825612d6441f8) 2 | 3 | [JavaScript 函数式编程](https://juejin.im/post/5b4ac0d0f265da0fa959a785) -------------------------------------------------------------------------------- /graphics/index.md: -------------------------------------------------------------------------------- 1 | # 图形化相关技术 2 | 3 | 游戏相关: 4 | 5 | - OpenGl 6 | - WebGl 7 | - canvas 8 | 9 | 数据可视化相关: 10 | 11 | - canvas 12 | - d3 13 | - 各种 chart 如 echart 等 14 | 15 | demo: 16 | 17 | - [水波图实现原理](https://juejin.im/post/5b4ffa045188251b134e7211) 18 | -------------------------------------------------------------------------------- /http/authorisation.md: -------------------------------------------------------------------------------- 1 | # 认证相关 2 | 3 | - [不要用JWT替代session管理(上):全面了解Token,JWT,OAuth,SAML,SSO](https://juejin.im/post/5b3b870a5188251ac85826b8) 4 | - [OAuth2.0认证授权workflow探究](https://juejin.im/post/5b436b056fb9a04fc226961d) 5 | -------------------------------------------------------------------------------- /http/cache.md: -------------------------------------------------------------------------------- 1 | # HTTP 缓存 2 | 3 | ## 参考链接 4 | 5 | - [面试精选之http缓存](https://juejin.im/post/5b3c87386fb9a04f9a5cb037) 6 | 7 | -------------------------------------------------------------------------------- /http/cros-origin.md: -------------------------------------------------------------------------------- 1 | # 跨域处理 2 | 3 | ## 同源策略 4 | 5 | > 同源策略:Same Origin Policy 6 | 7 | 在讨论跨域之前,我们有必要解释下“同源策略”: 8 | 9 | 同源策略是浏览器的一种安全限制,它限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互,这是一个用于隔离潜在恶意文件的重要安全机制。 10 | 11 | 我们在前端开发过程中遇到的某些资源,如 DOM、Ajax/Fetch 返回的异步数据及浏览器本地存储的 Cookie、localStorage 等,一般会比较敏感。 12 | 13 | 想象以下场景,我们登录在线银行,这个站点依赖 Cookie 来保护我们的用户信息:只有正常登录认证过的用户,服务器端会在浏览器中存储一个生成的 Cookie 来标识这个用户,允许正常进行转账操作。而在浏览完这个站点后,我们又访问了一个恶意站点,如果没有同源策略限制,这个恶意网站也可以拿到银行站点存储的 Cookie 并传输给别人,那么在这个 Cookie 过期之前,别人可以把你的银行卡搬空。。 14 | 15 | 关于 DOM 操作也是一样的,虚假钓鱼网站以 iframe 的方式嵌入了真实网站,我们在访问时可能根本发现不了,如果没有同源策略限制,主页面可以任意操作子页面中 DOM 元素,比如在用户密码输入框上增加了额外的事件监听,同样可以诱导我们暴露个人敏感信息[^1]。 16 | 17 | [^1]: 当然为了防止我们的站点被嵌入到钓鱼站点的 iframe 中,我们也可以通过 meta 声明、后端服务器设置等规避,如在 HTML 中增加如下 meta: ``,其他设置将在 web 安全章节详细说明。 18 | 19 | 而我们经常见到的另一些资源,如 CSS 样式表文件、JS 文件、字体文件、图片等因为不具备敏感信息,所以不受同源策略限制,这些静态资源我们可以依赖 CDN 来部署和分发以提高用户体验:一方面 CDN 节点众多,可以就近响应用户请求;另一方面,浏览器在发起请求的时候会默认带上本域的 Cookie,而请求静态资源时明显不需要 Cookie 保护,每次请求都带 Cookie 增大了网络带宽消耗,我们的 CDN 域一般与我们的站点域不一致,可以规避这个问题。 20 | 21 | ## 判断跨域 22 | 23 | 同源:协议、域名、端口都相同。详情可以参见[这里](https://developer.mozilla.org/en-US/docs/Archive/Misc_top_level/Same-origin_policy_for_file:_URIs) 。 24 | 25 | 示例: 26 | 27 | | URL | 结果 | 原因 | 28 | | ---------------------------------------- | ---- | ------------------- | 29 | | `http://store.company.com/dir2/other.html` | 成功 | | 30 | | `http://store.company.com/dir/inner/another.html` | 成功 | | 31 | | `https://store.company.com/secure.html` | 失败 | 不同协议 ( https和http ) | 32 | | `http://store.company.com:81/dir/etc.html` | 失败 | 不同端口 ( 81和80) | 33 | | `http://news.company.com/dir/other.html` | 失败 | 不同域名 ( news和store ) | 34 | 35 | ## 跨域数据存储访问 36 | 37 | ### localStorage 与 IndexedDB 38 | 39 | [localStorage](https://developer.mozilla.org/zh-CN/docs/Web/Guide/API/DOM/Storage) 和 [IndexedDB](https://developer.mozilla.org/zh-CN/docs/IndexedDB) 均遵循上述同源策略限制,它们不允许 JavaScript 对跨域数据进行读写操作。这限制了我们在不同子站点上共享数据的能力,如我们想在我们产品的两个站点见共享风格配置,用户切换了一个站点的风格(如导航为深色等)后,在同一浏览器中打开的另一个站点也保持同样的风格设置,依靠 localStorage 是做不到的,一般做法是存储在后端 Redis 等服务中,页面加载的时候读取下配置接口。 40 | 41 | ### Cookie 42 | 43 | [Cookie](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Cookies) 的作用域限制与 localStorage、IndexedDB 这些数据存储方案不同,它使用`Domain` 和 `Path` 来设置作用域。 44 | 45 | 因此我们可以使用 Cookie 来实现 localStorage 与 IndexedDB 章节中用户配置共享的例子,但需要注意,虽然我们可以用 Cookie 可以实现上述需求,但由于浏览器的每次请求都会携带符合条件的 Cookie 数据,这样无疑增大了带宽消耗,所以在实际项目中仍然建议配置信息存储在后端,由指定接口提供。 46 | 47 | 我们可以利用 Cookie 的 Domain 设置配合 Oauth 来实现指定子域名下所有站点的单点登录:`*.xiaosansiji.com` 是我们的一个泛域名解析,其下有 `a.xiaosansiji.com`、`b.xiaosansiji.com` 等多个站点,我们希望登录某个站点后,就可以默认登录所有 `xxx.xiaosansiji.com` 站点。 48 | 49 | 具体实现为:用户访问 `a.xiaosansiji.com` 站点时,跳转到单点登录服务器提供的统一登录页面,用户验证通过后重定向跳转回 `a.xiaosansiji.com` 主页面,在这次 HTTP 请求的 Response Header 中向浏览器中存储 Cookie 并设置 Domain 为 `xiaosansiji.com` : 50 | 51 | ```javascript 52 | Response Header 53 | HTTP/1.1 302 54 | Server: nginx/1.13.1 55 | Date: Wed, 04 Jul 2018 06:48:43 GMT 56 | Content-Length: 0 57 | Location: http://a.xiaosansiji.com/ 58 | Connection: keep-alive 59 | Set-Cookie: csid=D6ACED5C8AB99D5A3DB57594112AB00F;domain=xiaosansiji.com;path=/;HttpOnly 60 | Content-Language: zh-CN 61 | ``` 62 | 63 | 这样当我们在同一浏览器中新打开的一个 Tab 中访问 `b.xiaosansiji.com` 站点时,系统提示我们已经登录成功。 64 | 65 | 注意我们在 `Set-Cookie` 时使用了 `HttpOnly` 标记,这主要是从安全角度禁止 JavaScript 操作该 Cookie,详细内容参见 [《Web 安全》]()章节。 66 | 67 | ## 跨域 HTTP 访问 68 | 69 | ![cross-domain-error.png](./cross-domain-error.png) 70 | 71 | 在日常前端开发工作中,我们遇到的更多是上面这样的报错:我们从 `localhost:8000` 发起了一个 Ajax 请求到 `www.google.com.hk` 站点,然后我们没能拿到想要的数据,反而在 console 中提示了上图的错误。 72 | 73 | 这其实就是因为同源策略限制,我们的跨域请求失败了。需要注意其实我们的请求是已经发送到目标服务器了,对方接口也正常返回了数据,只是在返回到浏览器时被 block [^1]了(回想本篇开头的同源策略定义,它是**浏览器**的安全策略)。 74 | 75 | [^1]: 高版本的 Chrome 和 Firefox 等会在站点采用 HTTPS 的情况下直接阻止请求发出去,这时候后端其实不会接收到该请求。 76 | 77 | 我们常见的解决方案有三种: 78 | 79 | - JSONP :是把请求伪装成标签去请求。因为标签是浏览器自己发送请求,所以不受同源策略影响啊 80 | - 后端 Proxy:这个也很好理解,我把所有请求都发送到不跨域的代理服务器上,服务器上可是我们说的算,只要经过处理把数据返回给浏览器就好。 81 | - CORS:这是我们今天主要讲。因为解铃还须系铃人,既然是你限制的,那么你总得给我一个解决办法吧。浏览器给出的解决办法就是(CORS) 82 | 83 | ### JSONP 84 | 85 | > JSONP:JSON with Padding 86 | 87 | 我们在使用 jQuery 等封装的 Ajax 库时经常这样使用 JSONP: 88 | 89 | ```javascript 90 | $.Ajax({ 91 | type: "get", 92 | async: false, 93 | url: "http://demo.com/api/current?user=1", 94 | dataType: "jsonp", 95 | jsonp: "callback",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback) 96 | success: function(json){ 97 | alert(json); 98 | }, 99 | }); 100 | ``` 101 | 102 | 这让我们产生了一种错觉,仿佛 JSONP 也是 Ajax 的一种,毕竟我们正常发起请求时也只是将 `dataType` 改为 `json` 而已。 103 | 104 | 但 JSONP 其实跟 Ajax/Fetch 都没什么关系,它用一种比较 hack 的方式实现跨域 HTTP 接口交互:在同源策略章节我们已经说过,在页面中使用 `script` 标签加载 CDN 上的 JavaScript 资源文件是不受同源策略限制的。程序员们就想到如果我们请求的 JavaScript 文件是后端动态生成的,在浏览器端执行了这一段 JavaScript 代码后岂不是就拿到了后端接口的数据! 105 | 106 | 于是上述代码的底层实现其实是这样的: 107 | 108 | 浏览器端我们需要增加如下代码发起请求,并声明了请求成功后处理函数 109 | 110 | ```javascript 111 | var callback = function(data){ 112 | alert(data); 113 | }; 114 | var url = "http://demo.com/api/current?user=1"; 115 | var script = document.createElement('script'); 116 | script.setAttribute('src', url); 117 | document.getElementsByTagName('head')[0].appendChild(script); 118 | ``` 119 | 120 | 在服务器端我们需要把正常返回的数据转化为字符串,并用 callback 包裹 121 | 122 | ```javascript 123 | server.on('request', function(req, res) { 124 | var params = qs.parse(req.url.split('?')[1]); 125 | // jsonp返回设置 126 | res.writeHead(200, { 'Content-Type': 'text/javascript' }); 127 | res.write('callback' + '(' + JSON.stringify(params) + ')'); 128 | res.end(); 129 | }); 130 | ``` 131 | 132 | 这样页面上请求到后端数据后就可以直接调用 `callback` 方法进行后续数据展示处理了。 133 | 134 | 可以看到 JSONP 的底层实现跟 Ajax 的 XHR 完全不同,只是 jQuery 帮我们封装了这些操作而已。 135 | 136 | JSONP 方案可以运行在任何允许执行 JavaScript 脚本的浏览器上,兼容性较好,但也存在很多限制: 137 | 138 | - 需要后端同学的支持:正常返回的 JSON 数据需要处理一下,变成浏览器可以执行的脚本 139 | - 仅支持 GET 方法的请求:如代码示例中展示的,我们只能发起 GET 请求,且所有参数只能添加到 url 中 140 | - 对于错误的支持不好:不像 Ajax 和 Fetch 都有较好的错误处理接口,JSONP 失败了只会在控制台输出一句 error 而已 141 | 142 | 总的来说,我们在日常与后端接口交互中较少采用 JSONP 方案,在投放广告等领域用的比较多。 143 | 144 | ###后端 Proxy 145 | 146 | 这是我们日常开发中最常用的方案,具体来说就是让后端启一个代理服务,来代替直接由浏览器对其他域的接口发起请求。 147 | 148 | 如,我们将站点部署在 Nginx 上,有两个单独部署的后端接口地址(这在后端微服务应用中很常见)需要访问: 149 | 150 | ```nginx 151 | server { 152 | listen 80; 153 | server_name localhost; 154 | 155 | #反向代理地址为http://a.demo.com/api的后端接口,需要根据实际情况改为自己的地址 156 | location ^~ /api { 157 | proxy_pass http://a.demo.com; 158 | proxy_set_header X-Real-IP $remote_addr; 159 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 160 | proxy_set_header Host $http_host; 161 | } 162 | location ^~ /bpi { 163 | rewrite ^/bpi(.+) /api/$1 break; 164 | proxy_pass http://b.demo.com; 165 | proxy_set_header X-Real-IP $remote_addr; 166 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 167 | proxy_set_header Host $http_host; 168 | } 169 | ... 170 | } 171 | ``` 172 | 173 | 这样我们在浏览器上发起这两类请求时其实都可以请求到这个 Nginx 节点上,由 Nginx 根据 url 路径的不同(api/bpi)来分别请求两个站点的接口。 174 | 175 | 后端 Proxy 的方案唯一的缺点就是需要后端开发或者使用 Nginx/Apach 等配置代理,只能用于后端能够改造的前提下。 176 | 177 | ### CORS 178 | 179 | > CORS:cross-origin sharing 跨域资源共享 180 | 181 | 对于 Ajax 和 Fetch 来说,CORS 是现在最可靠的跨域解决方案,它本身已经加入 [W3C 规范](https://www.w3.org/TR/cors/) 。现在各主流浏览器都允许服务器端返回 HTTP 请求时增加相应 header 设置,以声明浏览器端发出的请求有权限做哪些操作。上节说过,同源策略会使得浏览器在服务端返回数据时阻塞该响应,而当我们在 Response header 中增加了相关 CORS 声明后,浏览器就可以放行该响应,让 JavaScript 继续后续的数据处理和展示工作。这相当于让服务器端为我们的请求“背书”,该服务器明确告知浏览器:我允许该站点跨域获取我的接口数据。 182 | 183 | 在 CORS 中的配置分为“简单请求”和“需预检的请求”两种。 184 | 185 | #### 简单请求 186 | 187 | 满足如下条件,视为“简单请求”: 188 | 189 | - 使用下列方法之一: 190 | 191 | - `GET` 192 | - `HEAD` 193 | - `POST` 194 | 195 | - 未设置下面列出之外的其他 header : 196 | 197 | - [`Accept`](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Accept) 198 | 199 | - [`Accept-Language`](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Accept-Language) 200 | 201 | - [`Content-Language`](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Content-Language) 202 | 203 | - [`Content-Type`](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Content-Type) 只能设置三种类型: 204 | 205 | - `text/plain` 206 | - `multipart/form-data` 207 | - `application/x-www-form-urlencoded` 208 | 209 | 还有如下几个不太常用 header 设置 210 | 211 | - [`DPR`](http://httpwg.org/http-extensions/client-hints.html) 212 | 213 | - [`Downlink`](http://httpwg.org/http-extensions/client-hints.html#downlink) 214 | 215 | - [`Save-Data`](http://httpwg.org/http-extensions/client-hints.html#save-data) 216 | 217 | - [`Viewport-Width`](http://httpwg.org/http-extensions/client-hints.html#viewport-width) 218 | 219 | - [`Width`](http://httpwg.org/http-extensions/client-hints.html#width) 220 | 221 | - 请求中的任意[`XMLHttpRequestUpload`](https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequestUpload) 对象均没有注册任何事件监听器;[`XMLHttpRequestUpload`](https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequestUpload) 对象可以使用 [`XMLHttpRequest.upload`](https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/upload) 属性访问。 222 | 223 | - 请求中没有使用 [`ReadableStream`](https://developer.mozilla.org/zh-CN/docs/Web/API/ReadableStream) 对象。 224 | 225 | 满足以上条件的“简单请求”,我们只需要要求服务器端在返回响应时提供 `Access-Control-Allow-Origin` 的 header 设置就可以了,在线例子可以查看[这里](http://arunranga.com/examples/access-control/simpleXSInvocation.html) 226 | 227 | ```http 228 | HTTP/1.1 200 OK 229 | Date: Thu, 05 Jul 2018 02:18:58 GMT 230 | Server: Apache 231 | Access-Control-Allow-Origin: http://arunranga.com 232 | Keep-Alive: timeout=2, max=100 233 | Connection: Keep-Alive 234 | Transfer-Encoding: chunked 235 | Content-Type: application/xml 236 | ``` 237 | 238 | 如上,我们在跨域的另一个服务器返回中设置了 `Access-Control-Allow-Origin: http://arunranga.com` ,即明确告知浏览器允许 `http://arunranga.com` 站点的请求获取本服务器的数据。 239 | 240 | 当然,有些提供天气/地理查询服务的网站可能会允许任何其他站点获取数据,则会设置 header 为 `Access-Control-Allow-Origin: *` 。 241 | 242 | 在有一种情况下,不允许设置 `Access-Control-Allow-Origin: *`:跨域请求的接口依赖 header 中的 Cookie 信息来做用户验证时,根据 CORS 规范,请求不会自动携带该域下的 Cookie,对于 Fetch 请求来说,我们需要设置 243 | 244 | ```javascript 245 | fetch(url, { 246 | credentials: 'include' 247 | }) 248 | ``` 249 | 250 | 以允许携带 Cookie,具体情况可参考 [`Request.credentials`](https://developer.mozilla.org/zh-CN/docs/Web/API/Request/credentials)。同时,我们只能设置`Access-Control-Allow-Origin: http://arunranga.com` ,即只能允许指定域的访问,而不能使用 `*` 允许来自所有域的访问。 251 | 252 | #### 需预检的请求 253 | 254 | 不满足“简单请求”条件的所有请求我们都视为“需预检的请求”,如 `PUT` 请求等。其特殊之处在于:我们不仅需要设置 `Access-Control-Allow-Origin`,还需要设置 `Access-Control-Allow-Methods` 等以允许这些请求。 255 | 256 | 在简单请求过程中,该跨域的请求与非跨域请求其实是一样的:都从浏览器端发送请求到了目标服务器,在浏览器接收到响应时再判断是否允许跨域处理。 257 | 258 | 而需预检的请求则不是这样:在发起的正式的 `PUT` 等请求前,浏览器会先使用 [`OPTIONS`](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Methods/OPTIONS) 方法发起一个预检请求,以询问服务器是否允许该请求,如果允许才会发送实际请求,可以查看这个在线[例子](http://arunranga.com/examples/access-control/preflightInvocation.html): 259 | 260 | ![option-request.png](option-request.png) 261 | 262 | 在这个例子中,我们发起了一个 `POST` 请求,但因为我们使用了非标准的的 header 设置,所以仍属于需预检的请求。这也是比较常见的做法,在 header 中加入某些我们自己定义头,如标识用户所属的组织等:`x-current-group: 'dev'`,相应的在 CORS 处理中我们需要在增加允许该 header 的设置:`Access-Control-Allow-Headers': 'x-current-group'` 。 263 | 264 | 当然如果我们每发起一个需预检的请求都要实际上发送两次 HTTP 请求(一个 OPTIONS 预请求,一个正式请求),对于服务器来说增大了访问压力,我们可以在 Response header 中设置 `'Access-Control-Max-Age': 600` 来让验证通过后的10分钟内不再发送预请求。 265 | 266 | #### 常见 header 设置 267 | 268 | 总结以上简单请求和需预检的请求使用场景,常用的 CORS Response header 设置有: 269 | 270 | - [`Access-Control-Allow-Origin`](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Access-Control-Allow-Origin): ` | *` 例,`http://arunranga.com` 271 | - [`Access-Control-Expose-Headers`](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Access-Control-Expose-Headers) : `[, ]*` 例,`x-current-group` 272 | - [`Access-Control-Allow-Methods`](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Access-Control-Allow-Methods) : `[, ]*` 例,`PUT, OPTIONS` 273 | - [`Access-Control-Allow-Credentials`](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials) : bool 设置为 `true` 时允许浏览器端携带 Cookie 等 Credentials 访问接口,这个除了服务端要设置外,浏览器请求的中也要设置,Ajax 是 `xhr.withCredentials = true;` Fetch 中是 `credentials: 'include'` 274 | - [`Access-Control-Max-Age`](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Access-Control-Max-Age) : 注意单位是秒 275 | 276 | ### 其他 CORS 用法 277 | 278 | 注意 CORS 其实不仅限于跨域接口的访问,HTML 5 规范中也对 CORS 提供了支持,比如我们在做前端全局异常采集时经常要求引入的 Scripts 做如下处理: 279 | 280 | ```javascript 281 | 282 | ``` 283 | 284 | 它允许我们可以获取该跨域脚本执行出错时的详细信息,否则我们就只能在监听 window.onerror 时得到这样的提示:`Script error.` 285 | 286 | 其他标签支持 CORS 的情况,请参看[这里](https://developer.mozilla.org/zh-CN/docs/Web/HTML/CORS_settings_attributes) 。 287 | 288 | ## 参考链接: 289 | 290 | - [浏览器跨域方法与基于Fetch的Web请求最佳实践](https://segmentfault.com/a/1190000006095018) 291 | - [浏览器的同源策略](https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy) 292 | - [HTTP cookies](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Cookies) 293 | - [JSONP 教程](http://www.runoob.com/json/json-jsonp.html) 294 | - [HTTP访问控制(CORS)](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS) 295 | 296 | 297 | 298 | -------------------------------------------------------------------------------- /http/cross-domain-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/http/cross-domain-error.png -------------------------------------------------------------------------------- /http/https.md: -------------------------------------------------------------------------------- 1 | # HTTPS 2 | 3 | [分分钟让你理解HTTPS](https://juejin.im/post/5ad6ad575188255c272273c4?utm_medium=fe&utm_source=weixinqun) -------------------------------------------------------------------------------- /http/index.md: -------------------------------------------------------------------------------- 1 | # HTTP 2 | 3 | 需要掌握的知识有: 4 | 5 | - URL :[什么是URL?](https://developer.mozilla.org/zh-CN/docs/Learn/Common_questions/What_is_a_URL) 6 | - 同源策略与跨域解决方案 [查看](https://github.com/xiaosansiji/cookbook-of-webdev/blob/master/http/cros-origin.md) 7 | - 缓存机制 [查看](https://github.com/xiaosansiji/cookbook-of-webdev/http/cache.md) 8 | 9 | 在此推荐两本书,《HTTP权威指南》与《图解HTTP》,权威指南这本书可以当作工具书来用,入门学习的话可以选择图解。 10 | 11 | [人生苦短,了解一下前端必须明白的http知识点]: https://juejin.im/post/5b34e6ba51882574d20bbdd4 12 | [一站到底 ---前端基础之网络]: https://juejin.im/post/5b3357556fb9a00e5a4b63df#heading-0 13 | [跟着动画来学习TCP三次握手和四次挥手]: https://juejin.im/post/5b29d2c4e51d4558b80b1d8c 14 | 15 | -------------------------------------------------------------------------------- /http/option-request.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/http/option-request.png -------------------------------------------------------------------------------- /interview/index.md: -------------------------------------------------------------------------------- 1 | # 面试 2 | 3 | - [前端面试集锦](https://github.com/paddingme/Front-end-Web-Development-Interview-Question) 4 | - [面试图谱:前端基础技术知识讲解](https://juejin.im/post/5b5567b25188256256696ee0) 5 | 6 | -------------------------------------------------------------------------------- /monitor/index.md: -------------------------------------------------------------------------------- 1 | # 前端监控 2 | 3 | - [把前端监控做到极致](https://zhuanlan.zhihu.com/p/32262716) 4 | 5 | -------------------------------------------------------------------------------- /performance-optimization/browser-render.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/performance-optimization/browser-render.png -------------------------------------------------------------------------------- /performance-optimization/flight-status.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/performance-optimization/flight-status.jpeg -------------------------------------------------------------------------------- /performance-optimization/google-performance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/performance-optimization/google-performance.png -------------------------------------------------------------------------------- /performance-optimization/image-20181109142635337.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/performance-optimization/image-20181109142635337.png -------------------------------------------------------------------------------- /performance-optimization/immutable.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/performance-optimization/immutable.gif -------------------------------------------------------------------------------- /performance-optimization/index.md: -------------------------------------------------------------------------------- 1 | # Web 站点性能优化 2 | 3 | - 优化什么 4 | - 通用优化方法 5 | - React 技术栈下的优化方法 6 | 7 | 8 | 9 | ## 优化什么? 10 | 11 | 从浏览器角度看待网页加载的过程: 12 | 13 | ![image-20181109142635337](https://github.com/xiaosansiji/cookbook-of-webdev/blob/master/performance-optimization/image-20181109142635337.png) 14 | 15 | 换个角度,从用户体验角度看待网页加载: 16 | 17 | ![image-20181109144732772](https://github.com/xiaosansiji/cookbook-of-webdev/blob/master/performance-optimization/google-performance.png) 18 | 19 | 由此我们可以得到一些常见性能指标:白屏时间、首次有效渲染时间、用户可交互时间、整页时间、DNS时间、CPU占用率、动画帧率。 20 | 21 | 当然这些指标并非同样重要,很多时候需要根据产品形态、用户需求等赋予权重(构建用户为中心的性能模型)。 22 | 23 | 至于怎么获取这些指标,需要一些监控的手段和工具(Lighthouse/主动监控等),可以参见之前分享的《手摸手,教你做一个前端监控系统》。 24 | 25 | ## 通用优化方法 26 | 27 | 推荐书单《高性能网站建设指南》、《[雅虎性能优化建议](https://developer.yahoo.com/performance/rules.html?guccounter=1)》 28 | 29 | ### 核心思想 30 | 31 | - 优化网络传输 32 | - 优化渲染性能 33 | - 减少内存泄露 34 | 35 | ### 优化网络传输 36 | 37 | #### 减少网络请求次数 38 | 39 | 浏览器针对同一域名的并行网络请求数是有限制的,根据浏览器厂家/版本或站点使用的 HTTP 协议版本的的不同限制数也不相同,大概在 2-8 个。 40 | 41 | 假如一个页面有120个静态资源(css、js、img),并且所有资源都在一个域名下,使用的浏览器最大网络并行请求资源数是6,如果所有请求时间都是一样的,每个文件加载需要500ms,则所有资源加载完成需要 120/6 * 0.5 = 10s 的时间。 42 | 43 | 为了减少同一域下网络请求数,我们可以采用如下几种方式: 44 | 45 | - 使用 Webpack、Gulp 等工具合并 JS/CSS 资源 46 | - Sprite 图 47 | - base 64 48 | - 使用 CDN 49 | 50 | ##### Sprite 图 51 | 52 | 将很多图片整合到一个图片文件中,利用 CSS 的 `background-position` 属性在渲染时定位到指定图片的位置。 53 | 54 | ![image-20181109150646552](https://github.com/xiaosansiji/cookbook-of-webdev/blob/master/performance-optimization/sprite-image.png) 55 | 56 | ##### base 64 57 | 58 | ```html 59 | 60 | ``` 61 | 62 | 有些页面上会有这样的 `img` 标签,对于比较小的图片可以通过这种方式内联到 HTML/CSS 文件中,减少一次网络请求。但是要慎重,跟 Sprite 图一样,base 64 处理后会带来维护困难,及不能有效利用缓存等问题(更改了一个图片的 base 64 编码意味着这个 HTML/CSS 文件就过期了)。 63 | 64 | ##### CDN 65 | 66 | 我们刚才说过浏览器对同一域名的并行网络请求数有限制的,而 CDN 的域名地址跟我们的业务主站域名一般时不一致的,这样我们在使用 CDN 时就可以加快并行请求资源的速度。 67 | 68 | #### 减小资源大小 69 | 70 | - Uglify 压缩代码 71 | - Tree-shaking 72 | - Gzip 73 | - 图片压缩 74 | - 使用 CSS 动画/Canvas 代替 GIF 75 | 76 | [^注意]: 在保证用户浏览体验的前提下,我们应该尽可能的减小站点请求资源大小,但这并不是说资源小了页面渲染性能一定会提升:由于一个 TCP 请求窗口在大部分情况下是 1480*10/1024 = 14.45K ,所以下载一个 15K 的文件和一个 28K 的文件从网络传输角度看时间几乎是一样的,因为这两个文件都需要两次往返传输。所以在优化静态资源大小时,14K 及它的倍数可以看作是一个个级别,级别之间的文件大小传输时间没有太大区别。当然尽量减小资源大小可以在移动场景下可以减少用户流量消耗,并非没有意义。 77 | 78 | ##### Tree-shaking 79 | 80 | 与 Uglify 压缩代码的方式不同,Tree-shaking 可以“剔除无用代码”。 81 | 82 | ##### Gzip 83 | 84 | 也是一种压缩传输方案:用压缩/解压需要的时间换取网络传输时间。 85 | 86 | ```http 87 | HTTP/1.1 200 OK 88 | Server: nginx/1.0.15 89 | Date: Sun, 26 Aug 2012 18:21:25 GMT 90 | Content-Type: text/css 91 | Last-Modified: Sun, 26 Aug 2012 15:17:07 GMT 92 | Connection: keep-alive 93 | Expires: Mon, 27 Aug 2012 06:21:25 GMT 94 | Cache-Control: max-age=43200 95 | Content-Encoding: gzip 96 | ``` 97 | 98 | `Content-Encoding: gzip` 标示开启了 Gzip,Nginx 中开启 Gzip 需要如下配置: 99 | 100 | ```nginx 101 | gzip on; 102 | gzip_min_length 1k; 103 | gzip_buffers 4 16k; 104 | #gzip_http_version 1.0; 105 | gzip_comp_level 2; 106 | gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png; 107 | gzip_vary off; 108 | gzip_disable "MSIE [1-6]\."; 109 | ``` 110 | 111 | ##### 图片压缩 112 | 113 | 我们通常根据 PC 还是移动站来选择不同格式或压缩比率的图片文件。 114 | 115 | 在此我们特别介绍下 WebP 图片格式: 116 | 117 | WebP 图片格式是由 Google 提出的一种新的网络图片格式,它提供有损和无损两种压缩方式处理原始图片: 118 | 119 | ![webp-vs-jpg](https://github.com/xiaosansiji/cookbook-of-webdev/blob/master/performance-optimization/webp-vs-jpg.png) 120 | 121 | ![webp-vs-png](https://github.com/xiaosansiji/cookbook-of-webdev/blob/master/performance-optimization/webp-vs-png.png) 122 | 123 | 可以看到无论有损还是无损,WebP 都有相当大的压缩优势,缺点是这种格式还未成为标准,兼容性存在问题。 124 | 125 | #### 提升传输效率 126 | 127 | - CDN 128 | - 有效利用缓存 129 | - HTTP/2 130 | 131 | CDN 可以在网络距离更近的节点上提供资源文件访问服务,而且使用比较大众的 CDN 服务商如七牛云等,有较大几率可以复用其他站点的资源。 132 | 133 | HTTP 缓存不详细说了,主要是利用 HTTP Header 中的 Etags、Expires 等做强缓存和协商缓存,不从服务器而是本机内存或磁盘上获取资源文件。 134 | 135 | 这里主要说下 HTTP/2 带来的性能上的提升: 136 | 137 | - 多路复用,降低了重复建立 TCP 连接的性能损耗,也可以减少 TCP 慢启动带来的性能影响 138 | - HPACK 压缩了 HTTP Header 体积 139 | - Server Push 可以预先将一些资源主动推送到浏览器端,而不是等需要加载的时候才向服务端请求 140 | 141 | 当然 HTTP/2 需要现升级协议到 HTTPS,切换上有一点成本。 142 | 143 | ### 优化渲染性能 144 | 145 | #### 提升首屏渲染性能 146 | 147 | - 尽早开始渲染 148 | - 按需加载/[Code-splitting](https://webpack.github.io/docs/code-splitting.html) 149 | - 懒加载与预加载 150 | - 骨架屏 151 | - SSR 152 | 153 | ##### 尽早开始渲染 154 | 155 | 能够尽早的拿到静态资源构建 render 树才能尽早开始页面渲染,除了优化网络传输等方法外,我们应当尽量减少 CSS/js 资源请求对渲染过程对影响。 156 | 157 | ![image-20181112161111566](https://github.com/xiaosansiji/cookbook-of-webdev/blob/master/performance-optimization/browser-render.png) 158 | 159 | 这里有必要指出:各浏览器内引擎一般会做优化,不是等整个 HTML 解析完才开始绘制,而是部分构建成功 render 树后就开始绘制,以求能更快的展现页面。 160 | 161 | - 不要让外部样式或脚本 block 渲染过程 162 | - 优先加载关键 CSS 163 | 164 | link 尽量在 head 中,script 尽量在 body 底部,js 执行并不会影响首屏时间,但可能截断首屏的内容。 165 | 166 | 收集开始渲染页面的第一个可见部分所需的所有 CSS(关键CSS)并将其内联添加到页面的 `` 中,从而减少网络往返。 由于在慢启动阶段交换包的大小有限,所以关键 CSS 的预算大约是 14 KB。或者通过 HTTP/2 的 Sever Push 在请求 HTML 文档时推送关键 CSS 文件到客户端浏览器,这样可以避免更改关键 CSS 后 HTML 文档缓存失效的问题。 167 | 168 | JS 文件可以尝试使用 `async` 和 `defer` : 169 | 170 | ```javascript 171 | 172 | ``` 173 | 174 | 这两个属性的标签都不会阻塞 DOM 树的更新,都是在页面渲染完成后执行,不同点在于: 175 | 176 | - async 属性的脚本会按加载完成后就执行 177 | - defer 当有多个 defer 属性的脚本时会按照标签出现的先后顺序执行 178 | 179 | ##### 懒加载与预加载 180 | 181 | 懒加载: 182 | 183 | 懒加载主要为了提升用户可交互时间这个指标,比如,我们可以优先加载用户可视范围内的图片资源,其他的等用户滚动到可视范围内了再进行加载: 184 | 185 | ```html 186 | 187 | ``` 188 | 189 | 预加载: 190 | 191 | 预加载其实会牺牲一部分首屏渲染性能,换来后续用户操作的流畅性,在访问站点时有些页面会加载一些本页面没有用到的图片等资源,这些资源会缓存在浏览器内存或硬盘上,这样在后续访问其他页面时就可以加快页面展现,利用 js、CSS 或 ajax 等都可以实现,如利用 js 构建 `Image` 对象: 192 | 193 | ```javascript 194 | var img = new Image(); 195 | img.src = "img/example.jpg"; 196 | ``` 197 | 198 | ##### 骨架屏 199 | 200 | ![skeleton-vs-loading](https://github.com/xiaosansiji/cookbook-of-webdev/blob/master/performance-optimization/skeleton-vs-loading.png) 201 | 202 | 之前大家为了优化用户体验一般会使用一些 Loading 动画,现在在移动端上更倾向于用骨架屏来提升用户体验。 203 | 204 | 实现逻辑为预先渲染出结构布局,数据加载完成后再填充数据显示,这样的好处在于不干扰用户操作,使用户对于加载的内容有一个大致的预期。 205 | 206 | 以下是 facebook 在弱网环境下的表现: 207 | 208 | ![skeleton-facebook](https://github.com/xiaosansiji/cookbook-of-webdev/blob/master/performance-optimization/skeleton-facebook.gif) 209 | 210 | ##### SSR 211 | 212 | 为了减少 SPA 类站点首屏需要浏览器端 JS 动态渲染带来的体验差异,我们可以使用后端渲染的方式首页。 213 | 214 | #### 减少 reflow 与 repaint 215 | 216 | - 减少 DOM 操作 217 | - 分层渲染与 GPU 加速 218 | - 消抖与节流 219 | 220 | 减少 DOM 操作的相关知识我们会在 React 部分详细说明,Virtual DOM/Diff 等很多设计都是围绕减少 DOM 操作来的。 221 | 222 | ##### 分层渲染与 GPU 加速 223 | 224 | ##### ![layers-firfox](https://github.com/xiaosansiji/cookbook-of-webdev/blob/master/performance-optimization/layers-firfox.png) 225 | 226 | 浏览器在得到 render tree 后渲染页面的大体过程如下: 227 | 228 | 1. 浏览器根据 Render 树确定多个独立的渲染层 229 | 2. CPU将每个层绘制进绘图中 230 | 3. 将位图作为纹理上传至GPU(显卡)绘制 231 | 4. GPU将所有的渲染层缓存(如果下次上传的渲染层没有发生变化,GPU就不需要对其进行重绘)并复合多个渲染层最终形成我们的图像 232 | 233 | (本章节参考[网站性能优化实战——从12.67s到1.06s的故事](https://juejin.im/post/5b0b7d74518825158e173a0c#heading-10)) 234 | 235 | 有没有可能将绘制带来的影响减少到最小? 236 | 237 | ```css 238 | transform: translateZ(0); 239 | ``` 240 | 241 | 通过使用 CSS transform 属性可以将 DOM 提取到单独的渲染层上,每次更改时影响的范围更小,更精确。 242 | 243 | 有没有可能减少在 CPU 内计算 DOM 位置,直接使用 GPU 绘制? 244 | 245 | CSS 动画就是 GPU 直接绘制,所以我们在实现某些动画效果时应当尽量使用 CSS 动画,而非 JS 动画。 246 | 247 | ##### 消抖与节流 248 | 249 | 如果一个事件频发的被触发: 250 | 251 | - 消抖 debounce:固定一次事件发生 n 毫秒后执行一次,n 毫秒内又触发1次事件,则重新延后 n 毫秒执行 252 | - 节流 throttle:预设一个延迟周期,在一个周期内只执行一次事件 253 | 254 | 举例:输入联想、滚动事件 255 | 256 | underscore、lodash 等工具库中都有消抖与节流函数。 257 | 258 | ### 减少内存泄漏 259 | 260 | 不同于 C/C++ 的手动管理内存,JS 有自动垃圾回收机制,但是在某些情况下也会出现内存不能及时回收的情况:如果我们使用了闭包后未将相关资源加以释放,或者引用了外链后未将其置空(比如给某DOM元素绑定了事件回调,后来却remove了该元素),及某些低版本浏览器下的循环引用等都会造成内存泄漏的情况发生。 261 | 262 | 针对 React 技术栈,在 shouldComponentUpdate 或者 componentWillUpdate 方法中调用 setState 会造成 setState 的循环调用,也会造成浏览器内存占用快速上升,最终使页面卡死。 263 | 264 | ## React 技术栈下的优化方法 265 | 266 | ### 默认的优化策略 267 | 268 | #### Virtual DOM 与 Diff 算法 269 | 270 | ![flight-status](https://github.com/xiaosansiji/cookbook-of-webdev/blob/master/performance-optimization/flight-status.jpeg) 271 | 272 | 假设我们有一个展示航班信息的列表,大约1000行,每5s自动刷新一次,如果我们每次拿到后台接口返回的列表数据后都暴力的直接 `targetDOM.innerHtml() ` 会有比较严重的性能问题。 273 | 274 | 在 jQuery 时代我们主要的解决思路是两点: 275 | 276 | 1. 不在 DOM 元素上直接进行添加或修改操作 277 | 2. 在内存中维护一个一维数组结构的对象当作一层缓存,每次拿到新的数据时与原先对象做比对,确定需要更新的元素后做精确更新,从而尽量复用 HTML 文档中原有的 DOM 结构 278 | 279 | 通过以上两种方式我们可以尽量减少 reflow、repaint 从而能够针对这一特定场景做出性能优化,但一方面这样做大大增加了我们实现业务的复杂度,另一方面思路二有缺陷,我们要面对的是 DOM 的树形结构,仅仅考虑一维数组结构并不具有通用性。 280 | 281 | React 提出的通用解决方案是: 282 | 283 | 1. Virtual DOM 用轻量的 JS 对象替代原生 DOM,隔离对原生 DOM 的直接操作 284 | 2. Diff 算法针对树形结构提供了优化过的比对策略 285 | 286 | ![tree-dom](https://github.com/xiaosansiji/cookbook-of-webdev/blob/master/performance-optimization/tree-dom.png) 287 | 288 | 传统树结构比对算法是循环递归的方式对节点进行遍历,其算法时间复杂度为 O(n^3),而 React 中实现的 Diff 算法的时间复杂度优化到了 O(n),具体实现思路为针对前端场景做了三个假设: 289 | 290 | 1. DOM 节点跨层级的移动操作特别少,可以忽略不计 291 | 2. 拥有相同类的两个组件会形成相似的树形结构,拥有不同类的两个组件会形成不同的树形结构 292 | 3. 同一层级的一组子节点,可以通过唯一 id 进行区分 293 | 294 | 针对这三个假设,React 在 Tree、Component、Element 三个粒度的对比上进行了特殊优化 295 | 296 | ![react-diff](https://github.com/xiaosansiji/cookbook-of-webdev/blob/master/performance-optimization/react-diff.png) 297 | 298 | #### setState 的特殊处理 299 | 300 | 浏览器对原生 DOM 的修改操作已经做了一层优化:临近的几次对某个 DOM 对象的操作会合并成一次 301 | 302 | 实际上在一些 MVVM 的框架甚至小程序等都提供类似 setState 这样的接口来批量/延迟更新数据。 303 | 304 | React 中的 setState 方法通过一个队列机制实现 state 更新,当调用 setState 的时候,会将需要更新的 state 合并之后放入状态队列,而不会立即更新。这与节流/消抖策略的思路一致:减少频繁发生的事件对页面渲染性能带来的影响。反应在组件更新上,每次在一个组件中调用 setState ,React 都会将这个组件标记为dirty。在一次事件循环结束后,React会搜索所有被标记为 dirty 的组件,并对它们进行重新渲染。 305 | 306 | ![setstate-dirty](https://github.com/xiaosansiji/cookbook-of-webdev/blob/master/performance-optimization/setstate-dirty.png) 307 | 308 | 当然我们有必要说明,setState 并不是完全异步的,只是说有一个队列机制。React 内部在处理 React 合成事件和生命周期函数中的 setState 调用时是延后处理更新操作,而对于原生事件和特殊的 setTimeout 中的 setState 调用则会立即更新。 309 | 310 | ```javascript 311 | class App extends React.Component { 312 | state = { val: 0 } 313 | 314 | componentDidMount() { 315 | this.setState({ val: this.state.val + 1 }) 316 | console.log(this.state.val) 317 | 318 | this.setState({ val: this.state.val + 1 }) 319 | console.log(this.state.val) 320 | 321 | setTimeout(_ => { 322 | this.setState({ val: this.state.val + 1 }) 323 | console.log(this.state.val); 324 | 325 | this.setState({ val: this.state.val + 1 }) 326 | console.log(this.state.val) 327 | }, 0) 328 | } 329 | 330 | render() { 331 | return
{this.state.val}
332 | } 333 | } 334 | // 0 335 | // 0 336 | // 2 337 | // 3 338 | ``` 339 | 340 | #### React 的事件机制 341 | 342 | setState 一节中我们提到了 React 合成事件与原生事件的概念,如果 DOM 上绑定了过多的事件处理函数,整个页面响应以及内存占用可能都会受到影响。React 为了避免这类 DOM 事件滥用,同时屏蔽底层不同浏览器之间的事件系统差异,实现了一个中间层——SyntheticEvent(合成事件)。 343 | 344 | 其实在原生 JS 中已经在利用事件冒泡机制来实现事件委托,从而提高页面性能; 345 | 346 | ```javascript 347 | var oUl = document.getElementById("ul1"); 348 |   oUl.onclick = function(ev){ 349 |     var ev = ev || window.event; 350 |     var target = ev.target || ev.srcElement; 351 |     if(target.nodeName.toLowerCase() == 'li'){ 352 |         alert(target.innerHTML); 353 |     } 354 |   } 355 | ``` 356 | 357 | jQuery 中提供 on 方法简化了声明事件委托的方式。 358 | 359 | 在 React 组件中声明事件时并没有直接绑定到对应的原生 DOM 上,而是绑定在 document 节点上,依靠 React 自己实现的一套事件冒泡机制进行事件委托,同时为了减少频繁创建合成事件对象,在内部维护了一个事件对象池。同时因为合成事件机制屏蔽各浏览器事件实现机制的差异,也提升了兼容性。 360 | 361 | #### React Fiber 362 | 363 | 我们先来看一下 React 16 以前完成一次组件渲染的过程是怎样的: 364 | 365 | 假设有如下结构的组件 366 | 367 | ![react-fiber-1](https://github.com/xiaosansiji/cookbook-of-webdev/blob/master/performance-optimization/react-fiber-1.png) 368 | 369 | 在 mount 阶段渲染过程中各组件声明周期调用顺序如下 370 | 371 | ![react-fiber-2](https://github.com/xiaosansiji/cookbook-of-webdev/blob/master/performance-optimization/react-fiber-2.png) 372 | 373 | 当我们的组件树很深时,这一次 mount 过程可能需要几百毫秒,而在这一过程中 React 的渲染会一直占用 js 引擎,这时如果有用户点击/输入等操作浏览器将不会处理,一直到渲染结束才会响应,从而造成页面“卡顿”的感觉。 374 | 375 | 为了解决这个问题,React 16 中引入了新的 Fiber 机制将 React 的渲染过程“分片”,在每个分片任务结束后检查是否有更高级的任务需要执行(如用户操作),若有责优先处理高级任务否则继续执行下一分片的任务。这样 React 渲染的过程就变成了下面这样: 376 | 377 | ![react-fiber-3](https://github.com/xiaosansiji/cookbook-of-webdev/blob/master/performance-optimization/react-fiber-3.jpg) 378 | 379 | ### 需要手动干预的方法 380 | 381 | #### 绑定事件处理函数 this 382 | 383 | ```javascript 384 | class Link extends React.Component { 385 | constructor(props) { 386 | super(props); 387 | this.state = { 388 | count: 0 389 | } 390 | } 391 | handleClick(e) { 392 | e.preventDefault(); 393 | this.setState({ count: this.state.count + 1 }) 394 | } 395 | render() { 396 | return Clicked me {this.state.count} times. 397 | } 398 | 399 | } 400 | 401 | ReactDOM.render(, document.querySelector("#root")) 402 | // Uncaught TypeError: Cannot read property 'setState' of undefined 403 | ``` 404 | 405 | 我们在开始使用 React 的时候经常出现上面的错误,这其实是因为调用事件处理函数时 this 指向发生了变化,详情参考[这里](https://github.com/mqyqingfeng/Blog/issues/7)。而为了避免这种情况我们有以下四种方式来绑定 this: 406 | 407 | **render 方法中使用 bind:** 408 | 409 | ```javascript 410 | 411 | Clicked me {this.state.count} times. 412 | 413 | ``` 414 | 415 | 但这种方式其实存在性能问题:JS 中 bind 方法会生成一个新的函数,对于 render 中的自组件来说 props 中的属性有更新,会造成一次额外的渲染。 416 | 417 | **render 方法中使用肩头函数:** 418 | 419 | ```javascript 420 | this.handleClick(e)}> 421 | Clicked me {this.state.count} times. 422 | 423 | ``` 424 | 425 | 与使用 bind 一样,每次都都会生成一个新函数对象,造成额外渲染。 426 | 427 | **在构造函数内提前绑定:** 428 | 429 | ```javascript 430 | class Link extends React.Component { 431 | constructor(props) { 432 | super(props); 433 | this.state = { 434 | count: 0 435 | } 436 | // 重点在这里 437 | this.handleClick = this.handleClick.bind(this); 438 | } 439 | handleClick(e) { 440 | e.preventDefault(); 441 | this.setState({ count: this.state.count + 1 }) 442 | } 443 | render() { 444 | return Clicked me {this.state.count} times. 445 | } 446 | } 447 | 448 | ReactDOM.render(, document.querySelector("#root")) 449 | ``` 450 | 451 | 这样提前确定 this 指向可以避免多次绑定带来的性能问题,但是函数的定义、使用和 this 绑定分在三个不同地方,降低了代码可读性。 452 | 453 | **在 class properties 中使用箭头函数:** 454 | 455 | ```javascript 456 | class Link extends React.Component { 457 | constructor(props) { 458 | super(props); 459 | this.state = { 460 | count: 0 461 | } 462 | } 463 | handleClick = e => { 464 | e.preventDefault(); 465 | this.setState({ count: this.state.count + 1 }) 466 | } 467 | render() { 468 | return Clicked me {this.state.count} times. 469 | } 470 | } 471 | ReactDOM.render(, document.querySelector("#root")) 472 | ``` 473 | 474 | 推荐做法,在 React 16 和 ES6 条件下可以使用。 475 | 476 | #### componentShouldUpdate 477 | 478 | ```javascript 479 | shouldComponentUpdate(nextProps, nextState) { 480 | if (this.props.color !== nextProps.color) { 481 | return true; 482 | } 483 | if (this.state.count !== nextState.count) { 484 | return true; 485 | } 486 | return false; 487 | } 488 | ``` 489 | 490 | #### PureComponent 491 | 492 | 声明组件时,使用 `React.PureComponent` 替代 `React.Component`,PureComponent 相当于在 shouldComponentUpdate 中做了一次“浅比较”。 493 | 494 | 对于简单的数据结构来说,浅比较已经足够,但是对于拥有复杂数据结构的对象来说就会有问题: 495 | 496 | ```javascript 497 | class WordAdder extends React.PureComponent { 498 | state = { 499 | user: ['aaa'] 500 | }; 501 | 502 | handleAddClick() { 503 | const users = this.state.users; 504 | users.push('bbb'); 505 | this.setState({ users }); 506 | } 507 | 508 | render() { 509 | ... 510 | } 511 | } 512 | ``` 513 | 514 | 这里当我们触发点击事件回调向用户数组中加入一个用户时,组件并没有如我们想象一样的进行一次新的渲染,因为我们直接在原来的数组对象上增加新用户数据,浅比较时会认为两者相等。 515 | 516 | 这里有必要简单介绍一下 JS 中的数据类型分为原始/值类型和对象/引用类型,它们的内存示意图如下: 517 | 518 | ![type-memory](https://github.com/xiaosansiji/cookbook-of-webdev/blob/master/performance-optimization/type-memory.png) 519 | 520 | 当修改原始类型的值时会改变在栈内存上对应的值,而改变对象类型时其栈上存储的地址却不会改变,造成浅比较想等,深比较不等的结果。 521 | 522 | 为了解决这个问题我们会要求针对复杂数据结构的对象的修改,不要直接在原对象上操作,而是生成一个新对象: 523 | 524 | ```javascript 525 | handleAddClick() { 526 | this.setState({ users: [ ...this.state.users, 'bbb' ] }); 527 | } 528 | ``` 529 | 530 | 利用 ES6 的扩展运算符,我们可以很便捷的生成一个全新的对象,这样在做浅比较时就得到不想等的结果,从而触发新的渲染。 531 | 532 | #### Immutable Data 533 | 534 | 新的问题来了,对拥有复杂结构的对象类型来说,每次新创建一个新对象会有一定的性能损耗,每次深比较性能开销也比较大,有没有什么方式既可以浅比较又能不完全创建新对象呢? 535 | 536 | Immutable 即是这样的解决方案:对 Immutable 对象的修改每次都会返回新的 Immutable 对象,与完全创建新对象不同的是在这一过程中数据结构是共享的。 537 | 538 | ![immutable](https://github.com/xiaosansiji/cookbook-of-webdev/blob/master/performance-optimization/immutable.gif) 539 | 540 | #### Fragments 541 | 542 | `React.Fragment` 也是 React 16 中新引入的一个特性,在 React 16 之前,因为 React 要求 render 函数返回的 elements 必须有根节点,所以在渲染数组类型的数据结构时我们经常会用一个空 div 包裹我们的返回内容: 543 | 544 | ```javascript 545 | function () { 546 | return ( 547 |
548 |
xxx
549 |
yyy
550 |
zzz
551 |
552 | ); 553 | } 554 | ``` 555 | 556 | 但这样增加了 HTML 文档上的 DOM 对象,对渲染性能也会造成影响。 557 | 558 | React 16 针对这种场景提出了两种解决方案: 559 | 560 | 可以使用`React.Fragment` 561 | 562 | ```javascript 563 | function () { 564 | return ( 565 | 566 |
xxx
567 |
yyy
568 |
zzz
569 |
570 | ); 571 | } 572 | ``` 573 | 574 | 当然 16 版本中也开始支持返回 elements 数组 575 | 576 | ```javascript 577 | function () { 578 | return [ 579 |
xxx
580 |
yyy
581 |
zzz
582 | ]; 583 | } 584 | ``` 585 | 586 | #### Context 传值 587 | 588 | ![](https://github.com/xiaosansiji/cookbook-of-webdev/upload/master/performance-optimization/react-context.png) 589 | 590 | 对站点全局语言切换或者像兄弟组件间消息通讯等场景,通过父子组件的 props 属性一层层向下传递不但非常繁琐,而且也会有多次渲染带来的性能问题。这时我们可以利用 React 提供的 Context 接口传递数据,实际上 react-redux/react-router 等都是通过 Context 传递数据: 591 | 592 | ```javascript 593 | function getRouter() { 594 | return ( 595 | 596 | 597 | } 600 | authority={['admin', 'user']} 601 | redirectPath="/user/login" 602 | /> 603 | 604 | 605 | ); 606 | } 607 | ``` 608 | 609 | 当然要注意的是在 React 16 中对 Context 接口进行了重构,在使用时注意兼容性修改。 610 | 611 | ## 参考链接 612 | 613 | [WebP 图片格式简介](https://www.cnblogs.com/upyun/p/7813319.html) 614 | 615 | [Vue项目骨架屏注入实践](https://www.jianshu.com/p/3da35af1e4c2) 616 | 617 | [网站性能优化实战——从12.67s到1.06s的故事](https://juejin.im/post/5b0b7d74518825158e173a0c#heading-7) 618 | 619 | [React 源码剖析系列 - 不可思议的 react diff](https://zhuanlan.zhihu.com/p/20346379?spm=a2c4e.11153940.blogcont586669.10.7aa21308YhIW92) 620 | 621 | [图解React Diff算法及新架构Fiber](https://yq.aliyun.com/articles/586669) 622 | 623 | [React 是怎样炼成的](https://segmentfault.com/a/1190000013365426) 624 | 625 | [React Fiber是什么](https://zhuanlan.zhihu.com/p/26027085) 626 | 627 | [深入理解React16之:(一).Fiber架构](https://www.jianshu.com/p/bf824722b496) 628 | 629 | [玩转 React(六)- 处理事件](https://segmentfault.com/a/1190000011877137) -------------------------------------------------------------------------------- /performance-optimization/layers-firfox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/performance-optimization/layers-firfox.png -------------------------------------------------------------------------------- /performance-optimization/react-context.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/performance-optimization/react-context.png -------------------------------------------------------------------------------- /performance-optimization/react-diff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/performance-optimization/react-diff.png -------------------------------------------------------------------------------- /performance-optimization/react-fiber-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/performance-optimization/react-fiber-1.png -------------------------------------------------------------------------------- /performance-optimization/react-fiber-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/performance-optimization/react-fiber-2.png -------------------------------------------------------------------------------- /performance-optimization/react-fiber-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/performance-optimization/react-fiber-3.jpg -------------------------------------------------------------------------------- /performance-optimization/setstate-dirty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/performance-optimization/setstate-dirty.png -------------------------------------------------------------------------------- /performance-optimization/skeleton-facebook.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/performance-optimization/skeleton-facebook.gif -------------------------------------------------------------------------------- /performance-optimization/skeleton-vs-loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/performance-optimization/skeleton-vs-loading.png -------------------------------------------------------------------------------- /performance-optimization/sprite-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/performance-optimization/sprite-image.png -------------------------------------------------------------------------------- /performance-optimization/tree-dom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/performance-optimization/tree-dom.png -------------------------------------------------------------------------------- /performance-optimization/type-memory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/performance-optimization/type-memory.png -------------------------------------------------------------------------------- /performance-optimization/webp-vs-jpg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/performance-optimization/webp-vs-jpg.png -------------------------------------------------------------------------------- /performance-optimization/webp-vs-png.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/performance-optimization/webp-vs-png.png -------------------------------------------------------------------------------- /security/index.md: -------------------------------------------------------------------------------- 1 | # 网络安全 2 | 3 | - [HTTP cookies](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Cookies) 4 | - [反击爬虫,前端工程师的脑洞可以有多大?](http://imweb.io/topic/595b7161d6ca6b4f0ac71f05) 5 | 6 | -------------------------------------------------------------------------------- /security/sso.md: -------------------------------------------------------------------------------- 1 | # 单点登录 2 | - [单点登录原理与简单实现](https://www.cnblogs.com/ywlaker/p/6113927.html) 3 | - [不务正业的前端之SSO(单点登录)实践](https://juejin.im/post/5b51f39b5188251a9f24a264) 4 | -------------------------------------------------------------------------------- /test/index.md: -------------------------------------------------------------------------------- 1 | # 测试 2 | 3 | 4 | 5 | [浅谈前端测试]: https://juejin.im/post/5b374d8c6fb9a00e2d480bfe 6 | 7 | -------------------------------------------------------------------------------- /the-way-of-coder/index.md: -------------------------------------------------------------------------------- 1 | # 技术人之路 2 | 3 | 4 | 5 | https://juejin.im/post/5b266c5ee51d45587d2dc67c 6 | 7 | [前端小白生存指南](https://zhuanlan.zhihu.com/p/28325416) -------------------------------------------------------------------------------- /tools/git.md: -------------------------------------------------------------------------------- 1 | # Git 2 | 3 | [您必须知道的 Git 分支开发规范](https://juejin.im/post/5b4328bbf265da0fa21a6820#heading-4) 4 | 5 | [git-flow 的工作流程](https://www.git-tower.com/learn/git/ebook/cn/command-line/advanced-topics/git-flow) 6 | 7 | [Git基本命令和GitFlow工作流](https://www.cnblogs.com/myqianlan/p/4195994.html) -------------------------------------------------------------------------------- /tools/index.md: -------------------------------------------------------------------------------- 1 | # 前端构建工具 2 | 3 | ## 参考链接 4 | 5 | - [前端构建工具,是干嘛的?](https://zhuanlan.zhihu.com/p/33692774) -------------------------------------------------------------------------------- /tools/webpack.md: -------------------------------------------------------------------------------- 1 | # Webpack 2 | 3 | [Webpack 4 配置最佳实践]: https://juejin.im/post/5b304f1f51882574c72f19b0#heading-8 4 | [搜罗一切webpack的好文章好工具]: https://github.com/webpack-china/awesome-webpack-cn 5 | [不聊webpack配置,来说说它的原理]: https://juejin.im/post/5b38d27451882574d87aa5d5 6 | [从0开始发布一个无依赖、高质量的npm]: https://juejin.im/post/5b39e039e51d45587b483123 7 | [浅谈性能优化之Tree Shaking]: https://scq000.github.io/2017/04/24/%E6%B5%85%E8%B0%88%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E4%B9%8BTree-Shaking/ 8 | 9 | -------------------------------------------------------------------------------- /web-dev-basic/CSS/BEM.md: -------------------------------------------------------------------------------- 1 | > **特别声明:**此篇文章由[David](http://www.codingserf.com/)根据《[Block, Element, Modifier](http://bem.info/method/definitions/)》进行翻译,整个译文带有我们自己的理解与思想,如果译得不好或不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:以及作者相关信息 2 | > 3 | > ——作者:[BEM官网](http://bem.info/) 4 | > 5 | > ——译者:[David](http://www.codingserf.com/) 6 | 7 | ## 什么是BEM? 8 | 9 | BEM代表块(Block),元素(Element),修饰符(Modifier)。这些术语的含意将在本文进一步阐述。 10 | 11 | 编程方法论中一个最常见的例子就是面向对象编程(OOP)。这一编程范例出现在许多语言中。在某种程度上,BEM和OOP是相似的。它是一种用代码和一系列模式来描述现实情况的方法,它只考虑程序实体而无所谓使用什么编程语言。 12 | 13 | 我们使用BEM的原则创建了一个前端开发技巧和工具的集合,这样我们就能快速构建一个网站,并且保证他们长久的可维护性。 14 | 15 | ## 统一数据域 16 | 17 | 想象一个如下图所示的普通网站。 18 | 19 | ![Sass调试](http://www.w3cplus.com/sites/default/files/styles/print_image/public/blogs/2013/Definitions-BEM-1.jpg) 20 | 21 | 就这样的一个网站来说,指出它是由哪些“块”构成的,对开发是很有帮助的。 22 | 23 | 例如,在上图中有`Head`,`Main Layout`和`Foot`块。`Head`由`Logo`,`Search`,`Auth`块和`Menu`组成。`MainLayout`包括一个`Page Title`和一个`Text`块。 24 | 25 | ![Sass调试](http://www.w3cplus.com/sites/default/files/styles/print_image/public/blogs/2013/Definitions-BEM-2.jpg) 26 | 27 | 对于团队沟通来说给页面的每一部分起个名字是很有用的。 28 | 29 | 这样的话一个项目经理就可以这么说: 30 | 31 | - 让`Head`再大点; 32 | - 创建一个`Head`中不带`Search`的页面。 33 | 34 | 一个HTML开发人员可以对一个JavaScript开发人员说: 35 | 36 | - 给`Auth`块来点动画,等等 37 | 38 | 现在让我们仔细了解一下什么是BEM: 39 | 40 | ## 块(Block) 41 | 42 | 一个块是一个独立的实体,就像应用的一块“积木”。一个块既可以是简单的也可以是复合的(包含其他块)。 43 | 44 | 例如搜索表单块: 45 | 46 | ![BEM的定义](http://www.w3cplus.com/sites/default/files/styles/print_image/public/blogs/2013/Definitions-BEM-3.jpg) 47 | 48 | ## 元素(Element) 49 | 50 | 一个元素是块的一部分,具有某种功能。元素是依赖上下文的:它们只有处于他们应该属于的块的上下文中时才是有意义的。 51 | 52 | 例如一个输入域和一个按钮是Search块的中的元素。 53 | 54 | ![BEM的定义](http://www.w3cplus.com/sites/default/files/styles/print_image/public/blogs/2013/Definitions-BEM-4.jpg) 55 | 56 | ## 描述页面和模板的意义 57 | 58 | 块和元素构成了页面的内容。它们不仅仅是被呈现在一个页面上,它们的排列顺序也同样重要。 59 | 60 | 块(或元素)彼此之间可能遵循着某种顺序。 61 | 62 | 例如,电商网站上的一个商品列表: 63 | 64 | ![BEM的定义](http://www.w3cplus.com/sites/default/files/styles/print_image/public/blogs/2013/Definitions-BEM-5.jpg) 65 | 66 | ……或者菜单项: 67 | 68 | ![BEM的定义](http://www.w3cplus.com/sites/default/files/styles/print_image/public/blogs/2013/Definitions-BEM-6.jpg) 69 | 70 | 块里也有可能再嵌套块。 71 | 72 | 例如,一个Head块会包含其他块: 73 | 74 | ![BEM的定义](http://www.w3cplus.com/sites/default/files/styles/print_image/public/blogs/2013/Definitions-BEM-7.jpg) 75 | 76 | 除了我们自己创建的一些块之外 ,我们还需要一种途径来描述页面上那些纯文本的布局。为此,每一个块和元素都应该有一个可以识别的关键字。 77 | 78 | 用来标识一个具体块的关键字其实就是这个块的名字(`block name`)。 79 | 80 | 例如,`menu`可以作为`Menu`块的关键字,`head`可以作为`Head`块的关键字。 81 | 82 | 用来标识一个元素的关键字也是这个元素的名字。 83 | 84 | 例如,菜单中的每个菜单项就是`menu`块的`item`元素。 85 | 86 | 一个项目中的块名必须是唯一的,明确指出它所描述的是哪个块。相同块的实例可以有相同的名字。在这种情况下一个块在一个页面上可以出现2(3,4,……)次。 87 | 88 | 一个块范围内的一种元素的名字也必须是唯一的。一种元素可以重复出现多次。 89 | 90 | 例如,菜单项: 91 | 92 | ![BEM的定义](http://www.w3cplus.com/sites/default/files/styles/print_image/public/blogs/2013/Definitions-BEM-8.jpg) 93 | 94 | 关键字应该按一定的顺序摆放。任何支持嵌套的数据格式(XML,JSON)都可以: 95 | 96 | ``` 97 | 98 | 99 | 100 | … 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | Search 109 | 110 | 111 | 112 | 113 | … 114 | 115 | 116 | 117 | 118 | 119 | ``` 120 | 121 | 在这个例子中,`b`和`e`两个命名空间用来区分块和元素两种节点。 122 | 123 | 同样可以用JSON格式来表示: 124 | 125 | ``` 126 | { 127 | block: 'page', 128 | content: { 129 | block: 'head', 130 | content: [ 131 | { block: 'menu', content: … }, 132 | { 133 | elem: 'column', 134 | content: { block: 'logo' } 135 | }, 136 | { 137 | elem: 'column', 138 | content: [ 139 | { 140 | block: 'search', 141 | content: [ 142 | { elem: 'input' }, 143 | { elem: 'button', content: 'Search' } 144 | ] 145 | } 146 | ] 147 | }, 148 | { 149 | elem: 'column', 150 | content: { 151 | block: 'auth', content: … 152 | } 153 | } 154 | ] 155 | } 156 | } 157 | 158 | ``` 159 | 160 | 上面的例子展示了一个块和元素相互嵌套的对象模型。这个结构中也可以包含任意多的自定义数据字段。 161 | 162 | 我们把这种结构叫BEM树(和DOM树类似)。 163 | 164 | 通过把模板转换(使用XSL或是JavaScript)应用到BEM树上生成最终的浏览器标签。 165 | 166 | 如果开发人员需要把一个块移动到页面的其他地方,他只需要改变一下BEM树就好了。模板会生成最终的视图。 167 | 168 | 你可以使用任何格式来描述BEM树,也可以使用任何模板引擎。 169 | 170 | 我们把JSON作为页面的描述格式。然后通过一个基于JS的模板引擎BEMHTML来把它转换为HTML。 171 | 172 | ## 块的独立性 173 | 174 | 随着一个项目的发展,我们常常会在页面中添加,删除,或者是移动一些块。例如,你可能想要互换`Logo`和`Auth`块,或者把`Menu`放到`Search`块下面。 175 | 176 | ![BEM的定义](http://www.w3cplus.com/sites/default/files/styles/print_image/public/blogs/2013/Definitions-BEM-9.jpg) 177 | 178 | 为了让这个过程更加简化,块必须是独立的。 179 | 180 | 一个独立的块可以放置在页面的任意位置 ,包括嵌套在其他块里。 181 | 182 | ## 独立的CSS 183 | 184 | 从CSS的角度来看: 185 | 186 | - 一个块(或者一个元素)必须有一个唯一的“名字”(一个CSS类)这样才能被CSS规则所作用。 187 | - HTML元素不能用作CSS选择器(如`.menu td`)因为这样的选择器并非是完全上下文无关的。 188 | - 避免使用级联(cascading)选择器(译注:如`.menu .item`)。 189 | 190 | ## 为独立的CSS类命名 191 | 192 | 下面是一种可能的CSS类命名方案: 193 | 194 | 一个块的CSS类名就是这个块的名字(block name)。 195 | 196 | ``` 197 | 200 | 201 | ``` 202 | 203 | 一个元素的CSS类名是一个块名和一个元素名的组合,它们中间用一些符号隔开。 204 | 205 | ``` 206 | 210 | 211 | ``` 212 | 213 | 在一个元素的CSS类名中包含一个块名是必要的,这样可以让级联最小化。 214 | 215 | 我们在长名称中使用连字符分隔单词(例如,`block-name`),使用两个下划线来分隔块名和元素名(`block-name__element-name`)。 216 | 217 | 例如: 218 | 219 | - `block-name--element-name` 220 | - `blockName-elementName` 221 | 222 | ## 独立的模板 223 | 224 | 对于模板引擎来说,块的独立性意味着: 225 | 226 | - 输入的数据要描述清楚块和元素:块(或元素)必须有个唯一的“名字”,在模板中告诉我们诸如“Menu应该放到这里”这样的事情。 227 | - 块可以出现在BEM树的任意地方。 228 | 229 | ## 独立块模板 230 | 231 | 当模板引擎在某个模板中遇到一个块的时候可以准确地把这个块转换成HTML。因此每个块都应该有自己的模板。 232 | 233 | 例如,下面就是一个XSL模板: 234 | 235 | ``` 236 | 237 | 240 | 241 | 242 | 243 | 246 | 247 | 248 | ``` 249 | 250 | 我们的产品正在逐渐弃用[XSLT](https://github.com/veged/xjst),我们用我们自己开发的基于JavaScript的模板引擎XJST来解析它。这个模板引擎吸收了所有XSLT的优点(我们是声明性编程的粉丝),并且在服务端和客户端都可以用JavaScript来实现。 251 | 252 | 现在我们用一种叫做[BEMHTML](http://clubs.ya.ru/bem/replies.xml?item_no=992)的特定领域语言来编写我们的模板,它是基于XJST的。BEMHTML的主要思想在Ya.Ru(在俄罗斯)的BEM俱乐部里提出。 253 | 254 | ## 块的重复 255 | 256 | 一个网站的第二个`Menu`块可能出现在`Foot`块里。或者,一个`Text`会变成两个,中间被一个广告分开。 257 | 258 | 即使一个块被开发成单独的单元,那么相同的块也可能在任何时候出现在这个页面上。 259 | 260 | 在CSS相关的术语中,这意味着: 261 | 262 | - 一定不能使用ID选择器:只有类选择器才能满足我们非唯一性的需求 263 | 264 | 在JavaScript里意味着: 265 | 266 | - 可以准确地检测到具有相同行为的块,因为它们有相同的CSS类名:使用CSS类选择器,可以拣选出所有相同名字的块,方便给它们定义动态行为 267 | 268 | ## 块修饰符 269 | 270 | 我们经常需要创建一个和已存在的块非常相似的块,只是外观或行为有些许改变。 271 | 272 | 比如说我们有一个这样的任务: 273 | 274 | 给Footer添加另外一个布局不一样的Menu。 275 | 276 | ![BEM的定义](http://www.w3cplus.com/sites/default/files/styles/print_image/public/blogs/2013/Definitions-BEM-10.jpg) 277 | 278 | 为了避免开发一个和现有的块只稍微有点不同的另一个块,我们引入修饰符(modifier)的概念。 279 | 280 | 修饰符作为一个块或是一个元素的一种属性,代表这个块或这个元素在外观或是行为上的改变。 281 | 282 | 一个修饰符有一个名字和一个值。多个修饰符可以同时使用。 283 | 284 | 例如:一个用来指定背景颜色的块修饰符 285 | 286 | ![BEM的定义](http://www.w3cplus.com/sites/default/files/styles/print_image/public/blogs/2013/Definitions-BEM-11.jpg) 287 | 288 | 例如:一个改变“当前”选项的元素修饰符 289 | 290 | ![BEM的定义](http://www.w3cplus.com/sites/default/files/styles/print_image/public/blogs/2013/Definitions-BEM-12.jpg) 291 | 292 | ## 从输入数据的角度来看修饰符 293 | 294 | 在BEM树里,修饰符是用来描述一个块或者是一个元素实体的属性的。 295 | 296 | 例如,它们可以作为XML的属性节点: 297 | 298 | ``` 299 | 300 | … 301 | 302 | 303 | ``` 304 | 305 | 用JSON也可以: 306 | 307 | ``` 308 | { 309 | block: 'menu', 310 | mods: [ 311 | { size: 'big' }, 312 | { type: 'buttons' } 313 | ] 314 | } 315 | 316 | ``` 317 | 318 | ## 从HTML/CSS的角度来看修饰符 319 | 320 | 对于一个块或者是一个元素来说修饰符是一个附加的CSS类。 321 | 322 | ``` 323 | 326 | 327 | ``` 328 | 329 | ``` 330 | .menu_size_big { 331 | // CSS code to specify height 332 | } 333 | .menu_type_buttons .menu__item { 334 | // CSS code to change item's look 335 | } 336 | 337 | ``` 338 | 339 | 我们用一个下划线来分隔块名(或元素名)和修饰符名,再用另一个下划线来分隔修饰符名和它对应的值。(译注:此处原文是俄文,大致就是这个意思)。 340 | 341 | ## 元素修饰符 342 | 343 | 元素修饰符以相同的方式实现。 344 | 345 | 当手写CSS代码的时候,为了编程的可访问性,始终使用分隔符非常重要。 346 | 347 | 例如,当前菜单项就可能被一个修饰符标记: 348 | 349 | ```html 350 | 351 | Index 352 | Products 353 | Contact 354 | 355 | 356 | ``` 357 | 358 | ```css 359 | { 360 | block: 'menu', 361 | content: [ 362 | { elem: 'item', content: 'Index' }, 363 | { 364 | elem: 'item', 365 | mods: { 'state' : 'current' }, 366 | content: 'Products' 367 | }, 368 | { elem: 'item', content: 'Contact' } 369 | ] 370 | } 371 | 372 | ``` 373 | 374 | ```css 375 | .menu__item_state_current 376 | { 377 | font-weight: bold; 378 | } 379 | 380 | ``` 381 | 382 | 上面的结构在HTML中代表如下: 383 | 384 | ```html 385 | 390 | 391 | ``` 392 | 393 | 或使菜单类独立于它布局的实现细节之外: 394 | 395 | ```html 396 | 409 | 410 | 411 | 426 | 427 | ``` 428 | 429 | ## 主题抽象 430 | 431 | 当许多人开发同一个项目他们应该在数据域上保持一致,在给块和元素命名的时候用上它。例如,一个标签云的块始终命名为tags。其中的每个元素就是一个tag。这种约定贯穿所有的语言:CSS,JavaScript,XSL等等。 432 | 433 | 从开发处理的角度来看:所有参与都基于同样的约定 。 434 | 435 | 从CSS角度开看:• 块和元素的CSS可以写成一种伪代码,然后根据命名约定编译成CSS。 436 | 437 | ```css 438 | .menu { 439 | __layout { 440 | display: inline; 441 | } 442 | __layout-item { 443 | display: inline-block; 444 | … 445 | } 446 | __item { 447 | _state_current { 448 | font-weight: bold; 449 | } 450 | } 451 | } 452 | 453 | ``` 454 | 455 | 相应JavaScript:可以使用专门的辅助库来替代使用类名直接选择DOM元素: 456 | 457 | ```javascript 458 | $('menu__item').click( … ); 459 | $('menu__item').addClass('menu__item_state_current'); 460 | $('menu').toggle('menu_size_big').toggle('menu_size_small'); 461 | 462 | ``` 463 | 464 | 块和元素的CSS类命名约定可能在一段时间内发生改变。如果命名约定改变了,只需要修改那些要访问块和元素,以及可能处理它们的修饰符的方法(function)。 465 | 466 | ``` 467 | block('menu').elem('item').click( … ); 468 | block('menu').elem('item').setMod('state', 'current'); 469 | block('menu').toggleMod('size', 'big', 'small'); 470 | 471 | ``` 472 | 473 | 上面的代码是抽象的,现实中我们使用bem-bl块中的i-bem块的JavaScript核心和[库](http://bem.github.com/bem-bl/sets/common-desktop/i-bem/i-bem.en.html)。 474 | 475 | ## 块的一致性 476 | 477 | 一个网站有一个带有某种动态行为的Button块。 478 | 479 | ![BEM的定义](http://www.w3cplus.com/sites/default/files/styles/print_image/public/blogs/2013/Definitions-BEM-13.jpg) 480 | 481 | 当鼠标滑过这样的块,它的外观就会改变。 482 | 483 | ![BEM的定义](http://www.w3cplus.com/sites/default/files/styles/print_image/public/blogs/2013/Definitions-BEM-14.jpg) 484 | 485 | 经理可能会要求在别的页面也使用相同的按钮。 486 | 487 | 一个块光有CSS实现还是不够的。复用一个块也意味着复用它的行为,也就是它所绑定的JavaScript。 488 | 489 | 所以一个块必须“知道”关于它自己的一切。为了实现一个块,要用我们所用到的所有技术来描述清楚它的外观和行为,我们把这叫多语言机制。 490 | 491 | 多语言描述一个块的时候涉及实现这个块的外观和功能的所有编程语言(技术)。 492 | 493 | 想让一个块像一个UI元素一样展现在页面上,我们需要用下面这些技术来实现它: 494 | 495 | - 模板(XSL,TT2,JavaScript等等),把块的声明转换成HTML代码 496 | - CSS,描述块的外观 497 | - JavaScript,如果块有动态行为的话 498 | - 图片 499 | - 文档 500 | 501 | 构成一个块的每样东西都可以作为一种块技术。 502 | 503 | ## 真实案例 504 | 505 | [Yandex](http://company.yandex.ru/)是一个大公司(在俄罗斯),它使用BEM方法论来开发它的服务。 506 | 507 | BEM方法论并不要求你使用某种框架。你也不必在你用到的所有页面技术中都使用BEM(但是那会是最有效的)。 508 | 509 | [Yandex的所有服务](http://www.yandex.ru/all)都在它们页面的CSS和JavaScript代码以及XSL模板中用到了BEM。例如: 510 | 511 | - [Yandex.Maps](http://maps.yandex.ru/?text=%D0%A0%D0%BE%D1%81%D1%81%D0%B8%D1%8F%2C%20%D0%9C%D0%BE%D1%81%D0%BA%D0%B2%D0%B0&sll=37.609218%2C55.753559&ll=37.609218%2C55.753563&spn=2.570801%2C0.884460&z=9&l=map) 512 | - [Yandex.Images](http://images.yandex.ru/yandsearch?text=Yandex+office&rpt=image):提供在因特网上搜索图片的服务。 513 | - [Yandex.Video](http://video.yandex.ru/#search?text=yac%202011):同时提供托管和搜索图片的服务。 514 | - [Yandex.Auto](http://auto.yandex.ru/) 515 | - [Turkish Yandex](http://www.yandex.com.tr/) 516 | 517 | 一此服务并没有使用XSL模板而是使用我们最新的模板技术来构建他们的页面。就是我们前面提到的BEMHTML模板引擎。以下就是这些服务: 518 | 519 | - [Yandex Search](http://yandex.ru/yandsearch?text=BEM+methodology+front-end&lr=213)或者[Yandex Search in English](http://yandex.com/yandsearch?text=%22What+is+BEM%3F%22+front-end&lr=213) 520 | - [Mobile Apps Search](http://apps.yandex.ru/):这个网站是呈现在智能手机上的。 521 | 522 | 也有一些其他公司在使用BEM。 523 | 524 | 比如,mail.us就在他们的部分服务中用到了BEM。他们页面上的一些块的CSS代码就是基于BEM的。他们也有自己的C++模板引擎,并根据BEM方法论来编写块模板。 525 | 526 | 更多的案例: 527 | 528 | - [Rambler.News](http://beta.news.rambler.ru/) 529 | - [HeadHunter](http://hh.ru/) 530 | - [TNK Racing Team](http://futurecolors.ru/tnkracing/) 531 | 532 | 你或许也对那些使用bem-bl块库的网站感兴趣: 533 | 534 | - [基于BEM的web表单JZ验证](http://form.dev.eot.su/) 535 | - [Mikhail Troshev vCard](http://mishanga.pro/):源代码托管在[GitHub](https://github.com/mishanga/bem-vcard)。 536 | 537 | ## 了解更多 538 | 539 | - [定义](http://bem.info/method/definitions/) 540 | - [文件系统组织](http://bem.info/method/filesystem/) 541 | - [历史](http://bem.info/method/history/) 542 | 543 | **译者手语:**整个翻译依照原文线路进行,并在翻译过程略加了个人对技术的理解。如果翻译有不对之处,还烦请同行朋友指点。谢谢! 544 | 545 | > #### 关于David 546 | > 547 | > 2009年开始接触前端开发,2011年组建创业团队——[[五维互动](http://www.fi5e-d.com/)],2012年团队被“收编”并更名[创影互动],遂只身来上海发展,现在就职于[FlipScript](http://www.flipscript.com.cn/)。欢迎交流共勉:[腾讯微博](http://t.qq.com/lybluesky0110)、[个人博客](http://www.codingserf.com/)。 548 | 549 | 如需转载烦请注明出处: 550 | 551 | 英文原文: 552 | 553 | 中文译文: 554 | 555 | 著作权归作者所有。 556 | 557 | 商业转载请联系作者获得授权,非商业转载请注明出处。 558 | 559 | 原文: 560 | 561 | https://www.w3cplus.com/css/bem-definitions.html 562 | 563 | -------------------------------------------------------------------------------- /web-dev-basic/CSS/CSS Modules.md: -------------------------------------------------------------------------------- 1 | # CSS Modules 2 | 3 | 在 CSS 章节,我们提到了传统 CSS 的局限性,在 React、Web Componet 逐渐流行的现在,我们越来越不能忍受样式污染带来工程问题:我们已经习惯了用“组件”来封装 UI 交互和逻辑,通过它们的组合来生成丰富多样的页面,但 CSS 由于其语言本身的特性,一直不能很好的适应组件化。 4 | 5 | ![css-history](css-history.png) 6 | 7 | 以上图片来自 [CSS Evolution: From CSS, SASS, BEM, CSS Modules to Styled Components](https://medium.com/@perezpriego7/css-evolution-from-css-sass-bem-css-modules-to-styled-components-d4c1da3a659b),本文内容也多有参考。 8 | 9 | > 前端能够看懂的笑话:“两个 CSS 参数走进一家酒吧( bar ),另一家酒吧的凳子就倒了。” 10 | 11 | 记得刚开始在项目里写 CSS 的时候,为了防止样式污染,我总想给 Class 选择器起一个“独一无二”的名字,为此绞尽脑汁但过段时间后还是免不了会出现页面样式覆盖的问题。在讨论所有这些旨在扩展 CSS 以服务前端组件化开发的解决方案之前,我们有必要说下 BEM。 12 | 13 | ## BEM 14 | 15 | > 唯一性是可重用的前提:你封装的组件在这个页面显示是正常的,我在别的页面引入了这个组件,由于本页面与组件内样式冲突,导致显示效果与预期不符,那我们可以说这个组件不可重用。 16 | 17 | 俄罗斯公司 Yandex 受困于长期迭代大型站点,CSS 很难维护的问题,总结他们的经验,提出了一套规范和相应的工具,当然现在我们觉得其中依然有意义的是其中的命名规范。 18 | 19 | 详细内容可以看 《[Block, Element, Modifier](http://bem.info/method/definitions/)》,或者看这篇[译文](BEM.md) 20 | 21 | 简单来说,BEM 提供了更容易理解的语义化 CSS 选择器命名规范,结合 Web Componet 组件化封装,我们可以将样式污染出现的概率降到很低,同时不会增加手工维护的工作量。 22 | 23 | ## CSS Modules 24 | 25 | BEM 帮我们规范了 CSS 命名,但在 React 技术栈的项目中,我们更常用 CSS Modules 等工具帮我们自动化的完成封装工作,比如在项目中我们经常这样完成组件封装: 26 | 27 | ```css 28 | .title { 29 | color: red; 30 | } 31 | ``` 32 | 33 | 34 | 35 | ```javascript 36 | import styles from './index.css'; 37 | function H1() => (
haha
) 38 | ``` 39 | 40 | 编译结束后,浏览器里看到的 HTML 内容变为: 41 | 42 | ```html 43 |
44 | haha 45 |
46 | ``` 47 | 48 | 当然 CSS 文件中的类名也会变成: 49 | 50 | ```css 51 | .title___NcS6x { 52 | color: red; 53 | } 54 | ``` 55 | 56 | 57 | 58 | ## 参考链接 59 | 60 | - [BEM 官网](http://getbem.com/) 61 | - [CSS Evolution: From CSS, SASS, BEM, CSS Modules to Styled Components](https://medium.com/@perezpriego7/css-evolution-from-css-sass-bem-css-modules-to-styled-components-d4c1da3a659b) 62 | - [CSS Modules 用法教程 - 阮一峰](http://www.ruanyifeng.com/blog/2016/06/css_modules.html) 63 | - [CSS Modules](https://github.com/css-modules/css-modules) 64 | 65 | 66 | -------------------------------------------------------------------------------- /web-dev-basic/CSS/css-history.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaosansiji/cookbook-of-webdev/97bb34978ad012d98506fb687784b827d8186d23/web-dev-basic/CSS/css-history.png -------------------------------------------------------------------------------- /web-dev-basic/CSS/index.md: -------------------------------------------------------------------------------- 1 | # CSS 2 | 3 | > 层叠样式表 Cascading Style Sheets 4 | 5 | CSS 按照 W3C 规范被分为CSS1 现已废弃, CSS2.1 是推荐标准, [CSS3](https://developer.mozilla.org/zh-CN/docs/CSS/CSS3) 分成多个小模块且正在标准化中。 6 | 7 | 若站点不需要兼容低版本 IE,则 CSS2.1 和 CSS3 都需要特别掌握。(我觉得所有还在使用 IE8 甚至 IE6 的用户应该每人给前端开发工程师1块钱,真的太恶心了。。) 8 | 9 | CSS 在 web 前端开发“三剑客”(HTML、CSS、JavaScript)中的精通难度应该是最容易被忽视的,如果你觉得自己 CSS 掌握的已经很好了,欢迎来[这里](https://github.com/you-dont-need/You-Dont-Need-JavaScript)打脸。 10 | 11 | 推荐阅读的书籍是《CSS权威指南》和《图解CSS3:核心技术与案例实践》,分别从 CSS2.1 和 CSS3 两个版本讲解了 CSS 的知识。 12 | 13 | CSS 需要掌握的基本知识有: 14 | 15 | **常见 block/inline/inline-block 元素** 16 | 17 | **样式优先级** 18 | 19 | **CSS 盒模型** 20 | 21 | **常见 CSS 选择器** 22 | 23 | **CSS3 变换与动画** 24 | 25 | **浮动布局** 26 | 27 | **PSD切图,蓝湖等在线工具使用** 28 | 29 | 最后一条不属于 CSS 本身的知识,但快速准确的实现 UI 同事提供的设计稿是前端必备的一项技能。 30 | 31 | 在工程实践中,因为 CSS 本身存在全局样式污染、~~无法使用变量共享配置等问题~~ [^1],业界提出了 Less、Sass、CSS in JS 等技术 32 | 33 | [^1]: 现在包括 Edge 等在内的现代浏览器都已经支持CSS 变量了,详情参看阮一峰老师的[博客](http://www.ruanyifeng.com/blog/2017/05/css-variables.html) 。但这并不意味着 Sass 等就没有存在的意义了,它们提供了很多其他高级的语法特性以弥补现有 CSS 规范的不足。 34 | 35 | CSS 其实是一种容易写,却难维护的语言,其维护成本很大程度上来自于它没有完善的模块系统,导致我们的代码无法有效的组织和管理,为了解决这些问题我们在工程实践上经常采用如下方案: 36 | 37 | ## 预处理器和后处理器 38 | 39 | ## CSS Modules 40 | 41 | [查看](https://github.com/xiaosansiji/cookbook-of-webdev/blob/master/web-dev-basic/CSS/CSS%20Modules.md) 42 | 43 | ## ClassNames 44 | 45 | ## CSS in JS 46 | 47 | ## styled-components 48 | 49 | ## 参考链接 50 | 51 | - [MDN CSS:层叠样式表](https://developer.mozilla.org/zh-CN/docs/Web/CSS) 52 | - [菜鸟 CSS3 教程](http://www.runoob.com/css3/css3-tutorial.html) 53 | - [React拾遗:从10种现在流行的 CSS 解决方案谈谈我的最爱 (上)](https://juejin.im/post/5b39e63ae51d4562aa017c81) 54 | 55 | 56 | -------------------------------------------------------------------------------- /web-dev-basic/HTML.md: -------------------------------------------------------------------------------- 1 | # HTML 2 | 3 | > 超文本标记语言 HyperText Markup Language 4 | 5 | 我们使用 HTML 来建立网页的“骨架/内容”,说实话 HTML 并不能算一种计算机编程语言[^1],但是一个写不好 HTML 的人一定不算前端/web 开发者。 6 | 7 | [^1]: HTML 不具备图灵完备性,当然有人认为 HTML + CSS 是图灵完备的,比如[这篇](https://lemire.me/blog/2011/03/08/breaking-news-htmlcss-is-turing-complete/) 8 | 9 | 我们现在讨论的 HTML 概念基本上可以替换为 HTML5 ,之前曾经出现过 XHTML 等标准现在已经不再流行了。学习 HTML 的资料网上汗牛充栋,各位同学可以根据自己需要自己学习,本节最下方也会给出几个学习站点链接,无论遵循哪一份资料,都应该掌握 HTML5 的基本特性: 10 | 11 | **语义特性(Semantic)** 12 | 13 | HTML5赋予网页更好的意义和结构。更加丰富的标签将随着对RDFa的,微数据与微格式等方面的支持,构建对程序、对用户都更有价值的数据驱动的Web。 14 | 15 | **本地存储特性(OFFLINE & STORAGE)** 16 | 17 | 基于HTML5开发的网页APP拥有更短的启动时间,更快的联网速度,这些全得益于HTML5 APP Cache,以及本地存储功能。Indexed DB(html5本地存储最重要的技术之一)和API说明文档。 18 | 19 | **设备兼容特性 (DEVICE ACCESS)** 20 | 21 | 从Geolocation功能的API文档公开以来,HTML5为网页应用开发者们提供了更多功能上的优化选择,带来了更多体验功能的优势。HTML5提供了前所未有的数据与应用接入开放接口。使外部应用可以直接与浏览器内部的数据直接相连,例如视频影音可直接与microphones及摄像头相联。 22 | 23 | **连接特性(CONNECTIVITY)** 24 | 25 | 更有效的连接工作效率,使得基于页面的实时聊天,更快速的网页游戏体验,更优化的在线交流得到了实现。HTML5拥有更有效的服务器推送技术,Server-Sent Event和WebSockets就是其中的两个特性,这两个特性能够帮助我们实现服务器将数据“推送”到客户端的功能。 26 | 27 | **网页多媒体特性(Class: MULTIMEDIA)** 28 | 29 | 支持网页端的Audio、Video等多媒体功能, 与网站自带的APPS,摄像头,影音功能相得益彰。 30 | 31 | **三维、图形及特效特性(Class: 3D, Graphics & Effects)** 32 | 33 | 基于SVG、Canvas、WebGL及CSS3的3D功能,用户会惊叹于在浏览器中,所呈现的惊人视觉效果。 34 | 35 | **性能与集成特性(Class: Performance & Integration)** 36 | 37 | 没有用户会永远等待你的Loading——HTML5会通过XMLHttpRequest2等技术,解决以前的跨域等问题,帮助您的Web应用和网站在多样化的环境中更快速的工作。 38 | 39 | **CSS3特性(Class: CSS3)** 40 | 41 | 在不牺牲性能和语义结构的前提下,CSS3中提供了更多的风格和更强的效果。此外,较之以前的Web排版,Web的开放字体格式(WOFF)也提供了更高的灵活性和控制性。 42 | 43 | ## 学习参考 44 | 45 | - [MDN web docs/HTML](https://developer.mozilla.org/zh-CN/docs/Web/HTML) 46 | - [菜鸟 HTML5 在线学习](http://www.runoob.com/html/html5-intro.html) 47 | - [W3shool HTML5 参考手册](http://www.w3school.com.cn/html5/html5_reference.asp) -------------------------------------------------------------------------------- /web-dev-basic/JavaScript/es6.md: -------------------------------------------------------------------------------- 1 | # ES6 2 | 先了解下在 ES5 中怎么实现“类”:[优雅的类写法](https://juejin.im/post/5b50c8b76fb9a04fd3439215) 3 | -------------------------------------------------------------------------------- /web-dev-basic/JavaScript/event.md: -------------------------------------------------------------------------------- 1 | # 事件处理 2 | 3 | ## 参考链接 4 | 5 | - [node基础面试事件环?微任务、宏任务?一篇带你飞](https://juejin.im/post/5b35cdfa51882574c020d685) 6 | - [从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理](https://juejin.im/post/5a6547d0f265da3e283a1df7?utm_medium=fe&utm_source=weixinqun) 7 | 8 | 9 | -------------------------------------------------------------------------------- /web-dev-basic/JavaScript/event.md : -------------------------------------------------------------------------------- 1 | # JavaScript 中的事件处理 2 | 3 | -------------------------------------------------------------------------------- /web-dev-basic/JavaScript/index.md: -------------------------------------------------------------------------------- 1 | # JavaScript 2 | 3 | > 不会 JavaScript 可以做好前端么? 4 | 5 | 这个问题可以这么来看,据说在腾讯等产业线巨长、部门众多的互联网公司里,前端是会划分成前端重构/前端开发/Node开发等不同岗位的,其中前端重构主要负责将设计图转化为页面及性能优化等,技能偏设计和 CSS + HTML,确实不太需要特别高深的 JavaScript 技能。但是在业界大多数的公司里是不会有这么详细的划分的,而且腾讯的这些前端重构岗的大牛们也必定都精通 JavaScript 的知识,所以大家还是老老实实把基础打牢吧~ 6 | 7 | JavaScript 的使用者常常处于这样的状态:将将好掌握了一点关于这门语言使用的技巧就不再继续学习,而热衷于讨论各类新奇框架/库的使用,毕竟大部分前端产品开发中掌握这些也就可以完成工作了。这样一看,后端开发者认为前端开发技术水平低的鄙视链也不是没有道理。为了替“前端开发工程师”正名,更重要的是为了能时刻把握层出不穷的框架的本质,不至于换了框架就完全不能开发出可用的产品,我们必须掌握关于 JavaScript 的以下基本知识: 8 | 9 | ## JavaScript 语言基础 10 | 11 | - 语法 12 | - JavaScript 中的面向对象编程、原型继承 13 | - 作用域与闭包 14 | - this 指向 15 | - 事件处理模型 16 | - BOM 与 DOM 操作 17 | - 异步处理机制 18 | 19 | 以上大部分内容可以在 JavaScript 相关教程中学习到,关于事件处理和异步处理的章节我会稍后补充章节专门说明。 20 | 21 | 在此特别推荐 [**You-Dont-Know-JS**](https://github.com/getify/You-Dont-Know-JS) 一书,它尽量简单、易懂的解释上述大部分问题,并且完全开源,中文版可以在各书城搜索《你不知道的javascript》购买。 22 | 23 | 与很多后端语言不同,除了 JavaScript 的语法本身以外,对 DOM 及 BOM 操作的知识也很重要,请大家不要忽略。 24 | 25 | 在此推荐《JavaScript 语言精粹》一书:JavaScript 是一门出色的语言,如果你按照正确的方式去使用它的话! 26 | 27 | 在下面 ES6 章节我会简要提到这门语言存在的一些问题,新的语言标准和工具协助解决了一部分问题,但知道它在实现上有哪些坑确实可以有效提高我们的编程水平,毕竟那些工具也只是按照最佳实践自动化处理了那些坑而已。 28 | 29 | 《JavaScript高级程序设计》是 JavaScript 学习的“红宝书”,但是由于这本书内容太多,建议大家在阅读时尽量先一次速读本书,然后阅读《JavaScript 语言精粹》,在日后的工作和学习中可以不时回来针对性的阅读具体章节,以加深理解。 30 | 31 | ## ES6 32 | 33 | > ECMAScript 6 (或 ECMAScript 2015+) 34 | 35 | ES6 并不是一种语言,相反它是语言的标准和规范,包括现在 JavaScript、TypeScript 等都是这个标准一种实现。ES6 和 ES2015+ 说的都是同一个事儿,ES6 就是在 2015 年发布的,在那之后每年 6 月份滚动发布的版本名称确定为 `ECMAScript + 当年月份`,所以我们一般会用 ES6 代指 ES2015 及之后几年发布的标准,当然也有人用 ES7/8 特别指称近期发布的一些版本。 36 | 37 | 在 ES6 标准发布之前,我们使用的 JavaScript 多是 ECMAScript 4.0 - ECMAscript 5.1 标准的实现,因为各厂商的浏览器版本对标准的实现都有差异,在那时直接用 JavaScript 实现我们的前端逻辑面临着很严峻的兼容风险,jQuery 正是在这一时代快速流行起来:jQuery 屏蔽了部分浏览器兼容性问题,为我们操纵 DOM 等提供了同一的接口。但是由于 ECMAScript 本身也存在很多问题,导致在使用 JavaScript 时我们经常要用很多特殊的写法或工具来避免这些问题,比如 var 变量没有块级作用域等,更多可参见这里:[10个JavaScript常见BUG及修复方法](https://blog.fundebug.com/2017/11/15/top_10_bugs_and_fixing_method/) 。 38 | 39 | ES6 延期了多次才正式发布,在这之间社区也提出了其他对下一代标准的实现,比如 Ruby 社区提出的 CoffeeScript 等,但现在来看 CoffeeScript 等已经用的不太多了,ES6 和 TypeScript 成为了业界主流。 40 | 41 | 在此推荐阮一峰老师的[《ECMAScript 6 入门》](http://es6.ruanyifeng.com/),这也是我的 ES6 入门教材。 42 | 43 | TypeScript 是微软贡献的 ECMAScript 实现语言,我们一般认为相比 ES6 它对大型前端项目能带来更好的可维护性[^1],我现在还没有在大型项目中实践 TypeScript ,只有一些个人的实验性质的小项目中有使用,后续我会再增加 TypeScript 的相关章节。 44 | 45 | [^1]: 众所周知,JavaScript 是一门动态类型语言,足够灵活,但这对于一个大型项目来说增加了运行时的不可预知性。TypeScript 提供的类型系统,可以在编译阶段就发现这些类型定义和使用的问题,同时语言层面增加的接口、泛型等特性,可以帮我们更好的以面向对象的编程范式完成代码的抽象和复用。 46 | 47 | ## 模块机制 48 | 长久以来在 JS 的世界里“模块”这个词常常意味着黑科技,ES6 之前 JavaScript 从语言层面并不不能很好支持我们以模块化的方式构建代码,为了更好的理解 JS 里的模块,我特意梳理了下前端发展历史中出现的那些“模块化”方案,请参看这一[章节](https://github.com/xiaosansiji/cookbook-of-webdev/blob/master/web-dev-basic/JavaScript/module.md)。 49 | -------------------------------------------------------------------------------- /web-dev-basic/JavaScript/memory-leak.md: -------------------------------------------------------------------------------- 1 | # JavaScript 内存泄漏处理 2 | 3 | ## v8 引擎的牢记回收机制 4 | 5 | [javascript 垃圾回收算法了解一下](https://juejin.im/post/5b1f7e62e51d45068a6cb98f) 6 | 7 | ## 内存泄漏处理 8 | 9 | [JavaScript 内存泄漏教程](http://www.ruanyifeng.com/blog/2017/04/memory-leak.html) -------------------------------------------------------------------------------- /web-dev-basic/JavaScript/module.md: -------------------------------------------------------------------------------- 1 | # JavaScript 模块机制 2 | 3 | ## 为什么需要模块机制 4 | 5 | - **提升可维护性**:“意大利面条”式的杂糅在一起的代码是很难读懂的,经过合理拆分的低耦合、高内聚模块是构建大型应用的基础。 6 | - **独立命名空间** :建议结合《你不知道的 JavaScript》作用域相关章节看,在模块外不能改变内部未开放的状态。 7 | - **方便复用** :借助于独立命名空间特性,我们可以放心的复用模块提供的功能,而不需要担心引入位置同名变量覆盖等问题。 8 | 9 | 在模块机制大规模应用前,我们经常使用 IIFE(立即执行函数表达式)来达到上述目的,如在 jQuery 大行其道的时代我们经常使用 IIFE 来封装我们自己的模块。以下例子来自《你不知道的 JavaScript》函数作用域章节: 10 | 11 | ```javascript 12 | var a = 2; 13 | 14 | (function IIFE( global ) { 15 | 16 | var a = 3; 17 | console.log( a ); // 3 18 | console.log( global.a ); // 2 19 | 20 | })( window ); 21 | 22 | console.log( a ); // 2 23 | ``` 24 | 25 | 大家可以自行验证如果不用 IIFE 方式处理,仅依靠 JavaScript 的函数作用域[^1]的代码执行结果会怎样。 26 | 27 | [^1]: ES6 之前的规范中主要提供了函数作用域,只有 `with`、`try/catch` 这样的不常用用法中才有块级作用域,不过 ES6 中增加了 `let` 、 `const` 关键字来提供块级作用域。 28 | 29 | IIFE 只能解决命名空间污染问题,它的缺点除了要手动写这样怪异的代码外,主要是没有提供一个明确的模块加载解决方案。以前我们主要依赖于浏览器中 `