共计 6275 个字符,预计需要花费 16 分钟才能阅读完成。
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) {}