- 本阶段主要以前端工程化为主题,分别从脚手架工具、自动化构建、模块化开发、规范化标准四个维度介绍前端工程化具体该如何落地、如何实践,以此应对复杂前端应用的开发和维护过程,提高开发者的工作效率,降低项目维护成本,从而更好地适应大前端时代下的前端开发工作。
模块一 开发脚手架及封装自动化构建工作流
- 此模块中会先带你了解什么是前端工程化,以及前端工程化和工具之间的关系;紧接着在脚手架工具的学习中你可以了解到脚手架的本质、工作原理,以及自己从无到有搭建一个自己的脚手架工具;最后我们会介绍几种常见的自动化构建工具的使用和扩展方式,通过使用自动化构建工具,可以大大提高你的开发效率。
任务一:工程化概述
- 工程化定义和主要解决的问题
- 想要使用ES6+新特性,兼容有问题
- 想要使用Less/Sass/PostCSS增强css的编程性,但运行环境不能直接支持
- 想要使用模块化的方式提高项目的可维护性,但运行环境不能直接支持
- 部署上线前需要手动压缩代码及资源文件,部署过程需要手动上传代码到服务器
- 多人协作开发,无法硬性统一大家的代码风格,从仓库中pull回来的代码质量无法保证
- 部分功能开发时需要等待后段服务接口提前完成
- 主要解决的问题
- 传统语言或语法的弊端
- 无法使用模块化,组件化
- 重复的机械式劳动
- 代码风格统一、质量保证
- 依赖后端服务接口支持
- 整体依赖后端项目
- 一个项目过程中工程化的表现
- 一切以提高效率、降低成本、质量保证为目的的手段都属于工程化
- 创建项目: 创建项目结构,创建特定类型文件
- 编码: 格式化代码,效验代码风格,编译/构建/打包
- 预览/测试: Web Server / Mock;Live Reloading/HMR;Source Map
- 提交: Git Hooks Lint-staged 持续集成
- 部署:CI/CD 自动发布
-
工程化不等于工具
-
工程化与Node.js
- 内容概述
- 脚手架工具开发
- 自动化构建系统
- 模块化打包
- 项目代码规范化
- 自动化部署
任务二:脚手架工具
- 脚手架工具概要
- 脚手架的本质工作:创建项目的基础结构、提供项目规范和约定
- 相同的组织结构
- 相同的开发规范
- 相同的模块依赖
- 相同的工具配置
- 相同的基础代码
- 内容概述
- 脚手架的作用
- 常用的脚手架工具
- 通用脚手架工具剖析
- 开发一款脚手架
- 常用脚手架工具
- React项目 create-react-app
- Vue项目 vue-cli
- Angular项目 angular-cli
- Yeoman 通用型脚手架
- Plop 在项目中创建一个组件/模块所需要的文件
- Yeoman 简介
- 用于创建现代化应用的脚手架工具
- yeoman.io
- Yeoman 基本使用
- 在全局范围安装yo
- npm install yo --blobal
- 安装对应的generator
- npm install generator-node --globel
- 通过yo运行generator
- mkdir 项目名称
- yo node
- yarn global add yo
- yarn global add generator-
- yo node
- MIT
- Sub Generator
- generator-node下子集生成器,cli,eslink等基础配置生成
- yo node:cli
- Yeoman 使用步骤总结
- 明确你的需求
- 在官网找到合适的Generator yeoman.io
- 全局范围安装找到的Generator
- 通过Yo运行对应的Geneartor
- 通过命令行交互填写选项
- 生成你所需要的项目结构
-
自定义Geneartor
-
创建Geneartor模块
- Geneartor 本质上就是一个mpm模块
- Generator 基本结构
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NM1sD2AD-1625144115392)(…/img/1624872808800.jpg)]
- 名字必须是generator-
- 创建一个生成器
- mkdir generator-
- yarn init
- yarn add yeoman-gengrator
- 在该文件目录下创建 geneartors - app - index.js
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0U2wnnhH-1625144115394)(…/img/1624873313308.jpg)]
- yarn link (链接到全局范围,使之成为一个全局模块包)
- yo sample(生成器名字)
-
根据模版创建文件
- 相对于手动创建每一个文件,模版的方式大大提高了效率
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2ZwsuyUs-1625144115395)(…/img/1624873564691.jpg)]
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kmV9zYaz-1625144115397)(…/img/1624873643530.jpg)]
- 接受用户的数据
- 在命令行获取的数据可以挂载到this.answers属性上,在writing 的时候使用
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CeuXtzRv-1625144115398)(…/img/1624873895102.jpg)]
- Vue Generator 案例
- mkdir geneartor-my-vue
- cd geneartor-my-vue
- yarn init
- yarn add yeoman-generator
- 在该文件目录下创建 generators - app - index.js
- index.js > writing > var tepmlates = [文件名];
tepmlates.forEach(item => { this.fs.copyTpl( this.tamplatePath(item), this.destiantionPath(item), this.answers ) })
- index.js > writing > var tepmlates = [文件名];
- 在app下创建 templates,放入需要初始化的模版,如vue项目的初始结构
- <%%=name%> 多加一个%,EJS就会被转义,不会去替换当前的name
- 发布Geneartor
- echo node_modules > .gitignore
- git init
- git state
- git add
- git commit -m “”
- 打开gihub创建一个空仓库
- git remote add origin 远程仓库地址
- git git push -u origin master
- yarn publish (发布)
- 如果是淘宝镜像,需要修改为官方镜像(yarn镜像和npm镜像是保持同步的)
- 可以添加一个 yeoman-generator 关键词,就会被yeoman官方收录
- Plop 一个小而美的脚手架工具
- 在项目中使用,比如创建一个footer组件,可以直接初始化.css.js 等多个文件,以及文件内默认的编码
- yarn plop component
- Plop 的具体使用
- yarn add plop --dev
- 在项目根目录下新建 plopfile.js
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YgKbNeU5-1625144115399)(…/img/1624876363683.jpg)]
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fuaqWv6P-1625144115400)(…/img/1624876466714.jpg)]
- yarn plop component (生成器名字)
- 总结
- 将plop模块作为项目开发依赖安装
- 在项目根目录下创建一个plopfile.js 文件
- 在plopfile.js文件中定义脚手架任务
- 编写用于生成特定类型文件的模版
- 通过Plop提供的cli运行脚手架任务
- 脚手架的工作原理
- 创建脚手架工具,就是创建一个 node-cli 应用
- mkdir sample-scaffolding
- cd sample-scaffolding
- yarn init
- package.json > “bin”: ‘cli.js’
- yarn link (关联到全局)
- sample-scaffolding (执行这个命令)
- yarn add inquirer (命令行询问的包)
- yarn add ejs (模版引擎)
- cli文件头部需要该注释 #!/usr/bin/env node
- sudo chmod -R 750 sample-scaffolding mac打开权限
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-glGGoKB2-1625144115400)(…/img/1624877914800.jpg)]
任务二:自动化构建
- 自动化构建简介
- 源代码》自动化构建》生产代码
- 自动化构建工作流 使用提高效率的语法、规范和标准
- 自动化构建初体验
- NPM Scripts 实现自动化构建工作流的最简方式,解决一些简单的构建任务
- 使用sass
- yarn add sass --dev
- ./node_modules/.bin/sass (打印帮助信息)
- ./node_modules/.bin/sass 输入路径 输出路径
- package.json> “scripts”: {“build”: “sass scss/main.scss css/style.css” }
- yarn add browser-sync --dev (启动一个测试服务器)
- preserve serve执行前自动调用的钩子函数
- –watch 监控sass文件,有改变则重新编译
- package.json> “scripts”: {“build”: “sass scss/main.scss css/style.css --watch”,“preserve”:“yarn build” “serve”: “browser-sync .” }
- yarn add npm-run-all --dev (同时执行多个命令行)
- –files “css/*.css” 监控文件变化,有变化直接更新到浏览器
- package.json> “scripts”: {“build”: “sass scss/main.scss css/style.css --watch”, “serve”: “browser-sync . --files “css/*.css””, “start”: “run-p build serve” }
- Permission denied: sudo chmod -R 750 某一目录
- 常用的自动化构建工具
- Grunt Gulp FIS 通过调用插件构建
- Grunt 插件生态非常完善,工作过程基于临时文件实现,构建过程比较慢,例如对sass文件做编译操作:添加私有属性操作,代码压缩等,每一步都会有磁盘读写操作,sass文件在编译完成过后就会将结果写入一个临时文件,下一个插件再去读取这个临时文件,处理的环节越多,读写临时文件的次数越多,对于超大型项目,文件很多,构建速度就会很慢
- Gulp 解决了Grunt构建速度慢的问题,因为它是基于内存实现的,对文件的处理环节都是在内存中完成的,相对于磁盘读写,速度就快了很多。默认支持同时去执行多个任务,效率大大提高,使用方式,相对于Grunt更加的直观易懂,插件生态也同样完善,后来居上,更受欢迎,市面上最流行的前端构建系统
- FIS 百度前端团队推出的开源项目,微内核的特点,更像是一种捆绑套餐,它把我们在项目中一些典型的需求都集成在内部了,例如我们在FIS中就能很轻松的处理资源加载,模块化开发,代码部署,性能优化,大而全,在国内很多项目中流行开了。
- webpack 模块打包工具
- 构建工具小结
- 如果是初学者,FIS可能更适合,但是要求灵活多变,Grent,Gulp是更好的选择,新手需要规则,老手渴望自由
- Grunt 的基本使用
- yarn init --yes
- yarn add grunt
- yarn grunt 任务名称
- grunt默认支持同步模式,如果需要执行异步任务,需要 this.async()标记
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pr5pXnq7-1625144115401)(…/img/1625018085405.jpg)]
- 异步任务不能使用箭头函数,default后面配置一个数组,默认执行多个任务
- Grunt 标记任务失败
- 通过在任务中 reture false 标记任务失败,如果这个任务是在一个任务列表中,这个任务失败会导致后续的任务都不执行
- 可以通过强制方式执行后续的任务: yarn grunt default --force
- 异步任务可以通过 done(false) 指定一个实参就可以标记失败
- Grunt 的配置方法
- 比如需要压缩文件,可以通过配置initConfig配置压缩路径
grunt.initConfig({
foo: {
bar: 123
}
})
grunt.registerTask('foo', () => {
console.log(grunt.config('foo.bar'))
})
- Grunt 多目标任务
- 可以理解为子任务的形式
- yarn grunt build:css 运行指定目标
- 通过this.target 拿到目标名字,this.data拿到目标配置数据
- options 会作为这个任务的配置属性出现
- 目标如果是一个对象,可以配置options,目标中的options会覆盖上一级任务中的options
grunt.initConfig({
build: {
options: {
foo: 'bar'
},
css: {
options: {
foo: 'baz'
}
},
js: '2'
}
})
// 多目标任务,可以让任务根据配置形成多个子任务
grunt.registerMultiTask('build', function() {
console.log(this.options())
console.log(`target: ${this.target}, data: ${this.data}`)
})
- Grunt 插件的使用
- 先npm安装这个插件,然后在gruntfile中载入这个插件
- yarn add grunt-contrib-clean 清除项目中多余的文件
grunt.initConfig({
clean: {
temp: 'temp/**' // 清除temp下所有文件
}
})
grunt.loadNpmTask('grunt-contrib-clean')
- yarn grunt clean
- Grunt 常见插件及总结
- sass最早出来就叫这个,但是语法规范不太容易被接受,后来又出了个新的语法规范,拓展名就叫scss
- yarn add grunt-sass sass --dev (grunt官方也提供了sass插件,但依赖sass环境,安装比较麻烦,所以安装依赖npm的sass)
- yarn add grunt-babel @babel/core @babel/preset-env --dev (ECMAScript最新特性转换)
- yarn add load-grunt-tasks --dev (一次加载多个插件任务)
- yarn grunt babel
- yarn add grunt-contrib-watch --dev (需要监视文件修改后重新执行任务)
- yarn grunt watch
- gruntfile.js
let sass = require('sass')
let 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: {
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 add gulp --dev
- yarn gulp foo (任务名称)
- gulp约定每一个任务都是异步任务,当任务完成后,需要执行回调函数
- gulpfile.js
// gulp 的入口文件
exports.foo = done => {
console.log('foo task working')
done() // 标识任务完成
}
exports.default = done => {
console.log('default task working')
done()
}
const gulp = require('gulp') // gulp 4.0以前使用 这种方式
gulp.task('bar', done => {
console.log('bar working')
done()
})
- Gulp 的组合任务
// 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) // 串行执行任务 yarn gulp foo
exports.bar = parallel(task1, task2, task3) // 并行执行任务
- Gulp 的异步任务
// gulp 的入口文件
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('promsie 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 readStream = fs.createReadStream('package.json')
// const writeStream = fs.createWriteStream('temp.txt')
// readStream.pipe(writeStream)
// return readStream
// }
exports.stream = done => {
const readStream = fs.createReadStream('package.json')
const writeStream = fs.createWriteStream('temp.txt')
readStream.pipe(writeStream)
readStream.on('end', () => { // gulp 注册了stream的end事件
done()
})
}
- Gulp 构建过程核心工作原理
- 输入(读取流)》 加工(转换流)》输出(写入流)
- The streaming build system
const fs = require('fs')
const {Transform} = require('stream')
exports.default = () => {
// 文件读取流
const read = fs.createReadStream('normalize.css')
// 文件写入流
const write = fs.createWriteStream('normalize.min.css')
// 文件转换流
const transform = new Transform({
// 核心转换过程实现
// chunk =》 读取流中读取到的内容 (Buffer)
transform: (chunk, encoding, callback) => {
const input = chunk.toString()
const output = input.replace(/\s+/g, '').replace(/\/\*.+?\*\//g, '')
callback(null, output)
}
})
// 把读取出来的文件流导入写入文件流
read
.pipe(transform) // 转换
.pipe(write) // 写入
return read // 返回文件流对象,让gulp注册结束事件
}
- Gulp 文件操作API
- yarn add gulp-clean-css --dev (css压缩)
- yarn add gulp-rename --dev (重新命名)
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 案例 - 样式编译
- git clone https://github.com/zce/zce-gulp-demo.git
- yarn add gulp-sass --dev
- Gulp 案例 - 脚本编译
- yarn add gulp-babel --dev
- yarn add @babel/core @babel/preset-env --dev
- Gulp 案例 - 页面模版编译
- yarn add gulp-swig --dev (模版转换引擎)
- Gulp 案例 - 图片和文字文件转换
- yarn add gulp-imagemin --dev (img图片压缩,也可以压缩svg的字体文件,如果不能处理,就不会处理,无损压缩)
- Gulp 案例 - 其它文件及文件清除
- yarn add del --dev
- 自动加载插件
- yarn add gulp-load-plugins --dev
- Gulp 案例 - 热更新开发服务器
- dist 下文件更新则同步到浏览器
- yarn add browser-sync --dev
const browserSync = require('browser-sync')
const bs = browserSync.create() // 创建一个开发服务器
const server = () => {
bs.init({
notify: false, // 是否现实加载中的动画
port: 2090,
files: 'dist/**', // 监控文件修改则更新到浏览器
server: {
baseDir: 'dist',
routes: {
'/node_modules': 'node_modules' // 优先级高于baseDir
}
}
})
}
- Gulp 案例 - 监视变化以及构建优化
- 在开发阶段不构建css,font,img等,减少性能消耗
- Gulp 案例 - useref 文件引用处理
- 处理css,js引用,会做压缩,会把构建注释中的js,css多个合成一个
const useref = () => {
return src('dist/*.html', {base: 'dist'})
.pipe(plgins.useref({searchPath: ['dist', '.']}))
.pipe(dest('dist'))
}
// <!-- build:js assets/scripts/vendor.js -->
// <script src="/node_modules/jquery/dist/jquery.js"></script>
// <script src="/node_modules/popper.js/dist/umd/popper.js"></script>
// <script src="/node_modules/bootstrap/dist/js/bootstrap.js"></script>
// <!-- endbuild -->
// 合成
// <script src="assets/scripts/vendor.js"></script>
- yarn add gulp-useref --dev
- Gulp 案例 - 文件压缩
- yarn add gulp-htmlmin gulp-yglify gulp-clean-css --dev
- yarn add gulp-if --dev (判断文件的类型)
- Gulp 案例 - 重新规划构建过程
- 影响到useref的文件先放在temp 临时目录中,比如css,js,html。
const {src, dest, parallel, series, watch} = require('gulp')
const del = require('del')
const browserSync = require('browser-sync')
const bs = browserSync.create() // 创建一个开发服务器
const loadPlugins = require('gulp-load-plugins')
const plgins = loadPlugins()
// const sass = require('gulp-sass')
// const babel = require('gulp-babel')
// const swig = require('gulp-swig')
// const imagemin = require('gulp-imagemin')
const data = { // 初始化模版需要的数据
meuns: [],
pkg: require('./package.json'),
date: new Date()
}
const clean = () => {
return del(['dist', 'temp'])
}
const style = () => {
return src('src/assets/styles/*.scss', {base: 'src'}) // 指定路径
.pipe(plgins.sass({outputStyle: 'expanded'})) // 指定编译后的样式
.pipe(dest('temp'))
.pipe(bs.reload({stream: true})) // 也能更新
}
const script = () => {
return src('src/assets/scripts/*.js', {base: 'src'})
.pipe(plgins.babel({presets: ['@babel/preset-env']}))
.pipe(dest('temp'))
.pipe(bs.reload({stream: true})) // 也能更新,把文件流的信息推到浏览器
}
const page = () => {
return src('src/*.html', {base: 'src'})
.pipe(plgins.swig({data, defaults: { cache: false }})) // 解决调试是模板缓存不更新的问题 , defaults: { cache: false }
.pipe(dest('temp'))
.pipe(bs.reload({stream: true})) // 也能更新
}
const img = ()=> {
return src('src/assets/images/**', {base: 'src'})
.pipe(plgins.imagemin({stream: true}))
.pipe(dest('dist'))
}
const font = ()=> {
return src('src/assets/fonts/**', {base: 'src'})
.pipe(plgins.imagemin())
.pipe(dest('dist'))
}
const extra = () => {
return src('public/**', {base: 'public'})
.pipe(dest('dist'))
}
const serve = () => {
watch('src/assets/styles/*.scs', style) // 发现修改的文件,则构建当前文件
watch('src/assets/scripts/*.js', script)
watch('src/*.html', page)
// watch('src/assets/images/**', img)
// watch('src/assets/fonts/**',font)
// watch('public/**', extra)
watch([
'src/assets/images/**',
'src/assets/fonts/**',
'public/**'
], bs.reload) // 开发阶段不需要每次都压缩,比较消耗性能
bs.init({
notify: false, // 是否现实加载中的动画
port: 2090,
// files: 'dist/**', // 监控文件修改则更新到浏览器 和.pipe(bs.reload({stream: true})) 选一个
server: {
baseDir: ['temp', 'src', 'public'],
routes: {
'/node_modules': 'node_modules' // 优先级高于baseDir
}
}
})
}
const useref = () => {
return src('temp/*.html', {base: 'temp'})
.pipe(plgins.useref({searchPath: ['temp', '.']}))
.pipe(plgins.if(/\.js$/, plgins.uglify()))
.pipe(plgins.if(/\.css$/, plgins.cleanCss()))
.pipe(plgins.if(/\.html$/, plgins.htmlmin({
collapseWhitespace: true, // 去掉html回撤空格
minfyCSS: true, // 去掉html中css空格
minfyJS: true // 去掉html 中 js空格
})))
.pipe(dest('dist')) // temp 临时目录,是解决压缩时同一目录下读写容易冲突
}
const compile = parallel(style, script, page)
const build = series(clean, parallel(series(compile, useref), extra, img, font))
const develop = series(compile, serve)
module.exports = {
clean,
build,
develop
}
- Gulp 案例 - 补充
- 选择要暴露的任务,配置在package.json scripts中
// "scripts": {
// "clean": "gulp clean",
// "build": "gulp build",
// "develop": "gulp develop"
// },
- 在.gitignore 中配置需要忽略的文件,如temp,dist等
- 封装工作流 - 准备
- 如果单纯的把Gulp案例中写的工作流demo复制到新项目中,可能出现包的版本不对,而且散落在各个项目中,一旦出现问题,或者要升级,要同时维护多个项目中的gulpfile
- 在github上新建一个仓库
- yarn global add caz
- caz nm zce-pages
- cd zce-pages
- git init
- git remote origin git地址
- git add .
- git commit -m ‘’
- git push -u origin master (-u以流的方式往上推)
- 把Gulp案例中的gulpfile 复制到lib index中,Gulp devDependencies 中依赖复制到构建流项目dependencies
- 封装工作流 - 提取 gulpfile
- code . -a (可以在同一个vscode中打开两个项目)
- yarn link “zce-pages” (先在构建项目中执行,然后再在新项目中执行,如果发布了npm包,直接用npm包)
- 在新项目中 gulpfile.js module.exports = require(‘zce-pages’) (构建流项目)
- yarn add gulp-cli --dev
- yarn add gulp --dev
- 封装工作流 - 解决模块中的问题
- 新项目(zce-gulp-demo)中添加 pages.config.js 用于配置构建流项目(zce-pages)需要的数据
- 构建流项目index.js 中
const cwd = process.cwd() // 当前项目的工作目录 let config = {} try { const loadConfig = require(`${cwd}/pages.config.js`) config = Object.assign({}, config, loadConfig) } catch(e) {}
- require 是按照当前目录依次往上找
- 封装工作流 - 抽象路径配置
- glupfile
const {src, dest, parallel, series, watch} = require('gulp')
const del = require('del')
const browserSync = require('browser-sync')
const bs = browserSync.create() // 创建一个开发服务器
const loadPlugins = require('gulp-load-plugins')
const plgins = loadPlugins()
// const sass = require('gulp-sass')
// const babel = require('gulp-babel')
// const swig = require('gulp-swig')
// const imagemin = require('gulp-imagemin')
let config = {
build: {
src: 'src',
dist: 'dist',
temp: '.temp',
public: 'public',
paths: {
styles: 'assets/styles/*.scss',
scripts: 'assets/scripts/*.js',
pages: '/*.html',
images: 'assets/images/**',
fonts: 'assets/fonts/**'
}
}
}
const cwd = process.cwd
try {
const loadConfig = require(`${cwd}/pages.config.js`)
config = Object.assign({}, config, loadConfig)
}
// const data = { // 初始化模版需要的数据
// meuns: [],
// pkg: require('./package.json'),
// date: new Date()
// }
const clean = () => {
return del([config.build.dist, config.build.temp])
}
const style = () => {
return src(config.build.paths.styles, {base: config.build.src, cwd: config.build.src}) // 指定路径
.pipe(plgins.sass({outputStyle: 'expanded'})) // 指定编译后的样式
.pipe(dest(config.build.temp))
.pipe(bs.reload({stream: true})) // 也能更新
}
const script = () => {
return src(config.build.paths.scripts, {base: config.build.src, cwd: config.build.src})
.pipe(plgins.babel({presets: [require('@babel/preset-env')]}))
.pipe(dest(config.build.temp))
.pipe(bs.reload({stream: true})) // 也能更新,把文件流的信息推到浏览器
}
const page = () => {
return src(config.build.paths.pages, {base: config.build.src, cwd: config.build.src})
.pipe(plgins.swig({data: config.data, , defaults: { cache: false }})) // 解决调试是模板缓存不更新的问题 , defaults: { cache: false }
.pipe(dest(config.build.temp))
.pipe(bs.reload({stream: true})) // 也能更新
}
const img = ()=> {
return src(config.build.paths.images, {base: config.build.src, cwd: config.build.src})
.pipe(plgins.imagemin({stream: true}))
.pipe(dest(config.build.dist))
}
const font = ()=> {
return src(config.build.paths.fonts, {base: config.build.src, cwd: config.build.src})
.pipe(plgins.imagemin())
.pipe(dest(config.build.dist))
}
const extra = () => {
return src('**', {base: config.build.public, cwd: config.build.public})
.pipe(dest(config.build.dist))
}
const serve = () => {
watch(config.build.paths.styles, {cwd: config.build.src}, style) // 发现修改的文件,则构建当前文件
watch(config.build.paths.scripts, {cwd: config.build.src}, script)
watch(config.build.paths.pages, {cwd: config.build.src}, page)
// watch('src/assets/images/**', img)
// watch('src/assets/fonts/**',font)
// watch('public/**', extra)
watch([
config.build.paths.images,
config.build.paths.fonts,
], {cwd: config.build.src}, bs.reload) // 开发阶段不需要每次都压缩,比较消耗性能
watch('**', {cwd: config.build.public}, page, bs.reload)
bs.init({
notify: false, // 是否现实加载中的动画
port: 2090,
// files: 'dist/**', // 监控文件修改则更新到浏览器 和.pipe(bs.reload({stream: true})) 选一个
server: {
baseDir: [config.build.temp, config.build.src, config.build.public],
routes: {
'/node_modules': 'node_modules' // 优先级高于baseDir
}
}
})
}
const useref = () => {
return src(conf.build.pages, {base: config.build.temp})
.pipe(plgins.useref({searchPath: [config.build.temp, '.']}))
.pipe(plgins.if(/\.js$/, plgins.uglify()))
.pipe(plgins.if(/\.css$/, plgins.cleanCss()))
.pipe(plgins.if(/\.html$/, plgins.htmlmin({
collapseWhitespace: true, // 去掉html回撤空格
minfyCSS: true, // 去掉html中css空格
minfyJS: true // 去掉html 中 js空格
})))
.pipe(dest(config.build.dist)) // temp 临时目录,是解决压缩时同一目录下读写容易冲突
}
const compile = parallel(style, script, page)
const build = series(clean, parallel(series(compile, useref), extra, img, font))
const develop = series(compile, serve)
module.exports = {
clean,
build,
develop
}
- 封装工作流 - 包装 Gulp CLI
- 可以去掉新项目的gulpfile 文件
- 构建流项目 > packaage.js > “bin”: “bin/zce-page.js”
- 构建流项目 > bin > zec-pages.js
#!/usr/bin/env node
process.agrv.push('--cwd')
process.agrv.push(process.cwd())
process.agrv.push('--gulpfile')
process.agrv.push('..')
require('gulp/bin/gulp')
- 封装工作流 - 发布并使用模块
- 构建流项目 > package.js > “files”: [“bin”, “lib”]
- yarn public --registry https://registry.yarnpkg.com (发布)
- yarn add zec-pages --dev
- yarn zec-pages build
- 新项目 package.josn 》 “scirpts”: {“clean”: “zec-pages clean” …}
- 封装工作流 - 工作流总结
- x-pages 是 zce-pages 的进步形
- FIS 的基本使用
- yarn global add fis3
- fis3 release -d output
- fis首要解决资源文件定位(模版页面引用的资源路径)
- 很长时间不更新了
- FIS 编译与压缩
- yarn global add fis-parser-node-sass
- yarn global add fis-parser-babel-6.x
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mLLz8nCs-1625144115402)(…/img/1625109112023.jpg)]