前端工程化整理(笔记)

前端工程化整理(笔记)

一切以提高效率、降低成本、质量保证为目的的方案都是“工程化”
前端工程化,nodeJS厥功至伟,大部分工程化的东西都是用nodeJS开发的,无node无前端工程化。
大概分为:

  • 脚手架工具
  • 自动化构建系统
  • 模块化打包
  • 项目代码规范化
  • 自动化部署

脚手架工具

常用脚手架

Yeoman

使用
1、在全局安装yeoman

$ npm install yo -g  # or yarn global add yo

2、安装对应的generator(要生成哪种项目,就用哪种生成器这里是node)

$ npm install generator-node -g # or yarn global add generator-node

3、通过yo运行generator

$ cd path/to/project-dir
$ mkdir my-module
$ yo node

自定义一个Generator

|- generator/          生成器
|  |- app/             默认生成器目录
|  |  |- index.js      默认生成器实现
|  |  |- templates     默认模板目录

index.js

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 => {
      
      this.answers = answers
    })
  }
  writing () {
    // Yeoman 自动在生成文件阶段调用此方法
    // 通过模板方式写入文件到目标目录
    
    // 模板文件路径
    const tmpl = this.templatePath('bar.html')
    // 输出目标路径
    const output = this.destinationPath('bar.html')
    // 模板数据上下文
    const context = this.answers

    this.fs.copyTpl(tmpl, output, context) //最后输出
  }
}

发布到npm 命令:npm publish

Plop (快速创建组件得小脚手架工具)

使用
1、安装到项目中

$ npm install plop --dev

2、在项目根目录新建文件plopfile.js

// 此函数接收一个 plop 对象,用于创建生成器任务

module.exports = plop => {
  //生成器的名字与配置
  plop.setGenerator('component', {
    description: 'create a component',
    prompts: [
      {
        type: 'input',
        name: 'name',
        message: 'component name',
        default: 'MyComponent'
      }
    ],
    actions: [
      {
        type: 'add', // 代表添加文件
        path: 'src/components/{{name}}/{{name}}.js',
        templateFile: 'plop-templates/component.hbs'
      },
      {
        type: 'add', // 代表添加文件
        path: 'src/components/{{name}}/{{name}}.css',
        templateFile: 'plop-templates/component.css.hbs'
      },
      {
        type: 'add', // 代表添加文件
        path: 'src/components/{{name}}/{{name}}.test.js',
        templateFile: 'plop-templates/component.test.hbs'
      }
    ]
  })
}
templateFile: 'plop-templates/component.hbs'

模板文件,在根目录创建的模板文件夹 /plop-templates/component.hbs

文件目录
component.hbs

import React from 'react';
export default () => (
  <div className="{{name}}">
    <h1>{{name}} Component</h1>
  </div>
)
脚手架原理

自动化构建

将开发出来的代码转换为生产代码,及自动化构建流,例如less->css、新语法转es5,兼容性等等

1、browesr-sync模块,起一个服务并且自动打开浏览器
“serve”: “browesr-sync” --files 监听文件变化,热更新

2、npm-run-all模块,同时实行多个命令
“start”: “run-p build serve” 同时执行build和serve

常用的自动化构建工具

Grunt、Gulp、FIS

Grunt

基本使用
1、 npm install grunt
2、创建 gruntfile.js
gruntfile.js

// Grunt 的入口文件
// 用于定义一些需要 Grunt 自动执行的任务
// 需要导出一个函数
// 此函数接收一个 grunt 的对象类型的形参
// grunt 对象中提供一些创建任务时会用到的 API
module.exports = grunt => {
//1、 grunt.initConfig() 用于为任务添加一些配置选项
  grunt.initConfig({
    // 键一般对应任务的名称
    // 值可以是任意类型的数据
    foo: {
      bar: 'baz'
    }
  })
  // --------------------------------
//2、 registerTask注册一个任务
  grunt.registerTask('foo', () => {
    // 任务中可以使用 grunt.config() 获取配置
    console.log(grunt.config('foo'))
    // 如果属性值是对象的话,config 中可以使用点的方式定位对象中属性的值
    console.log(grunt.config('foo.bar'))
  })
  // ---------------------------------
//3、 grunt中执行异步任务使用this.async()回调函数
  // 由于函数体中需要使用 this,所以这里不能使用箭头函数
  grunt.registerTask('async-task', function () {
    const done = this.async()
    setTimeout(() => {
      console.log('async task working~')
      done()
    }, 1000)
  })
  // ---------------------------------
//4、 任务函数执行过程中如果返回 false
  // 则意味着此任务执行失败
  grunt.registerTask('bad', () => {
	console.log('bad task');
	return false
  })
  // 异步函数中标记当前任务执行失败的方式是为回调函数指定一个 false 的实参
  grunt.registerTask('bad-async', function () {
    const done = this.async()
    setTimeout(() => {
      console.log('async task working~')
      done(false)
    }, 1000)
  })
  // -------------------------------
//5、 多任务配置
// 多目标模式,可以让任务根据配置形成多个子任务
// 配合initConfig使用,build下的每个键就是以一个任务与,除了option
  grunt.initConfig({
    build: {
      options: {
        msg: 'task options'
      },
      foo: {
        options: {
          msg: 'foo target options'
        }
      },
      bar: '456'
    }
  })

  grunt.registerMultiTask('build', function () {
    console.log(this.options())
  })
}
6、插件使用

