- 背景:
以前刀耕火种的年代
- 问题/解决方案
代码不够健壮,可读性差,没有智能提示,使用 TypeScript,提高代码质量,智能提示让我们更加方便快捷
多人开发,风格不够统一,质量层次不齐,可以使用一些编码规范检查的工具,使得项目代码风格统一,质量得到保证
Mock.js 这样的插件完成假数据的编写,开发阶段时,让前端可以不依赖后端接口去完成相应工作
想使用ES6+新特性,但是兼容有问题,借助babel
想使用Less/Sass/PostCss增强Css的编程性,借助一些编译工具
部署上线前需要手动压缩代码以及资源文件,部署过程需要手动上传代码到服务器 创建自己的自动化构建工作流,持续集成,自动发布
概念
前端工程化是指遵循一定的规范和标准,通过工具去降低成本,提高效率的手段。一切以提高效率,保证质量,降低成本为目的的手段都属于工程化
工程化 != 工具
工程化是对我们整体项目的规划和架构 工具只是帮我们去实现这种规划的一种手段
creat-react-app vue-cli 是集成式的工程化方案,并不是单纯的脚手架
不仅创建的项目,约定了项目应该是什么样的结构
提供了热更新开发服务,自动编译 vue 的单文件组件,代码分格的校验
工程化应该归功于 node,由 node 强力驱动
四个维度实现:
-
模块化
- es6 export import 社区制定了一些模块加载方案 CommonJS、AMD 和 CMD
- css 的模块化 @import, css in js,css module
- 资源的模块化 webpack 一切皆模块
-
组件化
- 模块化是文件层面上的,对代码资源的拆分。而组件化是设计层面的,对 UI 的拆封
- 组件化更重要是一种分治思想
- 组件化实现工程化用的工具就是 react,vue
-
规范化
- 目录结构的制定
- 有助于提高项目的逻辑结构的合理性
- 对应扩展和合作
- 快速的资源定位
- js 规范
- 统一语法 用 hooks 就大家一起用 不要一会类组件一会函数组件
- eslint 统一在项目根目录约定
- 格式化工具 -prettier
- 前后端接口的规范
- 接口文档 一步到位各撸各的
- 接口返回数据即显示,前端仅做渲染逻辑处理
- 渲染逻辑禁止跨多个接口调用
- 前端关注交互、渲染逻辑,尽量避免业务逻辑处理的出现
- 请求响应传输数据格式:JSON,JSON 数据尽量简单轻量,避免多级 JSON 的出现;
- 定好通用的数据返回格式,以及状态值的规范
- 日期类型,JSON 数据传输中一律使用字符串,具体日期格式统一 utc
- 目录结构的制定
自动化
任何简单机械的重复劳动都应该让机器去完成。
- 三个方面
- 项目脚手架帮我们自动搭建初始项目结构,提供基础模板,规范结构,等
- 项目开发中实现热加载,源代码的变动自动响应浏览器
- 项目自动化构建,自动化部署 持续集成 自动化测试
具体落实前端工程化
- 脚手架开发
- 自动化构建系统
- 模块化打包
- 项目代码规范化
- 自动化部署
脚手架工具
创建基础项目结构,提供项目规范和约定
保证相同的组织结构 相同的开发范式 相同的模块依赖
相同的工具配置 相同的基础代码没有脚手架我们会有大量的基础工作去做
团队成员对同一个脚手架新建的不同的工程都可以去维护修改添加需求,保证了成员灵活性和可调配性。
常用脚手架
React => create-react-app
vue => vue-cli
angular => angular-cli
yeoman 通用型脚手架工具
Plop 创建特定类型文件
脚手架的实现过程
脚手架工具其实就是个 nodecli 应用,创建脚手架过程就是创建 cli 应用的过程
通过命令行交互询问用户问题;
根据用户回答的结果,再结合一些模板文件,最后生成项目结构。
实现过程
创建一个文件
mkdir my-cli
- 初始化 package.json
yarn init
- 在 package.json 中添加 bin 字段,指定 cli 的入口文件
"bin":"cli.js"
添加 cli.js
cli 文件必须有特定操作头(如果是 Linux 或者 macOS 系统的话还需要修改此文件的读写权限为 755)
$ chmod 755 cli.js
#!usr/bin/env node
console.log('glh')
yarn link
my-cli
执行完再终端就会看到打印结果为 glh
要通过命令行询问用户、需要安装 inqurier
yarn add inquirer
根据用户输入动态生成文件
const inquirer = require('inquirer');
const path = require('path');
const fs = require('fs');
const ejs = require('ejs');
inquirer
.prompt([
{
type: 'input',
name: 'name',
message: 'Preject name',
},
])
.then(anwsers => {
// 模板目录
const templDir = path.join(__dirname, 'templetes');
// 目标路径
const destDir = process.cwd();
fs.readdir(templDir, (err, files) => {
if (err) throw err;
files.forEach(file => {
ejs.renderFile(path.join(templDir, file), anwsers, (err, result) => {
if (err) throw err;
fs.writeFileSync(path.join(destDir, file), result);
});
});
});
});
上面过程大致意思就是在脚手架根目录创建一个 templetes 目录,用来存放我们的模板文件,然后根据用户输入,通过 ejs 模板引擎的 renderFile 方法把我们的用户输入结果和模板相结合,输出到我们脚手架使用时候文件的根目录
自动化构建
一切重复的工作都应该自动化,将我们生产环境的源代码,转化为生产环境可以运行的代码或者程序,我们把这样一个过程称之为自动化构建工作流。这样的作用就脱离运行环境带来的兼容问题,在开发阶段使用一些提高效率的语法,规范和标准
NPM Script 是实现自动化构建工作流的最简单的方式
-
常见的自动化构建工具
Gulp
使用注意事项
- gulp默认创建的任务为异步任务,如果我们在任务中写同步代码必须传入回调函数指定任务结束
// 4.0版本以上
exports.foo = done = {
console.log('同步代码')
done()
}
- 任务组合
const { series, parallel } require('gulp')
// 串行模式
exports.foo = series(task1, task2)
// 并行模式
exports.foo = parallel(task1, task2)
- gulp的工作原理
The streaming build system
const fs = require('fs');
const { Transform } = require('stream');
exports.default = () => {
const read = fs.createReadStream('index.js');
const write = fs.createWriteStream('index.js');
const transform = new Transform({
transfor: (chunk, encoding, callback) => {
const input = chunk.toString();
const output = input.replace(/\s+/g, '').replace(/\/\*.+?\*\//g, '');
callback(null, output);
},
});
read.pipe(transform).pipe(write);
return read;
};
- 读取流
- 转换流
- 写入流