part2-m1

  • 本阶段主要以前端工程化为主题,分别从脚手架工具、自动化构建、模块化开发、规范化标准四个维度介绍前端工程化具体该如何落地、如何实践,以此应对复杂前端应用的开发和维护过程,提高开发者的工作效率,降低项目维护成本,从而更好地适应大前端时代下的前端开发工作。

模块一 开发脚手架及封装自动化构建工作流

  • 此模块中会先带你了解什么是前端工程化,以及前端工程化和工具之间的关系;紧接着在脚手架工具的学习中你可以了解到脚手架的本质、工作原理,以及自己从无到有搭建一个自己的脚手架工具;最后我们会介绍几种常见的自动化构建工具的使用和扩展方式,通过使用自动化构建工具,可以大大提高你的开发效率。
任务一:工程化概述
  1. 工程化定义和主要解决的问题
  • 想要使用ES6+新特性,兼容有问题
  • 想要使用Less/Sass/PostCSS增强css的编程性,但运行环境不能直接支持
  • 想要使用模块化的方式提高项目的可维护性,但运行环境不能直接支持
  • 部署上线前需要手动压缩代码及资源文件,部署过程需要手动上传代码到服务器
  • 多人协作开发,无法硬性统一大家的代码风格,从仓库中pull回来的代码质量无法保证
  • 部分功能开发时需要等待后段服务接口提前完成
  • 主要解决的问题
    • 传统语言或语法的弊端
    • 无法使用模块化,组件化
    • 重复的机械式劳动
    • 代码风格统一、质量保证
    • 依赖后端服务接口支持
    • 整体依赖后端项目
  1. 一个项目过程中工程化的表现
  • 一切以提高效率、降低成本、质量保证为目的的手段都属于工程化
    • 创建项目: 创建项目结构,创建特定类型文件
    • 编码: 格式化代码,效验代码风格,编译/构建/打包
    • 预览/测试: Web Server / Mock;Live Reloading/HMR;Source Map
    • 提交: Git Hooks Lint-staged 持续集成
    • 部署:CI/CD 自动发布
  1. 工程化不等于工具

  2. 工程化与Node.js

  • 内容概述
    • 脚手架工具开发
    • 自动化构建系统
    • 模块化打包
    • 项目代码规范化
    • 自动化部署
任务二:脚手架工具
  1. 脚手架工具概要
  • 脚手架的本质工作:创建项目的基础结构、提供项目规范和约定
    • 相同的组织结构
    • 相同的开发规范
    • 相同的模块依赖
    • 相同的工具配置
    • 相同的基础代码
  • 内容概述
    • 脚手架的作用
    • 常用的脚手架工具
    • 通用脚手架工具剖析
    • 开发一款脚手架
  1. 常用脚手架工具
  • React项目 create-react-app
  • Vue项目 vue-cli
  • Angular项目 angular-cli
  • Yeoman 通用型脚手架
  • Plop 在项目中创建一个组件/模块所需要的文件
  1. Yeoman 简介
  • 用于创建现代化应用的脚手架工具
  • yeoman.io
  1. 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
  1. Sub Generator
  • generator-node下子集生成器,cli,eslink等基础配置生成
  • yo node:cli
  1. Yeoman 使用步骤总结
  • 明确你的需求
  • 在官网找到合适的Generator yeoman.io
  • 全局范围安装找到的Generator
  • 通过Yo运行对应的Geneartor
  • 通过命令行交互填写选项
  • 生成你所需要的项目结构
  1. 自定义Geneartor

  2. 创建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(生成器名字)
  3. 根据模版创建文件

  • 相对于手动创建每一个文件,模版的方式大大提高了效率
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2ZwsuyUs-1625144115395)(…/img/1624873564691.jpg)]
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kmV9zYaz-1625144115397)(…/img/1624873643530.jpg)]
  1. 接受用户的数据
  • 在命令行获取的数据可以挂载到this.answers属性上,在writing 的时候使用
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CeuXtzRv-1625144115398)(…/img/1624873895102.jpg)]
  1. 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
        )
      })
      
  • 在app下创建 templates,放入需要初始化的模版,如vue项目的初始结构
  • <%%=name%> 多加一个%,EJS就会被转义,不会去替换当前的name
  1. 发布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官方收录
  1. Plop 一个小而美的脚手架工具
  • 在项目中使用,比如创建一个footer组件,可以直接初始化.css.js 等多个文件,以及文件内默认的编码
  • yarn plop component
  1. 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运行脚手架任务
  1. 脚手架的工作原理
  • 创建脚手架工具,就是创建一个 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)]