1、下载对应插件,npm install grunt-contrib-clean
2、通过grunt.loadNpmTasks引入插件
3、通过initConfig配置插件的使用,启动命令对应插件clean

grunt-contrib-clean删除指定文件

module.exports = grunt => {
  grunt.initConfig({
    clean: {
      temp: 'temp/**'
    }
  })
  
  grunt.loadNpmTasks('grunt-contrib-clean')
}
7、常用的grunt插件

1、grunt-sass 编译sass
2、load-grunt-tasks 自动加载所有的 grunt 插件中的任务不必一个个loadNpmTasks();

const loadGruntTasks = require('load-grunt-tasks')
module.exports = grunt => {
  loadGruntTasks(grunt) // 自动加载所有的 grunt 插件中的任务
}

3、grunt-babel @babel/core @babel/preset-env ES6转ES5编译兼容

module.exports = grunt => {
  grunt.initConfig({
    babel: {
      options: {
        sourceMap: true,
        presets: ['@babel/preset-env']
      },
      main: {
        files: {
          'dist/js/app.js': 'src/js/app.js'
        }
      }
    }
  })
}

4、grunt-contrib-watch 监听文件变化

module.exports = grunt => {
  grunt.initConfig({
    watch: {
      js: {
        files: ['src/js/*.js'],
        tasks: ['babel']
      },
      css: {
        files: ['src/scss/*.scss'],
        tasks: ['sass']
      }
    }
  })
}
Gulp

基本使用基本与grunt相同
1、 npm install gulp
2、创建 gulpfile.js

// 创建任务
// 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 bar

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)

// 让多个任务同时执行(并行)
exports.bar = parallel(task1, task2, task3)

gulp中的异步任务

const fs = require('fs')
// gulp的任务函数本身都是异步的,通过调用done()完成
exports.callback = done => {
  console.log('callback task')
  done()
}
exports.callback_error = done => {
  console.log('callback task')
  done(new Error('task failed'))
}
// -------------------------------
// 也可使用Promise需要node8以上
exports.promise = () => {
  console.log('promise task')
  return Promise.resolve()
}
exports.promise_error = () => {
  console.log('promise task')
  return Promise.reject(new Error('task failed'))
}
// -----也可以是async/await------------------------------- 
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
}
// 其实是调用了read中的done;
exports.stream = done => {
  const read = fs.createReadStream('yarn.lock')
  const write = fs.createWriteStream('a.txt')
  read.pipe(write)
  read.on('end', () => {
    done()
  })
}

gulp中的文件操作
gulp的内置插件:src和dest

// src读出文件流 dest写入文件流
const { src, dest } = require('gulp')
// 压缩css
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 自动化构建中常用的插件
1、gulp-load-plugins 自动加载所用到的插件
const loadPlugins = require(‘gulp-load-plugins’)

const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins()

// sass编译 sass
plugins.sass({ outputStyle: 'expanded' })
// js新属性转为ES5  babel
plugins.babel({ presets: ['@babel/preset-env'] })
// 模板编译  swig
plugins.swig({ data, defaults: { cache: false } }
// 图片压缩  imagemin
plugins.imagemin()

2、热更新开发服务器 browser-sync插件

const { watch } = require('gulp')
const browserSync = require('browser-sync')
const bs = browserSync.create()

const style = () => {
  return src('src/assets/styles/*.scss', { base: 'src' })
    .pipe(plugins.sass({ outputStyle: 'expanded' }))
    .pipe(dest('temp'))
    .pipe(bs.reload({ stream: true })) // 也可在这里触发服务器reload
}

const serve = () => {
  // 监听文件修改
  watch('src/assets/styles/*.scss', style)
  watch('src/assets/scripts/*.js', script)
  watch('src/*.html', page)
  // 
  watch([
    'src/assets/images/**',
    'src/assets/fonts/**',
    'public/**'
  ], bs.reload)
  // bs.reload重新加载,监听文件变化后可使用bs.reload
  bs.init({
    notify: false,
    port: 2080, 
    // open: false, // 是否关闭热更新
    // files: 'dist/**', // 监听文件变化更新浏览器监听目录
    server: {
      baseDir: ['temp', 'src', 'public'], // 网站根目录
      routes: {
        '/node_modules': 'node_modules'
      }
    }
  })
}

3、构建优化拆封,生成与开发环境的配置
4、useref插件,处理文件引用目录问题,并打包儿多部分文件

// 打包后的文件处理,将构建注释转化
// 处理html文件中,js和css的引用
const useref = () => {
  return src('temp/*.html', { base: 'temp' })
    .pipe(plugins.useref({ searchPath: ['temp', '.'] }))
    // html js css 文件压缩处理
    // uglify js压缩、cleanCss css压缩、htmlmin html压缩
    // gulp-if插件区分文件类型
    .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'))
}

5、区分导出任务,并写入script中,用npm启动
6、封装自动化构建工作流,提取构建系统的公共部分,创建npm包儿发布

  • 建立npm包儿,最后发布到npm仓库管理(可参考npm包开发流程)
  • 导入专门的配置文件,可以传入参数
  • 一般参数有:文件配置文件目录、环境目录等等
  • 包装gulp-cli,创建/bin/umbal-page.js文件
    umbal-page.js
#!/usr/bin/env node

process.argv.push('--cwd')
process.argv.push(process.cwd())
process.argv.push('--gulpfile')
process.argv.push(require.resolve('..'))

require('gulp/bin/gulp')
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值