前端工程化实战
前端工程化实战
工程化概述
1.工程化的定义和主要解决的问题
- 传统语言或语法的弊端
- 无法使用模块化。组件化
- 重复的机械工作
- 代码风格的统一,质量保证
- 依赖后端服务接口的支持
- 整体依赖后端项目
2.一个项目过程工程化的表现
一切重复的工作都应该被自动化
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JlvxiaGI-1610480594072)(C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\1608718394556.png)]
- 创建项目
- 创建项目结构
- 创建特定类型文件
- 编码
- 格式化代码
- 校验代码风格
- 编译构建和打包
- 预览和测试
- webServer/Mock
- live Reloading/HMR
- Source Map
- 提交
- git hooks
- lint-staged
- 持续集成
- 部署
- CI/CD
- 自动发布
3.工程化不等于工具
工程化=/=某个工具
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tfCa5zQ3-1610480594074)(C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\1608718866374.png)]
规划项目架构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JJY3jGI8-1610480594075)(C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\1608718921517.png)]
官方给出的集成式项目解决方案
4.工程化与NodeJS
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XP7LE8im-1610480594076)(C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\1608719022782.png)]
- 脚手架工具的开发
- 自动化构建系统
- 模块化打包
- 项目代码规范化
- 自动化部署
脚手架工具
1.脚手架工具概要
- 脚手架的本质作用—创建项目结构,提供项目规范和约定
- 相同的组织结构,相同的开发范式,相同的模块依赖,相同的工具配置,相同的基础代码
2.常用的脚手架工具
- react create-react-app
- vue vue-cli
- angular angular-cli
- Yeoman
- Plop
3.Yeoman简介
Yeoman是一个通用的现代脚手架工具
可以定制属于自己的前端脚手架
4.Yeoman的基础使用
-
安装前需要安装Node
-
$ yarn global add yo //全局范围安装yo $ yarn global add generator-node//安装对应的generator $ yo node // 运行generator
5.Sub Generrator
一些淘宝镜像源
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bXvW2xkj-1610480594077)(C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\1608722114871.png)]
yo node:cli
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zmQoNqHW-1610480594077)(C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\1608721932495.png)]
6.自定义 Generator(基于Yeoman搭建自己的脚手架)
-
创建Generator模块,本质上是创建NPM模块
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-450Ho4BK-1610480594078)(C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\1608722402287.png)]
-
模块名必须是generator-
-
步骤
-
创建模块文件夹 mkdir generator-sample
-
进入模块文件夹:cd generator-sample
-
yarn-init
-
yarn add yeoman-generator// 方便创建生成器
-
在indexjs 是Generator的核心入口,需要继承 yeoman Generator
-
写代码
const Generator=require('yeoman-generator') module.exports=class extends Generator{this.fs.write(this.destinationPath('temp.txt'),Math.random().toString()) } -
yarn link // 链接到全局范围
-
yo sample
-
8.根据模板创建文件
-
在app文件夹下创建一个文件夹模板
-
在index.js文件夹中
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)
9.接受用户输入
-
使用基类的prompting()
-
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})}
10.Vue-Generatal示例
- 1.新建一个Vue的Generatal的示例
- 2.将Vue基础的脚手架替换为模板
- 如果遇见<%xxx%>这种字段需要在前添加%号
- 3.在index.js遍历每个文件并生成到输出目录下
11.发布一个Generatal模块
12.Plop简介
自动化构建
1.自动化 构建的简介
- 自动化构建 ,源代码 变成生产环境的代码
- 将一些不被支持的特性转换为可以支持的
2.初步认识自动化构建
3.常用的自动化构建工具
-
grunt
构建速度相对较慢
-
Gulp
同时执行多任务
在内存中读写-块
-
FIS
初学者比较适
4.Grunt 的基本使用
-
$ yarn --init code gruntfile.js // 添加Grunt的入口 文件
5.Grunt标记任务失败
- 使用renturn false
- 前面的任务执行了 后面任务默认不执行
- –force 在终端输入可以让所有执行
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)})
}
6.Grunt 配置选项方法
module.exports = grunt => {// grunt.initConfig() 用于为任务添加一些配置选项grunt.initConfig({// 键一般对应任务的名称// 值可以是任意类型的数据foo: {bar: 'baz'}})grunt.registerTask('foo', () => {// 任务中可以使用 grunt.config() 获取配置console.log(grunt.config('foo'))// 如果属性值是对象的话,config 中可以使用点的方式定位对象中属性的值console.log(grunt.config('foo.bar'))})
}
7.Grunt多目标任务
8.Grunt插件的使用
//1.使用npm安装插件
//2.GruntFile文件中grunt.loadNpmTasks('插件名')
module.exports = grunt => {grunt.initConfig({clean: {temp: 'temp/**'}})grunt.loadNpmTasks('grunt-contrib-clean')
}
9.Grunt常用的插件
// grunt-babel
// grunt-contrib-watch
//grunt-sass
//load-grunt-task
//sass
const sass = require('sass')
const loadGruntTasks = require('load-grunt-tasks')module.exports = grunt => {grunt.initConfig({sass: {options: {sourceMap: true,implementation: sass},main: {files: {'dist/css/main.css': 'src/scss/main.scss'}}},babel: {options: {sourceMap: true,presets: ['@babel/preset-env']},main: {files: {'dist/js/app.js': 'src/js/app.js'}}},watch: {js: {files: ['src/js/*.js'],tasks: ['babel']},css: {files: ['src/scss/*.scss'],tasks: ['sass']}}})// grunt.loadNpmTasks('grunt-sass')loadGruntTasks(grunt) // 自动加载所有的 grunt 插件中的任务grunt.registerTask('default', ['sass', 'babel', 'watch']) //
}
Gulp基本使用—高效 易用
-
安装依赖
-
yarn init --yes yarn add gulp --dev 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() })
Gulp的组合任务
-
series串行任务
-
parallel 同步任务
-
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)
Gulp异步任务的三种方式
-
通过回调函数解决—错误优先的标准
-
Promise的方案
-
Async await
-
stream
-
const fs = require('fs')exports.callback = done => {console.log('callback task')done() }exports.callback_error = done => {console.log('callback task')done(new Error('task failed')) }exports.promise = () => {console.log('promise task')return Promise.resolve() }exports.promise_error = () => {console.log('promise task')return Promise.reject(new Error('task failed')) }const timeout = time => {return new Promise(resolve => {setTimeout(resolve, time)}) }exports.async = async () => {await timeout(1000)console.log('async task') }exports.stream = () => {const read = fs.createReadStream('yarn.lock')const write = fs.createWriteStream('a.txt')read.pipe(write)return read }// exports.stream = done => { // const read = fs.createReadStream('yarn.lock') // const write = fs.createWriteStream('a.txt') // read.pipe(write) // read.on('end', () => { // done() // }) // }
Gulp构建过程核心工作原理
读文件–改变文件—写文件
基于Stream的流读取
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) // 写入
}
Gulp文件操作API
一些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'))
}
Gulp样式编译
const style = () => {return src('src/assets/styles/*scss', { base: "src" }).pipe(sass({ outputStyle: 'expanded' })).pipe(dest('dist'))
}
Gulp脚本编译
const script = () => {return src("src/assets/scripts/*js", { base: "src" }).pipe(babel({ presets: ['@babel/preset-env'] })).pipe(dest('dist'))
}
Gulp案例 图片和字体转换
const image = () => {return src("src/assets/images/**", { base: "src" }).pipe(plugins.imagemin()).pipe(dest('dist'))
}const font = () => {return src("src/assets/fonts/**", { base: "src" }).pipe(plugins.imagemin()).pipe(dest('dist'))
}
Gulp其他文件及文件清除
const extra = () => {return src('public', { base: 'src' }).pipe(dest('dist'))
}const clean = () => {return del(['dist'])
}
Gulp自动加载插件
-
const loadPlugins = require('gulp-load-plugins') const plugins = loadPlugins()// const plugins.sass = require('gulp-sass')// const plugins.babel = require('gulp-babel')// const plugins.swig = require('gulp-swig')// const plugins.imagemin = require('gulp-imagemin') -
插件名就是其成员
Gulp开发服务器
使用browser-sync安装的
const serve = () => {bs.init({notify: false,port: 2000,files: 'dist/**',// open: false,server: {baseDir: 'dist',routes: { //处理请求'/node_modules': 'node_modules'}}})
}
Gulp监视变化以及构建变化
const serve = () => {watch('src/assets/styles/*scss', style)watch('src/assets/scripts/*js', script)watch('src/*.html', html)bs.init({notify: false,port: 2000,files: 'dist/**',// open: false,server: {baseDir: 'dist',routes: { //处理请求'/node_modules': 'node_modules'}}})
}
Gulpuserf文件引用处理
const useref = () => {return src('dist/*html', { base: 'dist' }).pipe(plugins.useref({ searchPath: ['dist', '.'] })).pipe(dest('dist'))
}
Gulp案例文件压缩
const useref = () => {return src('dist/*html', { base: 'dist' }).pipe(plugins.useref({ searchPath: ['dist', '.'] })).pipe(plugins.if(/\.js$/, plugins.uglify())).pipe(plugins.if(/\.css$/, plugins.cleanCss())).pipe(plugins.if(/\.html$/, plugins.htmlmin({collapseWhitespace: true,minifyCss: true,minifyJS: true}))).pipe(dest('release'))
}
Gulp重新构建规划过程
// 实现这个项目的构建任务
// 实现步骤
/*** 1.样式编译 * 安装gulp-sass 并引入,sass会默认任务带下划线的被引入* outputStyle: 'expanded' 样式完全展开* 2.脚本编译* 安装 @babel/core @babel/preset-env gulp-babel* 3.模板文件编译* 安装 yarn add gulp-swig* 4.图片和字体的转换(压缩文件)* 安装 gulp-imagemin* 5.文件清除和其他 文件* 6.自动加载插件* 最新版的imagemin 无法自动加载* 7,热更新开发服务器* 安装browser-sync ,使用watch监听文件变化* 8.useref插件* gulp-useref差距* 9.压缩html js css* gulp-htmlmin gulp-uglify gulp-clean-css --dev* gulp-if*/
const { src, dest, parallel, series } = require('gulp')
const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins()// const plugins.sass = require('gulp-sass')// const plugins.babel = require('gulp-babel')// const plugins.swig = require('gulp-swig')// const plugins.imagemin = require('gulp-imagemin')
const del = require('del')
const browserSync = require('browser-sync')
const bs = browserSync.create()const data = {menus: [{name: 'Home',icon: 'aperture',link: 'index.html'},{name: 'About',link: 'about.html'},{name: 'Contact',link: '#',children: [{name: 'Twitter',link: 'https://twitter.com/w_zce'},{name: 'About',link: 'https://weibo.com/zceme'},{name: 'divider'},{name: 'About',link: 'https://github.com/zce'}]}],pkg: require('./package.json'),date: new Date()
}
const style = () => {return src('src/assets/styles/*scss', { base: "src" }).pipe(plugins.sass({ outputStyle: 'expanded' })).pipe(dest('temp'))
}const script = () => {return src("src/assets/scripts/*js", { base: "src" }).pipe(plugins.babel({ presets: ['@babel/preset-env'] })).pipe(dest('temp'))
}const html = () => {return src("src/*.html", { base: "src" }).pipe(plugins.swig({ data })).pipe(dest('temp'))
}const image = () => {return src("src/assets/images/**", { base: "src" }).pipe(plugins.imagemin()).pipe(dest('dist'))
}const font = () => {return src("src/assets/fonts/**", { base: "src" }).pipe(plugins.imagemin()).pipe(dest('dist'))
}const extra = () => {return src('public/**', { base: 'public' }).pipe(dest('dist'))
}const clean = () => {return del(['dist', 'temp'])
}const serve = () => {watch('src/assets/styles/*scss', style)watch('src/assets/scripts/*js', script)watch('src/*.html', html)watch(["src/assets/fonts/**","src/assets/images/**",'public/**'], bs.reload)bs.init({notify: false,port: 2000,files: 'dist/**',// open: false,server: {baseDir: ['temp', 'src', 'public'],routes: { //处理请求'/node_modules': 'node_modules'}}})
}const useref = () => {return src('temp/*html', { base: 'temp' }).pipe(plugins.useref({ searchPath: ['temp', '.'] })).pipe(plugins.if(/\.js$/, plugins.uglify())).pipe(plugins.if(/\.css$/, plugins.cleanCss())).pipe(plugins.if(/\.html$/, plugins.htmlmin({collapseWhitespace: true,minifyCss: true,minifyJS: true}))).pipe(dest('dist'))
}const compile = parallel(style, script, html)const build = series(clean,parallel(series(compile, useref),image,font,extra))const dev = series(compile, serve)// const page
module.exports = {compile,build,dev,serve,clean
}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
