文章目录
前言
时间账单 总是要还的。。。。克莱因壶有时间也想看。。。。
一、什么是前端工程化
- 前端工程化是指遵循一定的标准和规范通过工具提高效率的一种手段。技术是为了解决问题而存在的,主要解决的问题
- 传统语言和语法的弊端
- 无法使用模块化/组件化
- 重复的机械性工作
- 依赖后端接口支持
- 整体依赖后端项目
- 很难做到代码风格统一、质量难以做保证
- 一切以提高效率、降低成本、质量保证为目的的手段都属于工程化
二、脚手架工具
常用的脚手架工具:
- React.js---->create-react-app
- Vue.js---->vue-cli
- Angular----->angular-cli
三、Yeoman
Yeoman 是一种高效、开源的 Web 应用脚手架搭建系统,意在精简开发过程
- 提供了一种灵活创建、开发、编译和调试 Web 应用的脚手架(scaffolding)软件
- 本身是 JavaScript 编写的,但适用于任何语言编写的应用
- 支持与 Webpack、Babel、TypeScript、React 和 Angular 等多种第三方软件库的无缝集成
需要安装对应的Generator来使用
- generator本质就是一个NPM模块,generator有基本结构
开发行业中的自动化构建就是把我们在开发环境的源代码自动化的转化为生产环境中可运行的代码
四、使用node写一个小脚手架
实现思路
- 1.新建一个sample-scaffolding文件夹,在文件夹中npm init生成package.json文件,在json文件中增加一个bin字段,指定cli的入口文件为cli.js
- 2.“#!/usr/bin/env node” cli文件需要这个头 linux和macOS要修改这个文件的读写权限为755,通过chomd cli.js 755 来实现
- 3.在cli.js.js文件中通过npm link的方式链接到全局,通过sample-scaffolding(文件夹名)验证cli基础是否完成
- 4.npm i inquier模块,有个prompt方法接收数组参数,这个方法用来询问用户信息
- 5.创建模板文件夹template,index.html
- 6.根据相应node api获取 目标目录(process.cwd())和模块目录(path.join(_dirname,‘template’))
- 7.根据fs.readdir方法获取template里面的所有文件名
- 8.遍历返回的数组,通过ejs.renderFile模板引擎去将用户输入的属性对应渲染到模板文件中
- 9.通过fs.writeFileSync将模板文件写入到目标路径中
- 10.测试步骤 新建demo文件夹 在demo终端上输入 sample-scaffolding,demo文件夹下生成模板文件 demo和sample-scaffolding都在此文件夹下
#!/usr/bin/env node
console.log("测试")
//工作过程 问用户问题 根据用户回答结果生成文件
const inquirer = require('inquirer')
const path = require('path')
const fs = require('fs')
const ejs = require('ejs')
inquirer.prompt([{
type: 'input', //交互类型
name: "name", //属性 名字
message: "Project name?" //提示信息
}]).then(res => { //根据用户输入 返回的对象
console.log(res)
console.log(__dirname)
console.log(process.cwd())
//模板目录 join方法 window下用\链接起来 并规范生成的路径
const tmplDir = path.join(__dirname, 'template') //_dirname 当前文件所在文件夹绝对路径 -文件所在目录
//目标目录
const destDir = process.cwd() //当前执行node进程命令文件所在的文件夹目录 -工作目录
//将模板目录转换到目标目录
fs.readdir(tmplDir, (err, files) => { //readdir方法 获取目录所有文件名
console.log(files)
if (err) throw err
files.forEach(item => {
//通过模板引擎渲染文件
ejs.renderFile(path.join(tmplDir, item), res, (err, result) => {
if (err) throw err
console.log(result)
//将结果写入目标路径
fs.writeFileSync(path.join(destDir,item),result)
})
});
})
})
五、gulp
自动化构建有grunt,gulp,fis,但是目前主要流行gulp了
1.准备启动
mkdir my-gulp
cd my-gulp
yarn init --yes //初始化package文件
yarn add gulp --dev //安裝gulp模块
2.创建gulpfile.js文件
// gulpfile.js
//gulp的入口文件
exports.foo = (done)=>{
console.log("foo is working")
//使用 yarn gulp foo执行,发现报错,因为gulp取消了同步任务,规定为异步任务,可以接受一个参数,最后调用参数标识任务的完成
done() //标识任务完成
}
//使用默认,yarn gulp 即可定位运行到default
exports.default = done => {
console.log('default')
done()
}
3.组合任务
未被导出的函数可以理解为私有任务,例如以下为三个私有任务
const task1 = done => {
setTimeout({
console.log("task1 working~~")
done()
},1000)
}
const task2 = done => {
setTimeout({
console.log("task2 working~~")
done()
},1000)
}
const task3 = done => {
setTimeout({
console.log("task3 working~~")
done()
},1000)
}
可以通过series,parallel进行并行和串行的操作
const { series, parallel, task } = require("gulp")
exports.foo = series(task1, task2, task3) //串行
exports.bar = parallel(task1,task2,task3) //并行
//测试
yarn gulp foo
yarn gulp bar
4.异步任务
gulp都是异步任务,我们可以通过传参来抛出异常
exports.callback = done => {
console.log('callback~~')
done()
}
exports.callback_error = done => {
console.log('callback_error~~')
//可以通过传参的方式来抛出一个错误,错误优先
done(new Error('task_error'))
}
通过promise來控制任务的成功与否
exports.promise_success = done => {
console.log('promise')
//不需要为resolve传递任何值,以为gulp会忽略
return Promise.resolve()
}
exports.promise_fail = done => {
console.log('promise')
//传递具体的错误信息
return Promise.reject(new Error('promise fail'))
}
使用async await 进行
const timeout = time => {
return new Promise(resolve => {
setTimeout (resolve,time)
})
}
exports.async = async () => {
await timeout(1000)
console.log('async task~~~')
}
基于Stream的异步
exports.stream = () => {
const readStream = fs.createReadStream('package.json')
const writeStream = fs.createWriteStream("tmp.txt")
readStream.pipe(writeStream)
return readStream
}
5.构建过程
//对css进行压缩
const fs = require("fs")
const { Transform } = require("stream")
exports.default = () => {
//文件读取流
const read = fs.createReadStream("nomarlize.css")
//文件写入流
const write = fs.createWriteStream("nomarlize.min.css")
//文件转换流
const transform = new Transform({
transform:(chunk,encoding,callback)=>{
//核心转化过程实现
//chunk => 读取流中读取到的内容(buffer)
const input = chunk.toString()
const output = input.replace(/\s+/g,'')
callback(null,output)//错误有限,如果没有错误,则传入null
}
})
//先转化后写入
read.pipe(transform).pipe(write)
return read
}
6.文件操作API
src,dest
const {src,dest} = require('gulp')
//将src下的文件映射到dist
exports.default = () => {
return src('src/normalize.css').pipe(dest('dist'))
}
使用通配符,將src下边的以css结尾的文件都会被复制
exports.default = () => {
return src('src/*.css').pipe(dest('dist'))
}
安装模块
yarn add gulp-clean-css --dev
yarn add gulp-rename --dev
转化css代码
const {src,dest} = require('gulp')
const cleanCss = require('gulp-clean-css')
const rename = require('gulp-rename')
exports.default = () => {
return src('src/*.css').
pipe(cleanCss())
.pipe(rename({extname:'.min.css'}))
.pipe(dest('dist'))
}
总结
前端工程可以解决一下几类问题:
- 1.ES6+兼容性问题
- 2.sass和less运行环境不支持
- 3.使用模块化提高项目的可维护性,并且使运行环支持
- 4.自动压缩代码和资源文件,自动上传到服务器
- 5.多人开发统一代码风格
- 6.解决依赖后端接口支持,依赖后端环境