序
前端该不该碰业务?
前端还是不要碰业务逻辑,围绕着交互做就好了
将“前端工程体系”定义成一种服务,而非一种工程模型
示例代码
前端工程师的基本素养
前端革命
AJAX
A New Approach to Web Applications
实现异步请求和局部刷新
Node
Node 集成了 V8 引擎、事件驱动 和 底层 I/O API,并且可使用 JS 语言开发服务器端应用的运行环境
1、服务器端开发
2、同构JS
服务器端渲染:浏览器主动发送请求,然后服务器端生成 HTML 文档后发送响应给浏览器,浏览器接到响应后将 HTML 文档渲染为可视网页
节省客户端资源
有利于SEO
缺点:每访问一个页面都要发起请求
SPA:服务端 RESTFul API 只提供渲染 HTML 所需的 JSON 数据
减轻了服务器的资源消耗
与HTML 文档比起来,JSON 数据的体积小很多,减少了网络请求的事件消耗
页面路由控制更快速灵活
可以离线使用
缺点:
“白屏时间”:浏览器要等JS文件加载完后才可以渲染后续的 HTML 文档内容
不利于SEO( google 已经对SPA 进行了 SEO 优化,但国内浏览器仍有该问题)
数据格式问题及路由逻辑冲突
同构JS:在 浏览器 和 Node 环境都可以渲染 ,性能、SEO、可维护性都有更好的支持
3、前端工具
Grunt | Gulp | webpack 等等
前后端分离
好处
开发:实现前后端并行开发,缩短开发周期
测试:令前后端工程师更快速、精准地对问题进行定位
部署:将静态文件和动态文件分离部署并结合回滚策略,简化了部署流程,增强了应用程序的健壮性
模式
开发
HTML模版的处理方案
SPA项目:不存在HTML 模版的概念,所有 HTML 实体内容均由 JS 在浏览器下生成。所以可将 html 作为静态文件处理
HTML 模板由服务器部署的项目:最终的HTML模版需要与服务器端代码一起打包部署,由于静态文件必须由HTML 引入,为了避免套模板,开发阶段前端直接编写 HTML 模板
HTML 模板引擎的支持
Mock:写代码前约定好接口的请求规范和数据结构
HTML 模板的初始数据
各种异步数据接口的数据
大前端项目:前端负责与客户端相关的所有文件,包括静态文件和 HTML 模板
部署
静态资源和动态资源的分离部署
SPA项目:
不能令浏览器将 html 文件强制缓存到本地
方案一: 专业服务器一般都支持针对文件拓展类型设置不同的缓存策略
html 文件:使用协商缓存(浏览器HTTP请求返回304)
其他静态资源:强缓存策略 (浏览器HTTP请求返回200)
方案二:都使用协商缓存
静态资源部署到静态文件服务器
HTML 模板 与 服务器端代码一同部署
注意:大部分公司供测试用的静态文件服务器是不设置客户端缓存的,这样可以保证测试环境下每次访问网站都能拿到最新的资源
HTML 模板由服务器部署的项目:最终的HTML模版需要与服务器端代码一起打包部署,由于静态文件必须由HTML 引入,为了避免套模板,开发阶段前端直接编写 HTML 模板
HTML 模板引擎的支持
Mock:写代码前约定好接口的请求规范和数据结构
HTML 模板的初始数据
各种异步数据接口的数据
大前端项目:
将 JS、CSS、图片等静态资源部署到静态文件服务器
HTML 模板文件与中间层的 Node.js 代码一同部署到 Web 服务器
前端工程化
工具为实现
开发
ES 规范与浏览器兼容性不一致
CSS 弱编程能力
资源定位
图片压缩|base64 内嵌| CSS Sprites
模块依赖分析和压缩打包
协作
- JS部分逻辑依赖接口API
部署(动静态资源分离部署)
- 部分资源需要借助后端工程师部署
规范为蓝本
项目文件的组织结构:
源码的开发范式
工具的使用规范
各阶段的环境依赖
进化形态——集中管理的云平台
淡化环境差异性,保证构建产出的一致性
权限集中管理,提高安全性
项目版本集中管理,便于危机处理,比如版本回滚等
工程化方案架构
工具流管理工具:Grunt | Gulp
构建工具:webpack | rollup
整体解决方案:FIS | WeFlow
命令行工具
1、package.json 设置入口文件
"bin": {
"dbox": "bin/dbox.js"
}
2、在 bin/dbox.js 顶部声明此文件需要调用 Node.js 执行
#!usr/bin/env/ node
3、命令行交互模块 commander.js
const commander = require('commander')
环境区分
dev: 借助 Mock 服务进行前端逻辑开发
testing:测试环境与生产环境的异步数据接口地址不同,构建出的代码需要便于浏览器调试(不混淆)
production: 控制静态文件的体积
集成 Yeoman 封装脚手架方案
通过命令行收集用户的配置信息
将这些动态的配置信息转化成静态的文件内容:通常使用 Boilerplate(样板文件,HTML模板引擎)执行,Yeoman 默认使用 EJS 引擎,动态内容转化完成后可将“.ejs” 文件后缀修改为 “.js “ 、”.css” 、”.html”
将生成的文件复制到目标文件夹
封装一个脚手架方案实质上是创建一个 Yeoman Generator 实例
class extends Generators {
constructor(args, opts) {
super(args, opts);
// ...
}
initializing() {
// ...
}
prompting() {
// 负责用户提示和配置收集
let prompts = [].concat(require('./_prompts/_js.js'))
.concat(require('./_prompts/style.js'))
.concat(require('./_prompts/_html.js'))
return this.prompt(prompts).then((res) => {
let appname = res.appname || this.options.appname;
let options = Object.assign({}, res, {appname});
});
// dependencies,提供给自动安装依赖模块功能使用
this.pkg = options.nodeModules;
// 渲染配置项
this.renderOpts = options;
}
writing() {
// 负责文件操作
}
install() {
// 负责依赖模块安装
}
}
构建
开发者直接编写的源代码并不能在宿主浏览器中正确无误地运行,构建(编译)承担着从源代码到可执行代码的转换者角色。
ES 规范的转译
CSS 预编译语法转译
HTML 模板渲染
依赖打包:分析文件依赖关系,将同步依赖的文件打包在一起,减少 HTTP 请求数量
资源嵌入:比如小于10KB 的图片编译为 base64 格式嵌入文档,减少一次 HTTP 请求
文件压缩:减小文件体积,缩短请求时间
hash 指纹:通过给文件名加入 hash 指纹,以应对浏览器缓存策略
域名/路径改变:开发环境与线上环境的域名肯定是不同的,不同类型的资源甚至部署于不同的 CDN 服务器上
文件名改变:经过构建之后文件名被加上 hash 指纹,内容的改动导致 hash 指纹的改变
资源定位本质上是由于测试环境与生产环境的差异性
Babel
ES6 对开发效率和源代码可维护性的提升是非常客观的。ES6 几行代码通常需要几十行 ES5 代码才可以实现。
Babel 将 class 转化为两部分:
工厂函数代码
创建 class 本身的代码
构建系统:支持模块化规范并能够将散列的模块构建为利于部署的整合文件
模块化开发的价值:
避免命名冲突
便于依赖管理
利于性能优化
提高可维护性
利于代码复用
commonJS
针对服务器端或桌面应用开发等非浏览器环境下的 JS 开发
静态模块化规范
均是同步阻塞式加载,无法实现按需异步加载
AMD/CMD
可以处理 JS 以外的资源
源码无须编译便可在浏览器环境下运行
按需异步加载、并行加载
插件系统
CommonJS 和 ES6 Module 虽然自身不支持异步加载,但是提供了两种方式:
require.ensure()
: 是 webpack 的特有 API,可移植性差import()
:未来可期,但是需要借助特殊注释定义异步文件的名称
增量更新与缓存
构建产出文件 hash 指纹,这是实现增量更新的必要条件
构建更新 html 文件对其他静态资源的引用 URL
强缓存根据过期时间决定使用本地缓存还是请求新资源
Expires 的致命缺陷:它所指定的时间点是以服务器为准的时间,但是客户端进行过期判断时是将本地的时间与此时间点对比。
Cache-control:
no-cache 和 no-store:
no-cache: 并非禁止缓存,而是需要先与服务器确认返回的响应是否发生了变化,如果资源未发生变化,则可使用缓存副本从而避免下载
no-store: 是真正意义上的禁止缓存,禁止浏览器以及所有中间缓存存储任何版本的返回响应。每次用户都会向服务器发送请求,并下载完整的响应
public 和 private:
public:表示此响应可以被浏览器以及中间缓存器无限期缓存,此信息并不常用,常规方案是使用 max-age 指定精确的缓存时间
private: 表示此响应可以被用户浏览器缓存,但是不允许任何中间缓存器对其进行缓存。例如用户的浏览器可以缓存包含用户私人信息的 HTML 网页,但 CDN 却不能缓存
max-age: 指定从请求的时刻开始计算,此响应的缓存副本有效的最长时间。
Cache-control 比 Expires 有更高的优先级
协商缓存每次都会发出请求,经过服务器进行对比后决定采用本地缓存还是新资源
Etag 作为响应首部信息返回给浏览器。浏览器在 Cache-control 指定 no-cache 或者 max-age 和 Expires 均过期后,将 Etag 值通过 If-none-match 作为请求首部信息发送给服务器。服务器接收到请求之后,对比所请求资源的 Etag 值是否改变,如果未改变将返回 304 Not Modified,并且根据既定的缓存策略分配新的 Cache-control 信息;如果资源发生了改变,则会返回最新的资源以及重新分配的 Etag 值。
对于非服务器端渲染项目中的 HTML 文档,由于它是所有其他静态资源的引用者,所以必须保证每次请求到的资源都是最新的。同时,为了便于服务器解析和保证网站地址的唯一性, html 文件不能应用 hash 指纹。这种场景下只能使用协商缓存。
覆盖更新:在引用资源的 URL 后添加请求参数,比如添加时间戳参数,浏览器会将参数不同的 URL 视为全新的 URL,所以下面的改动可以保证浏览器向服务器请求并下载最新的资源。
<script type="text/javascript" src="main.home.js?v=1.0.0">
有两个致命缺陷:
必须保证 html 文件与改动的静态文件同步更新,否则会出现资源不同步的情况
不利于版本回滚
增量更新:
<script type="text/javascript" src="main.home.bbcdaf73.js">