一、前端工程化
1.工程化的定义和主要解决的问题
- 工程化的定义:
- 遵循一定的标准和规范,通过工具去提升开发的效率,降低成本的一种手段。
- 主要解决的问题:
- 传统语言或语法的弊端
- 无法使用模块化、组件化
- 重复的机械式工作
- 代码风格统一、质量保证
- 依赖后端服务接口支持
- 整体依赖后端项目
- 部署上线前需要手动压缩代码及资源文件
- 部署过程需要手动上传代码到服务器
2.一个项目中工程化的表现
- 一切一提高效率、降低成本、质量保证为目的的手段都属 [ 工程化 ]
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0YsfpdSv-1620281845575)(D:\personal\大前端高薪训练营-拉钩\笔记\image-20210429155734825.png)]
- 创建项目:使用脚手架工具创建项目基础结构
- 编码:格式化代码、校验代码风格、编译/构建/打包
- 预览/测试:WebServer / mock、LiveReloading / HMR 、Source Map . 热更新
- 提交:Git Hooks 、Lint-staged、持续集成 代码提交之前做检查、日志
- 部署:CI / CD 、自动发布。避免手动操作失误
3.工程化 != 工具
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PRi623Ne-1620281845577)(D:\personal\大前端高薪训练营-拉钩\笔记\image-20210429160908808.png)]
二、脚手架工具
创建项目基础结构、提供项目规范和约定
1.脚手架工具概要
- 脚手架的作用
- 相同的组织结构
- 相同的开发范式
- 相同的模块依赖
- 相同的工具配置
- 相同的基础代码
- 常用的脚手架工具
- 通用的脚手架工具剖析
- 开发一款脚手架
三、Yeoman 简介
- 最老牌、最通用的的web 脚手架工具。
1. Yeoman 基本使用
-
安装 yeoman
yarn global add yo // 安装 yeoman yarn global add generator-node // 安装generator生成器 工具 yo node
npm i -g yo npm i -g generator-node yo node
-
yo 安装描述
- 模块叫什么名字
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zOH7s3N4-1620281845578)(D:\personal\大前端高薪训练营-拉钩\笔记\image-20210429162949545.png)]
- 项目已经存在是否选择另外一个
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fnb2oxZa-1620281845580)(D:\personal\大前端高薪训练营-拉钩\笔记\image-20210429163103493.png)]
- 项目描述
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mnhy5fyb-1620281845581)(D:\personal\大前端高薪训练营-拉钩\笔记\image-20210429163230987.png)]
- 项目的主页
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bvNZ9kBk-1620281845582)(D:\personal\大前端高薪训练营-拉钩\笔记\image-20210429163342888.png)]
- 作者的邮箱、主页、关键词
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AIw9KhGb-1620281845583)(D:\personal\大前端高薪训练营-拉钩\笔记\image-20210429163520864.png)]
- 是否发送代码的覆盖率报告,持续集成
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5qZBnfWc-1620281845583)(D:\personal\大前端高薪训练营-拉钩\笔记\image-20210429163626300.png)]
- node的支持、github名字、MIT
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IXyC3YFT-1620281845584)(D:\personal\大前端高薪训练营-拉钩\笔记\image-20210429163804203.png)]
- 模块叫什么名字
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qAO1Oa7s-1620281845584)(D:\personal\大前端高薪训练营-拉钩\笔记\image-20210429164010082.png)]
2.Yeoman 使用步骤总结
-
明确你的需求
-
找到合适的 Generator
-
全局范围安装找到的 Generator
-
通过 yo 命令运行对应的 Generator
-
通过命令行交互填写选项
-
生成你所需要的项目结构
-
步骤:
// 地址:https://yeoman.io/generators/ // yeoman 官网 yarn global add generator-webapp yo generator-webapp yo webapp
3.创建 Generator 模块
-
初始化
yarn init
-
安装 Generator 的基类
yarn add yeoman-generator
-
// 此文件作为 Generator 的核心入口 // 需要导出一个继承自 Yeoman Generator 的类型 // Yeoman Generator 在工作时会自动调用我们在此类型中定义的一些生命周期方法 // 我们在这些方法中可以通过调用父类提供的一些工具方法实现一些功能,例如文件写入 const Generator = require('yeoman-generator') module.exports = class extends Generator { prompting () { // Yeoman 在询问用户环节会自动调用此方法 // 在此方法中可以调用父类的 prompt() 方法发出对用户的命令行询问 return this.prompt([ { type: 'input', name: 'name', message: 'Your project name', default: this.appname // appname 为项目生成目录名称 } ]) .then(answers => { // answers => { name: 'user input value' } this.answers = answers }) } writing () { // Yeoman 自动在生成文件阶段调用此方法 // // 我们这里尝试往项目目录中写入文件 // this.fs.write( // this.destinationPath('temp.txt'), // Math.random().toString() // ) // ------------------------------------------------------- // // 通过模板方式写入文件到目标目录 // // 模板文件路径 // const tmpl = this.templatePath('foo.txt') // // 输出目标路径 // const output = this.destinationPath('foo.txt') // // 模板数据上下文 // const context = { title: 'Hello zce~', success: false } // this.fs.copyTpl(tmpl, output, context) // ------------------------------------------------------- // 模板文件路径 const tmpl = this.templatePath('bar.html') // 输出目标路径 const output = this.destinationPath('bar.html') // 模板数据上下文 const context = this.answers this.fs.copyTpl(tmpl, output, context) } }
-
命令行输入
yo link
4.vue generator 的案例
-
win +r 键输入 cmd 打开命令行工具输入:
mkdir generator-vue // 创建generator-vue文件夹 cd generator-vue // 进入创建好的文件夹 yarn init // 初始化package.json yarn add generator-vue // 安装yeoman 的依赖 code . // 通过vscode 打开项目
-
在 vscode 中的依次创建 generators/app/index.js 的入口文件
// index.js const Generator = require('yeoman-generator') module.exports = class extends Generator { prompting () { return this.prompt([ { type: 'input', name: 'name', message: 'Your project name', default: this.appname // appname 为项目生成目录名称 } ]) .then(answers => { // answers => { name: 'user input value' } this.answers = answers }) } writing () { // 模板文件路径 const tmpl = this.templatePath('bar.html') // 输出目标路径 const output = this.destinationPath('bar.html') // 模板数据上下文 const context = this.answers this.fs.copyTpl(tmpl, output, context) } }
-
在 app 文件下面创建 templates 文件,把项目的结构拷贝到templates中作为模板!
-
在项目模板中 把需要创建项目时替换的名称,换位模板标记 <%= name %>
-
在index.js的入口文件中输入:
const Generator = require('yeoman-generator') module.exports = class extends Generator { prompting () { return this.prompt([ { type: 'input', name: 'name', message: 'Your project name', default: this.appname // appname 为项目生成目录名称 } ]) .then(answers => { this.answers = answers }) } writing () { const templates = [ 'public', 'public/favicon.ico', 'public/index.html', 'src', 'src/api', 'src/api/index.js', 'src/api/login.js', 'src/assets', 'src/assets/images', 'src/assets/images/user.png', 'src/assets/images/user-default.png', 'src/assets/scss', 'src/assets/scss/_variable.scss', 'src/assets/scss/app.scss', 'src/assets/scss/common.scss', 'src/assets/scss/home.scss', 'src/assets/scss/reset.scss', 'src/components, 'src/components/EChart.vue', 'src/components/Icon.vue', 'src/components/IconSvg.vue', 'src/components/Tabs.vue', 'src/icons', 'src/icons/svg', 'src/icons/svg/daochu.svg', 'src/icons/svg/daoru.svg', 'src/icons/svg/morentouxiang.svg', 'src/icons/svg/tuichu.svg', 'src/icons/index.js', 'src/layout', 'src/layout/components', 'src/layout/components/CommonAside.vue', 'src/layout/components/CommonForm.vue', 'src/layout/components/CommonHeader.vue', 'src/layout/components/CommonTab.vue', 'src/layout/components/CommonTable.vue', 'src/layout/components/index.js', 'src/layout/Main.vue', 'src/mock', 'src/mock/home.js', 'src/mock/index.js', 'src/mock/permission.js', 'src/mock/user.js', 'src/router', 'src/router/index.js', 'src/router/routes.js', 'src/store', 'src/store/modules', 'src/store/modules/tab.js', 'src/store/modules/user.js', 'src/store/getters.js', 'src/store/index.js', 'src/utlis', 'src/utlis/bus.js', 'src/utlis/config.js', 'src/utlis/request.js', 'src/views', 'src/views/CollectiFDataFiles', 'src/views/CollectiFDataFiles/index.vue', 'src/views/Home', 'src/views/Home/Home.vue', 'src/views/Login', 'src/views/Login/Login.vue', 'src/views/MobileTerminalTargeKnowledgeManagement', 'src/views/MobileTerminalTargeKnowledgeManagement/index.vue', 'src/views/PlatformTargetKnowledgeManagement', 'src/views/PlatformTargetKnowledgeManagement/index.vue', 'src/views/RegionalSpecificKnowledgeManagement', 'src/views/RegionalSpecificKnowledgeManagement/index.vue', 'src/views/RestoreThePostInformationMaterialFile', 'src/views/RestoreThePostInformationMaterialFile/index.vue', 'src/views/TheGlobalQuantity', 'src/views/TheGlobalQuantity/index.vue', '.browserslistrc', '.DS_Store', '.eslintrc.js', '.gitignore', 'babel.config.js', 'package.json', 'package-lock.json', 'postcss.config.js', 'README.md', 'vue.config.js', 'yarn.lock' ] templates.forEach(item => { this.fs.copyTpl( this.templatePath(item), this.destinationPath(item), this.answers ) }) } }
-
然后在命令行中输入
yarn link // link 到全局 cd .. // 返回到上一级 mkdir vue-template // 创建 vue-template 文件夹 cd vue-template yo node // node 是开始安装 generator-node 的名字
四、自动化构建
1.自动化简介
- 一切重复工作本应自动化
- 把开发阶段写的源代码转换成生产环境的生产代码(自动化构建工作流)
- 脱离运行环境兼容带来的问题
- 使用提高效率的规范、语法和标准
- ECMAScript Next
- Sass
- 模板引擎
2.自动化构建初体验(scss)
/* 命令行中输入 黑色字体*/
yarn init // 初始化
// 创建scss 文件夹和 main.scss 文件和index.html
yarn add sass --dev // 安装sass官方提供的scss文件
// 执行 node_modules\.bin\sass 文件 打印帮助信息
node_modules\.bin\sass
// 执行 node_modules\.bin\sass scss/main.scss css/style.css 生成style.css
node_modules\.bin\sass scss/main.scss css/style.css
// npm Scripts
// 在package.json 中输入 "scripts":{
// "build": "sass scss/main.scss css/style.css"
// },
"scripts":{"build": "sass scss/main.scss css/style.css"}
// yarn build 或 npm run build
yarn build
// yarn add browser-sync --dev 启动测试服务器运行项目
yarn add browser-sync --dev
// 在package.json 中输入 "scripts":{
// "build": "sass scss/main.scss css/style.css",
// "serve": "browser-sync ."
// },
yarn serve // 启动服务器,自动弹出浏览器
// 添加prserve 自动执行yarn build 执行scss 到 css
// 在package.json 中输入 "scripts":{
// "build": "sass scss/main.scss css/style.css",
// "preserve": "yarn build",
// "serve": "browser-sync ."
// },
yarn add npm-run-all --dev // 同时启动 build serve 命令
// "scripts": {
// "build": "sass scss/main.scss css/style.css --watch",
// "serve": "browser-sync . --files \"csss/*.css\"",
// "start": "run-p build serve"
// },
3.常用的自动构建化工具
- Grunt (自由):
- 临时构建,相对速度较慢
- Gulp(自由):
- 构建速度快,基于内存实现
- 同时支持多个任务
- FIS(基础):
- 百度团队推出
- 捆绑套餐、模块开发
五、Grunt 自动化构建工具
1.Grunt 基本用法
-
添加 grunt 包
yarn add grunt
-
在当前文件夹下添加 gruntfile.js 文件
code gruntfile // grunt 的配置文件
// gruntfile.js // Grunt 的入口文件 // 用于定义一些需要 Grunt 自动执行的任务 // 需要导出一个函数 // 此函数接受一个 Grunt 的形参,内部提供一些创建任务时可以用到的 API module.exports = grunt => { grunt.registerTask('foo', 'a sample task', () => { console.log('hello grunt') }) grunt.registerTask('bar', () => { console.log('other task') }) // // default 是默认任务名称 // // 通过 grunt 执行时可以省略 // grunt.registerTask('default', () => { // console.log('default task') // }) // 第二个参数可以指定此任务的映射任务, // 这样执行 default 就相当于执行对应的任务 // 这里映射的任务会按顺序依次执行,不会同步执行 grunt.registerTask('default', ['foo', 'bar']) // 也可以在任务函数中执行其他任务 grunt.registerTask('run-other', () => { // foo 和 bar 会在当前任务执行完成过后自动依次执行 grunt.task.run('foo', 'bar') console.log('current task runing~') }) // 默认 grunt 采用同步模式编码 // 如果需要异步可以使用 this.async() 方法创建回调函数 // grunt.registerTask('async-task', () => { // setTimeout(() => { // console.log('async task working~') // }, 1000) // }) // 由于函数体中需要使用 this,所以这里不能使用箭头函数 grunt.registerTask('async-task', function () { const done = this.async() setTimeout(() => { console.log('async task working~') done() }, 1000) }) }
// 命令行输入 yarn grunt foo
2.Grunt 标记任务失败
module.exports = grunt => {
// 任务函数执行过程中如果返回 false
// 则意味着此任务执行失败
grunt.registerTask('bad', () => {
console.log('bad working~')
return false
})
grunt.registerTask('foo', () => {
console.log('foo working~')
})
grunt.registerTask('bar', () => {
console.log('bar working~')
})
// 如果一个任务列表中的某个任务执行失败
// 则后续任务默认不会运行
// 除非 grunt 运行时指定 --force 参数强制执行
grunt.registerTask('default', ['foo', 'bad', 'bar'])
// 异步函数中标记当前任务执行失败的方式是为回调函数指定一个 false 的实参
grunt.registerTask('bad-async', function () {
const done = this.async()
setTimeout(() => {
console.log('async task working~')
done(false)
}, 1000)
})
}
3.Grunt 的配置方法和多目标任务
module.exports = grunt => {
// 多目标模式,可以让任务根据配置形成多个子任务
// grunt.initConfig({
// build: {
// foo: 100,
// bar: '456'
// }
// })
// grunt.registerMultiTask('build', function () {
// console.log(`task: build, target: ${this.target}, data: ${this.data}`)
// })
grunt.initConfig({
build: {
options: {
msg: 'task options'
},
foo: {
options: {
msg: 'foo target options'
}
},
bar: '456'
}
})
grunt.registerMultiTask('build', function () {
console.log(this.options())
})
}
4.Grunt 插件的使用
module.exports = grunt => {
grunt.initConfig({
clean: {
temp: 'temp/**'
}
})
grunt.loadNpmTasks('grunt-contrib-clean')
}
- 下载包,loadNpmTasks 引用插件,配置直接使用
六、Gulp 自动化构建工具
1.Gulp的基本使用
-
初始化
yarn init --yes
-
安装 Gulp 包
yarn add gulp --dev
-
Gulpfile.js 文件
code gulpfile.js
// // 导出的函数都会作为 gulp 任务 // exports.foo = () => { // console.log('foo task working~') // } // gulp 的任务函数都是异步的 // 可以通过调用回调函数标识任务完成 exports.foo = done => { console.log('foo task working~') done() // 标识任务执行完成 } // default 是默认任务 // 在运行是可以省略任务名参数 exports.default = done => { console.log('default task working~') done() } // v4.0 之前需要通过 gulp.task() 方法注册任务 const gulp = require('gulp') gulp.task('bar', done => { console.log('bar task working~') done() })
命令行
yarn gulp foo
2.Gulp 组合任务
-
串行任务结构
const { series, parallel } = require('gulp') 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) } // 让多个任务按照顺序依次执行 exports.foo = series(task1, task2, task3) // 让多个任务同时执行 exports.bar = parallel(task1, task2, task3)
-
命令行
yarn gulp foo || npm run gulp foo // 执行任务foo yarn gulp bar || npm run gulp bar // 执行任务bar
3.Gulp 异步任务(三种方式)
-
回调函数
exports.callback = done => { console.log('callback task') done() } exports.callback_error = done => { console.log('callback task') done(new Error('task failed')) }
-
Promise
// promise exports.promise = () => { console.log('promise task') return Promise.resolve }
-
async await
exports.async = async () => { await timeout(1000) console.log('async task') }
4. Gulp 构建过程核心工作原理
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mizhm0gY-1620281845585)(D:\personal\大前端高薪训练营-拉钩\笔记\image-20210429093445966.png)]
-
代码
const fs = require('fs') const { Transform } = require('stream') exports.default = () => { // 文件读取流 const readStream = fs.createReadStream('normalize.css') // 文件写入流 const writeStream = fs.createWriteStream('normalize.min.css') // 文件转换流 const transformStream = new Transform({ // 核心转换过程 transform: (chunk, encoding, callback) => { const input = chunk.toString() const output = input.replace(/\s+/g, '').replace(/\/\*.+?\*\//g, '') callback(null, output) } }) return readStream .pipe(transformStream) // 转换 .pipe(writeStream) // 写入 }
-
命令行输入
yarn gulp // 得到压缩过后的文件
5. Gulp 文件操作 API + 插件的使用
-
安装插件引用
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')) }