├── README.md └── chapter ├── build.md ├── directory.md ├── flow-spec.md ├── mock.md └── technology-stack.md /README.md: -------------------------------------------------------------------------------- 1 | # 前端工程指导 2 | 3 | 本书会展示前端工程从0到100的过程,并提供实现指导。各个团队负责人根据自己团队情况进行实现。并让项目开发人员阅读本项目,便于理解并遵守工程规范。 4 | 5 | > 如果你要实现适合自己团队的前端工程,请务必详细阅读每一个章节,和每一个章节中链接到的其他页面。 6 | 7 | ## 章节 8 | 9 | 1. [文件目录](./chapter/directory.md) 10 | 2. [构建系统](./chapter/build.md) 11 | 3. [技术选型](./chapter/technology-stack.md) 12 | 4. ~[数据模拟](./chapter/mock.md)~ 13 | 5. [流程规范](./chapter/flow-spec.md) 14 | 6. ~[通用代码](./chapter/base-code.md)~ 15 | 7. ~[组件生态](./chapter/components.md)~ 16 | -------------------------------------------------------------------------------- /chapter/build.md: -------------------------------------------------------------------------------- 1 | # 构建系统 2 | 3 | 上一章:[文件目录](./directory.md) 4 | 5 | --- 6 | 7 | ## 为什么需要构建系统 8 | 9 | 在上一章[文件目录](./directory.md)中的文件结构,存在一些未解决的问题。 10 | 11 | `/m/btn/index.less` 如果要在视图代码中使用,不使用构建系统分别可以通过以下3种方式使用。 12 | 13 | 1. 在 `/view/login/index.html` 中通过 `` 引用 14 | 2. 在 `/view/login/index.css` 中通过 `@import url(../../m/btn/index.css)`; 引用 15 | 3. 复制 `/m/btn/index.css` 文件内容到 `/view/login/index.css` 中 16 | 17 | 1和2两种方式都会增加一个新的HTTP请求数,页面需要加载 `/m/btn/index.css` 和 `/view/login/index.css`。第三种方式很傻不易于维护 btn 样式一旦修改就要手动同步到多个地方。 18 | 19 | 可能读者会有疑问: 20 | 21 | > 直接把 btn 代码写到 view/pc/index.css 然后在所有页面调用这个css文件就解决了资源重复加载和手动同步的问题。 22 | 23 | 但是 btn 模块的代码放在 `view/pc/index.css` 中,违反了[文件目录](./directory.md)中提到的**资源就近维护**的原则。 24 | 25 | 这时我们就要使用CSS预处理器来帮助我们解决这个问题。比如 [Less](http://less.bootcss.com/) [Sass](https://www.sass.hk/)。 26 | 27 | 比如在 Less 中可以通过 `@import (less) "../m/btn/index.css";` `@import "../m/btn/index.less";` 或 的方式引入 css 或 less 。 28 | 29 | ```less 30 | // view/login/index.less 31 | @import (less) "../m/btn/index.css"; 32 | .login-title { 33 | font-size:20px; 34 | } 35 | ``` 36 | 37 | 通过编译文件会变成 38 | 39 | ```css 40 | /* view/login/index.less */ 41 | .m-btn { 42 | border:1px solid #EEE; 43 | background-color: #fafafa; 44 | color:#333; 45 | box-sizing: border-box; 46 | } 47 | .m-btn--danger { 48 | color:pink; 49 | border-color:red; 50 | } 51 | .login-title { 52 | font-size:20px; 53 | } 54 | ``` 55 | 56 | 还需要让构建系统检测 `/m/btn/index.css` 和 `/view/login/index.less` 被修改时立即编译 less。 57 | 58 | 而 `/m/switchClass/index.js` 也会遇到跟 `/m/btn/index.css` 相同的问题,这在JS方面统一使用 webpack 解决。[webpack-book](https://github.com/onface/webpack-book) 59 | 60 | ## 构建系统不等于前端工程 61 | 62 | 本书的章节顺序是[文件目录](./directory.md)在**构建系统**的前面,是为了纠正一个问题。 63 | 64 | 一定要先知道问题是什么,然后用构建工具解决这个问题。而不是学会了构建工具的使用,就按照固定的使用方式解决问题。 65 | 66 | 构建工具教程的的使用示例都只是单一场景,因为它是教程所以没法做到覆盖所有项目情况。需要使用者自己根据项目情况深思熟虑后判断如何使用。 67 | 68 | ## 构建工具对源码的侵入越少越好 69 | 70 | **px to rem**(不要用这个方案) 71 | 72 | ```css 73 | /* 源码 */ 74 | body { 75 | border-top: 1px; 76 | border-bottom: 10px; 77 | padding: 10px; /* @norem */ 78 | background-size: 10px 10px; /* @rem */ 79 | } 80 | ``` 81 | 82 | ```css 83 | /* 输出 */ 84 | body { 85 | border-top: 1px; 86 | border-bottom: 0.5557rem; 87 | padding: 10px; 88 | background-size: 0.5557rem 0.5557rem; 89 | } 90 | ``` 91 | 92 | 直接阅读源码会认为 body的各项单位设置的就是px,会带来误导。而且 `/* @norem */` 的标记非常麻烦。 93 | 94 | **less function** 95 | 96 | 编译 rem 这种需求应该使用CSS预处理器的函数功能解决 97 | 98 | [less-rem](https://github.com/onface/less-rem) 99 | 100 | ```less 101 | // 源码 102 | @import "./rem"; 103 | .demo { 104 | width:rem(640); 105 | height:rem(100); 106 | box-shadow: rem(11) rem(22) rem(33) pink; 107 | background: #eee; 108 | } 109 | ``` 110 | 111 | ```less 112 | // rem.less 113 | .function { 114 | .rem(@size) { 115 | // 640 是设计稿宽度 116 | // 640 is psd width 117 | return: @size/(640/320*16)+0rem; 118 | } 119 | } 120 | ``` 121 | 122 | ```css 123 | /* 输出 */ 124 | .demo { 125 | width: 20rem; 126 | height: 3.125rem; 127 | box-shadow: 0.34375rem 0.6875rem 1.03125rem pink; 128 | background: #eee; 129 | } 130 | ``` 131 | 132 | 直接阅读源码可以追踪到 `rem.less` 就会明白这个项目的 rem 计算标准是什么 133 | 134 | 135 | ## 构建工具的选择 136 | 137 | **因为自己搭建前端工程的构建系统才需要看这一部分所以内容移动到了 [issues](https://github.com/onface/workflow/issues/1)**,各种坑都在 issues 中。 138 | 139 | ## 构建工具的组合 140 | 141 | gulp fis webpack 应该组合使用,因为: 142 | 143 | 1. gulp 虽然有 [gulp-webpack](https://www.npmjs.com/package/gulp-webpack) 但是构建速度完全比不上**单独启动一个服务器加上 [webpack-hot-middleware](https://www.npmjs.com/package/webpack-hot-middleware)** 。 144 | 2. fis3 虽然有 [fis3-parser-webpack](https://www.npmjs.com/package/fis3-parser-webpack) 但是做不到异步加载和热更新。 145 | 3. webpack 虽然能[提取单独样式文件](https://github.com/onface/webpack-book/tree/gh-pages/6-extract-text) 但是不可能用它提取所有文件。还是需要 fis3 或者 gulp 构建非JS文件。 146 | 147 | > 所以 `gulp-webpack` `fis3-parser-webpack` `webpack提取单独样式文件` 都不要用。 148 | 149 | 那么就要选择 gulp 或 fis3 作为构建工具。因为 [静态资源映射表](http://fis.baidu.com/fis3/docs/lv3.html#%E5%9F%BA%E4%BA%8E%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%E7%9A%84%E6%A8%A1%E5%9D%97%E5%8C%96%E6%96%B9%E6%A1%88%E8%AE%BE%E8%AE%A1) 的原因,作者选择 fis3。当然你也可以选择 gulp ,毕竟可以改造它们以满足自己的需求。**只是时间成本和技术成本都很高,对两个构建工具做详细了解后选择改造工作量最小的**。时间充裕的情况下多花点时间了解(磨刀不误砍柴工)。 150 | 151 | 本地开发阶段:非 js 文件用 gulp fis3 构建,js文件使用 `webpack-dev-middleware` 和 `webpack-hot-middleware` 构建。因为 `webpack-dev-middleware` 速度非常快。 152 | 153 | > 如果选择 fis3 注意:最终构建时,先用fis3构建一遍所有文件,然后用webpack构建一遍js文件,都构建到同一个文件夹。然后再用fis3 构建一次生成文件指纹的文件(md5)。因为 js 交给 webpack 构建所以不能达到直接用fis3构建所有文件并加上文件指纹。 154 | 155 | ## 参考 156 | 157 | [onface/react-project](https://github.com/onface/react-project) 是基于 react 技术栈的前端工程解决方案 158 | 159 | ## markrun 160 | 161 | [markrun](https://github.com/markrun/markrun) 主要的功能是 162 | 163 | **源码** 164 | 165 | ````js 166 | document.title = "js - basic a 18" 167 | ```` 168 | 169 | **输出** 170 | 171 | ```html 172 |
173 | document.title = "js - basic a 18" 174 |175 | 178 | ``` 179 | 180 | [](https://markrun.github.io/markrun/) 181 | 182 | 利用 markrun 配合构建系统就能在 `/m/**/README.md` 中 编写一份代码,生成的html中出现 `pre` 和 `script/style/html` 183 | 184 | 单独列出 markrun 是因为提高了模块的文档编写速度开发人员就更愿意写文档,能在开发模块的同时完成简单的使用示例编写。 185 | 186 | --- 187 | 188 | 下一章:[技术选型](./technology-stack.md) 189 | -------------------------------------------------------------------------------- /chapter/directory.md: -------------------------------------------------------------------------------- 1 | ## 文件目录 2 | 3 | 项目代码可以分为两类 4 | 5 | 1. 模块代码 module 6 | 2. 视图代码 view 7 | 8 | > 注意是**视图代码**而不是*业务逻辑代码*,因为业务逻辑可以封装成模块。 9 | 10 | 当你刚入行开发一个企业站时,只需要写视图代码。比如 11 | 12 | ```js 13 | $(function () { 14 | $('.js-btn').on('click', function () { 15 | $('.js-text').toggleClass('light') 16 | }) 17 | }) 18 | ``` 19 | 随着技能的提升会将某些可复用的业务代码写成一个函数以便以重复使用。比如 20 | 21 | ```js 22 | function switchClass(element, target, className){ 23 | $(element).on('click', function () { 24 | $(target).toggleClass(className) 25 | }) 26 | } 27 | ``` 28 | 29 | > 实际工作中会对一些复杂的模块进行封装,不像 这里的 `switchClass()` 这么简单。 30 | 31 | 也会对某些CSS进行封装便于复用 32 | 33 | ```html 34 | 35 | 确认 36 | 删除 37 | ``` 38 | 39 | ```css 40 | /* btn.css */ 41 | .m-btn { 42 | border:1px solid #EEE; 43 | background-color: #fafafa; 44 | color:#333; 45 | box-sizing: border-box; 46 | } 47 | .m-btn--danger { 48 | color:pink; 49 | border-color:red; 50 | } 51 | ``` 52 | 53 | 很多项目的代码会根据文件类型的不同存放在不同的文件夹下 54 | 55 | ``` 56 | css/ 57 | - common.css # 将 btn 的样式写在 common.css 中 58 | img/ 59 | - logo.png 60 | js/ 61 | - common.js # 将 switchClass()写在 common.js 中 62 | - news.js 63 | - login.js 64 | - index.js 65 | html/ 66 | - news.html 67 | - login.html 68 | - index.html 69 | ``` 70 | 71 | 这种方式在页面越来越多时会难以维护,有时还需要在多个目录不停的切换。 72 | 73 | 为了便于检索,我们可以将模块代码和视图代码分别放在 `m` 和 `view` 文件夹下。 74 | 75 | **相关资源就近维护** 76 | 77 | ```shell 78 | m/ 79 | btn/ 80 | - loading.png 81 | - index.css 82 | - README.html # 编写 btn 的 html 示例 83 | switchClass/ 84 | - index.js 85 | - README.html # 编写 switchClass 的使用示例 86 | view/ # 调用模块代码和一些不需要封装的逻辑代码 87 | pc/ 88 | - base.js # 底层库(jQuery React Vue 等) 89 | - index.js # 公用界面代码(控制导航栏搜索展开,点击底部客服弹出窗口) — 单页应用则不需要 pc/index.js pc/index.css — 90 | - index.css # 存放 normalize.css 和少量公用样式,(不要使用 CSS Reset) 91 | login/ 92 | - index.js # 调用 m/swtich/index.js 提供的 swtich() 93 | - index.html # 引入 m/btn/index.css 和使用 确认 94 | - logo.png 95 | - index.css 96 | ``` 97 | 98 | 不命名为 `view/common` 而命名为 `view/pc` 是因为随着项目需求的变化,可能会出现 `view/mobile` 。 99 | 100 | 不只是相关资源就近维护了,还增加了 `/m/btn/README.html` 和 `/m/switch/README.html` 文件。 101 | 102 | README.html 的文件内容是: 103 | 104 | ```html 105 | 106 | 107 | 确认 108 | 删除 109 | ``` 110 | 111 | ```html 112 | 113 | 114 | Abcdef 115 | 116 | 117 | 120 | ``` 121 | 122 | 此处的两个 README.html 文件中编写当前模块的使用示例。这样其他同事想要使用这个模块时可以通过文档快速了解用哪些用法,不需要询问开发者。 123 | 124 | 继续维护这个模块时,我们会需要对已有的模块代码进行修改。不知道模块代码会被如何使用的情况下是不敢轻易修改的,但是参照着示例修改就能知道本次修改会不会影响到某一种示例。(复杂的模块最好写单元测试) 125 | 126 | **模块再小都要写示例,磨刀不误砍柴工。** 127 | 128 | ## 小结 129 | 130 | 1. 资源就近维护 131 | 2. 代码分为模块代码和视图代码 132 | 3. 模块一定要编写文档和示例 133 | 4. 使用 `/view/pc` 文件夹替代 `/common`,便于后续增加 `/view/mobile` 134 | 135 | ```shell 136 | m/ 137 | btn/ 138 | switchClass/ 139 | view 140 | pc/ 141 | - base.js 142 | - **.** 143 | login/ 144 | ``` 145 | 146 | --- 147 | 148 | 下一章:[构建](./build.md) 149 | -------------------------------------------------------------------------------- /chapter/flow-spec.md: -------------------------------------------------------------------------------- 1 | # 流程规范 2 | 3 | ## 开发规范 4 | 5 | ### 为什么需要开发规范 6 | 7 | 团队需要开发规范,每个人都按照开发规范编码便于协同开发。每一个人都是不同的个体,对于什么样的代码是优秀的代码都有自己的理解。开发规范能一定程度上**统一代码风格**,**避免写出不易于维护的代码**和提供一些**好的编程技巧**。 8 | 9 | 举个反例: 10 | 11 | 公司有四名前端,对于 class 命名他们的代码分别是 12 | 13 | ```html 14 | 15 |