任务二:自动化构建
  1. 自动化构建简介
  • 源代码》自动化构建》生产代码
  • 自动化构建工作流 使用提高效率的语法、规范和标准
  1. 自动化构建初体验
  • 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 某一目录
  1. 常用的自动化构建工具
  • Grunt Gulp FIS 通过调用插件构建
    • Grunt 插件生态非常完善,工作过程基于临时文件实现,构建过程比较慢,例如对sass文件做编译操作:添加私有属性操作,代码压缩等,每一步都会有磁盘读写操作,sass文件在编译完成过后就会将结果写入一个临时文件,下一个插件再去读取这个临时文件,处理的环节越多,读写临时文件的次数越多,对于超大型项目,文件很多,构建速度就会很慢
    • Gulp 解决了Grunt构建速度慢的问题,因为它是基于内存实现的,对文件的处理环节都是在内存中完成的,相对于磁盘读写,速度就快了很多。默认支持同时去执行多个任务,效率大大提高,使用方式,相对于Grunt更加的直观易懂,插件生态也同样完善,后来居上,更受欢迎,市面上最流行的前端构建系统
    • FIS 百度前端团队推出的开源项目,微内核的特点,更像是一种捆绑套餐,它把我们在项目中一些典型的需求都集成在内部了,例如我们在FIS中就能很轻松的处理资源加载,模块化开发,代码部署,性能优化,大而全,在国内很多项目中流行开了。
  • webpack 模块打包工具
  • 构建工具小结
    • 如果是初学者,FIS可能更适合,但是要求灵活多变,Grent,Gulp是更好的选择,新手需要规则,老手渴望自由
  1. Grunt 的基本使用
  • yarn init --yes
  • yarn add grunt
  • yarn grunt 任务名称
  • grunt默认支持同步模式,如果需要执行异步任务,需要 this.async()标记
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pr5pXnq7-1625144115401)(…/img/1625018085405.jpg)]
  • 异步任务不能使用箭头函数,default后面配置一个数组,默认执行多个任务
  1. Grunt 标记任务失败
  • 通过在任务中 reture false 标记任务失败,如果这个任务是在一个任务列表中,这个任务失败会导致后续的任务都不执行
  • 可以通过强制方式执行后续的任务: yarn grunt default --force
  • 异步任务可以通过 done(false) 指定一个实参就可以标记失败
  1. Grunt 的配置方法
  • 比如需要压缩文件,可以通过配置initConfig配置压缩路径
grunt.initConfig({
    foo: {
        bar: 123
    }
})
grunt.registerTask('foo', () => {
    console.log(grunt.config('foo.bar'))
})
  1. 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}`)
})
  1. Grunt 插件的使用
  • 先npm安装这个插件,然后在gruntfile中载入这个插件
  • yarn add grunt-contrib-clean 清除项目中多余的文件
grunt.initConfig({
    clean: {
        temp: 'temp/**' // 清除temp下所有文件
    }
})
grunt.loadNpmTask('grunt-contrib-clean')
  • yarn grunt clean
  1. 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'])
}
  1. 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()
})
  1. 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) // 并行执行任务
  1. 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()
    })
}
  1. 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注册结束事件
}
  1. 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'))
}
  1. Gulp 案例 - 样式编译
  • git clone https://github.com/zce/zce-gulp-demo.git
  • yarn add gulp-sass --dev
  1. Gulp 案例 - 脚本编译
  • yarn add gulp-babel --dev
  • yarn add @babel/core @babel/preset-env --dev
  1. Gulp 案例 - 页面模版编译
  • yarn add gulp-swig --dev (模版转换引擎)
  1. Gulp 案例 - 图片和文字文件转换
  • yarn add gulp-imagemin --dev (img图片压缩,也可以压缩svg的字体文件,如果不能处理,就不会处理,无损压缩)
  1. Gulp 案例 - 其它文件及文件清除
  • yarn add del --dev
  1. 自动加载插件
  • yarn add gulp-load-plugins --dev
  1. 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 
            }
        }
    })
}
  1. Gulp 案例 - 监视变化以及构建优化
  • 在开发阶段不构建css,font,img等,减少性能消耗
  1. 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
  1. Gulp 案例 - 文件压缩
  • yarn add gulp-htmlmin gulp-yglify gulp-clean-css --dev
  • yarn add gulp-if --dev (判断文件的类型)
  1. 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
}
  1. Gulp 案例 - 补充
  • 选择要暴露的任务,配置在package.json scripts中
// "scripts": {
//   "clean": "gulp clean",
//   "build": "gulp build",
//   "develop": "gulp develop"
// },
  • 在.gitignore 中配置需要忽略的文件,如temp,dist等
  1. 封装工作流 - 准备
  • 如果单纯的把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
  1. 封装工作流 - 提取 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
  1. 封装工作流 - 解决模块中的问题
  • 新项目(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 是按照当前目录依次往上找
  1. 封装工作流 - 抽象路径配置
  • 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
}
  1. 封装工作流 - 包装 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')
  1. 封装工作流 - 发布并使用模块
  • 构建流项目 > 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” …}
  1. 封装工作流 - 工作流总结
  • x-pages 是 zce-pages 的进步形
  1. FIS 的基本使用
  • yarn global add fis3
  • fis3 release -d output
  • fis首要解决资源文件定位(模版页面引用的资源路径)
  • 很长时间不更新了
  1. FIS 编译与压缩
  • yarn global add fis-parser-node-sass
  • yarn global add fis-parser-babel-6.x
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mLLz8nCs-1625144115402)(…/img/1625109112023.jpg)]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值