1、
传统语言或语法的弊端:
无法使用模块化/组件化
通过机器去取代人的一些重复性工作
多人协作开发,无法硬性统一大家的代码风格,从仓库pull回来
部分功能需要等待后端服务接口提前完成
整体依赖后端项目(发布的时候)
2、
工程化表现
创建
编码 :统一代码风格
预览 :web/mock ;live/reloading/hmr ; source map
提交:git hook、lint-staged、持续集成
部署:CI/CD,自动发布
3、
工程化不是等于某个工具吗,工具只是我们用来落地实现,工程化则是一整个规划
一些成熟的工程化集成:create-react-app,vue-cli
4、
工程化是由node赋能的
脚手架工具
1、常用的脚手架工具
重点关注几个有代表性的工具
2、Yeoman
Yeo主要是一种通用的脚手架工具
3、基本使用
add yo
4、sub generator
yo node:cli
yarn link
5、常规使用步骤
明确你的需求
找到合适的generator
全局范围内安装generator
通过yo运行generator
通过命令行填写generator选项
生成所需的项目结构
yarn global add generator
6、自定义generator
基于yeoman搭建自己的脚手架
generator本质上就是npm模块
命名必须是generator-<name>
yarn add yeoman-generator 通过这条命令来添加
7、根据模板创建文件
8、接受用户的输入
// 此文件作为 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 //最后会被赋值到context当中
})
}
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)
}
}
9、plop
一个小而美的脚手架工具
会根据之前的配置自动创建文件
10、plop具体使用
将plop模块作为项目开发依赖
在项目根目录下创建一个plopfile.js文件
在plopfile.js文件中定义脚手架任务
编写用于生成特定类型文件的模板
通过plop提高的cli运行
10、脚手架工作原理
11、常用的自动化构建工具
grunt:最早的,构建速度较慢,因为其基于临时文件
gulp :构建速度较快
Fis:比较容易入手
12、grunt
使用grunt.registerTask来注册任务
(default,[foo,bar]) 依次执行
13、
使用return false ;done(false)来终止任务
14、initConfig设置,config(‘foo’)去取
15、多目标任务
grunt里配置build
grunt.initConfig({
build: {
options: {
msg: 'task options'
},
foo: {
options: {
msg: 'foo target options'
}
},
bar: '456'
}
})
16、grunt插件使用
module.exports = grunt => {
grunt.initConfig({
需要配置clean关键字
clean: {
temp: 'temp/**'
//找到temp下的所有子目录
}
})
grunt.loadNpmTasks('grunt-contrib-clean')
}
17、
const sass = require('sass')
const loadGruntTasks = require('load-grunt-tasks')
module.exports = grunt => {
grunt.initConfig({
sass: {
options: {
sourceMap: true, //生成sourcemap文件
implementation: sass //生成sass文件
},
main: {
files: {
'dist/css/main.css': 'src/scss/main.scss'
// 输出路径:输入路径
}
}
},
babel: {
options: {
sourceMap: true,
presets: ['@babel/preset-env']//preset-env默认根据最新的es进行转换
},
main: {
files: {
'dist/js/app.js': 'src/js/app.js'
}
}
},
watch: {
// grunt-contrib-watch插件
js: {
files: ['src/js/*.js'],//需要监视的文件
tasks: ['babel'] //需要执行什么任务
},
css: {
files: ['src/scss/*.scss'],//需要监视的文件
tasks: ['sass'] //需要执行sass任务
}
}
})
// grunt.loadNpmTasks('grunt-sass')
loadGruntTasks(grunt) // 自动加载所有的 grunt 插件中的任务
grunt.registerTask('default', ['sass', 'babel', 'watch'])
}
18、gulp基本使用
都是用yarn gulp 对应输出函数名
// // 导出的函数都会作为 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()
})
19、gulp组合任务
// 让多个任务按照顺序依次执行
exports.foo = series(task1, task2, task3)
// 让多个任务同时执行
exports.bar = parallel(task1, task2, task3)
20、gulp异步任务的三种方式
exports.promise_error = () => {
console.log('promise task')
return Promise.reject(new Error('task failed'))
}
使用promise
const timeout = time => {
return new Promise(resolve => {
setTimeout(resolve, time)
})
}
exports.async = async () => {
await timeout(1000)
console.log('async task')
}
使用async语法糖
exports.stream = () => {
const read = fs.createReadStream('yarn.lock')
const write = fs.createWriteStream('a.txt')
read.pipe(write)
return read
}
返回read,会等到read里的end事件触发的时候
21、gulp构建过程核心工作原理
// 文件读取流
const readStream = fs.createReadStream('normalize.css')
// 文件写入流
const writeStream = fs.createWriteStream('normalize.min.css')
// 文件转换流
const transformStream = new Transform({
// 核心转换过程
// chunk =》 读取流中读取到的内容
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) // 写入
22、gulp文件操作api和插件的使用
exports.default = () => {
return src('src/*.css')
.pipe(cleanCSS())
.pipe(rename({ extname: '.min.css' }))
.pipe(dest('dist'))
}
23、gulp脚本编译
const sass = require('gulp-sass')
const babel = require('gulp-babel')
const script = () => {
return src('src/assets/scripts/*.js', { base: 'src' })
.pipe(babel({ presets: ['@babel/preset-env'] }))
.pipe(dest('temp'))
}
24、自动化加载插件
const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins()
使用
plugins.sass({ outputStyle: 'expanded' })
25、开发服务器
const serve = () => {
//使用各种文件
watch('src/assets/styles/*.scss', style)
watch('src/assets/scripts/*.js', script)
watch('src/*.html', page)
// watch('src/assets/images/**', image)
// watch('src/assets/fonts/**', font)
// watch('public/**', extra)
watch([
'src/assets/images/**',
'src/assets/fonts/**',
'public/**'
], bs.reload)
//更新图片字体后,bs.reload会重新发起对于src,public地址下的请求推送到浏览器
bs.init({
notify: false, //关掉提示
port: 2080, //指定端口
// open: false, //自动打开浏览器
// files: 'dist/**', //监听对应的文件
server: {
baseDir: ['temp', 'src', 'public'],
//这样配置就可以依次请求,找不到就找下一个,这样比如图片、字体这些东西就不用每次都编译了
//baseDir: 'dist',//读取的地址为编译后的文件
routes: {
'/node_modules': 'node_modules'//先看routes里的配置,如果没有
}
}
})
}
26、文件引用处理
const useref = () => {
return src('temp/*.html', { base: 'temp' })
//文件操作,修改注释完成文件的复制与合并
.pipe(plugins.useref({ searchPath: ['temp', '.'] }))
// html js css
.pipe(plugins.if(/\.js$/, plugins.uglify()))
//需要先执行compile,因为useref执行后会删掉注释,所以执行compile标出注释
.pipe(plugins.if(/\.css$/, plugins.cleanCss()))
.pipe(plugins.if(/\.html$/, plugins.htmlmin({
collapseWhitespace: true, //去除换行符
minifyCSS: true, //sytle标签压缩
minifyJS: true
})))
.pipe(dest('dist'))
}
27、重构构建过程
// 上线之前执行的任务
const build = series(
clean,
parallel(
series(compile, useref),
image,
font,
extra
)
)
创建temp文件地址,平时compile都放到这里,最后通过useref放到dis
28、gulp补充
自动化构建案例
module.exports = {
clean,
build,
develop
}
其他的任务都是这些大任务里的子任务
29、解决模块中的问题
const cwd = process.cwd()
//读取文件中pages.config文件
try {
const loadConfig = require(`${cwd}/pages.config.js`)
config = Object.assign({}, config, loadConfig)
} catch (e) {}
30、
23、gulp脚本编译
const sass = require('gulp-sass')
const babel = require('gulp-babel')
const script = () => {
return src('src/assets/scripts/*.js', { base: 'src' })
.pipe(babel({ presets: ['@babel/preset-env'] }))
.pipe(dest('temp'))
}
24、自动化加载插件
const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins()
使用
plugins.sass({ outputStyle: 'expanded' })
25、开发服务器
const serve = () => {
//使用各种文件
watch('src/assets/styles/*.scss', style)
watch('src/assets/scripts/*.js', script)
watch('src/*.html', page)
// watch('src/assets/images/**', image)
// watch('src/assets/fonts/**', font)
// watch('public/**', extra)
watch([
'src/assets/images/**',
'src/assets/fonts/**',
'public/**'
], bs.reload)
//更新图片字体后,bs.reload会重新发起对于src,public地址下的请求推送到浏览器
bs.init({
notify: false, //关掉提示
port: 2080, //指定端口
// open: false, //自动打开浏览器
// files: 'dist/**', //监听对应的文件
server: {
baseDir: ['temp', 'src', 'public'],
//这样配置就可以依次请求,找不到就找下一个,这样比如图片、字体这些东西就不用每次都编译了
//baseDir: 'dist',//读取的地址为编译后的文件
routes: {
'/node_modules': 'node_modules'//先看routes里的配置,如果没有
}
}
})
}
26、文件引用处理
const useref = () => {
return src('temp/*.html', { base: 'temp' })
//文件操作,修改注释完成文件的复制与合并
.pipe(plugins.useref({ searchPath: ['temp', '.'] }))
// html js css
.pipe(plugins.if(/\.js$/, plugins.uglify()))
//需要先执行compile,因为useref执行后会删掉注释,所以执行compile标出注释
.pipe(plugins.if(/\.css$/, plugins.cleanCss()))
.pipe(plugins.if(/\.html$/, plugins.htmlmin({
collapseWhitespace: true, //去除换行符
minifyCSS: true, //sytle标签压缩
minifyJS: true
})))
.pipe(dest('dist'))
}
27、重构构建过程
// 上线之前执行的任务
const build = series(
clean,
parallel(
series(compile, useref),
image,
font,
extra
)
)
创建temp文件地址,平时compile都放到这里,最后通过useref放到dis
28、gulp补充
自动化构建案例
module.exports = {
clean,
build,
develop
}
其他的任务都是这些大任务里的子任务
29、解决模块中的问题
const cwd = process.cwd()
//读取文件中pages.config文件
try {
const loadConfig = require(${cwd}/pages.config.js
)
config = Object.assign({}, config, loadConfig)
} catch (e) {}
30、gulp源文件监听更新视图
const {watch} = reqiure(‘gulp’)
在serve的bs.init上插入下面代码
watch([需要编译的所有css文件], [编译css的命令如minicss])
watch([需要压缩的所有图片,字体,其他文件], bs.reload) bs.reload用于更新,没有编译或压缩
31、gulp文件引用处理
yarn add gulp-useref --dev
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。