工程化、自动化构建练习

简答题


1.谈谈你对工程化的初步认识,结合你之前遇到的问题说出三个以上工程化能够解决的问题或者带来的价值。

工程化就是通过一些方法去提升研发效率和研发质量的手段。

解决问题
  1. 传统语法或语法的弊端
  2. 无法使用模块化/组件化
  3. 重复的机械式工作
  4. 代码风格统一、质量保证
  5. 依赖后端服务接口支持
  6. 整体依赖后端项目
    创建项目:使用脚手架工具,自动帮我们完成基础结构的搭建。
    编码:自动帮我们完成一些代码风格化以及代码风格的校验,从而确保每一个开发人员写出的代码都是相同的风格,使用编译工具让我们在开发阶段使用新的特性,提高我们代码编码的效率。
    预览/测试:提供热更新体验。
    提交:自动化的在项目提交之前,对项目进行整体的检查,包括项目质量,代码风格的检查,确保不会把有问题的d代码提交到仓库中,对提交日志也可以有严格的限制
    部署:在代码提交后,自动化的通过持续集成或持续部署方式,自动将我们的代码部署到服务器,避免了手动操作产生的不稳定因素。

2.你认为脚手架除了为我们创建项目结构,还有什么更深的意义?

  • 提高效率,可以快速搭建一个基础项目结构
  • 规范化 对技术选型、项目结构等做了一些规范,降低了沟通成本。

编程题

1.概述脚手架实现的过程,并使用Node JS完成一个自定义的小型脚手架工具

实现过程

  • 创建一个项目文件
  • 通过 yarn init 初始化 package.json 文件
  • 在项目的根目录中创建一个入口的 js 文件
  • 在 package.json 文件中添加 “bin”: “入口文件路径”
  • 编写入口 js 文件
  • 编写完后,执行 yarn link 命令连接到全局
  • 在终端执行脚手架命令
  • 可以通过 yarn publish 发布到 npm 仓库

实操

  • 创建名为 test-cli 文件夹
  • 在终端输入 yarn init -y 创建 package.json 文件
  • 在 package.json 添加 bin 入口
{
//...
  "bin": "cli.js",
//...
}
  • 在根目录创建 cli.js 文件 添加 bin 入口标识
#! /usr/bin/env node

//...
  • 在根目录下创建模板目录 templates 将模板文件导入到目录中
  • 引入 inquirer 模块 通过命令行询问的方式 让用户输入、选择一些信息
  • 引入 ejs 模块 结合所需功能问题变量 然后通过 fs 模块读取模板文件 使用 ejs 渲染数据写入到模板文件中
  • 通过 yarn link 命令链接到全局
  • 命令行运行 test-cli 就能执行手脚架了

cli.js代码:

// 脚手架的工作过程:
// 1. 通过命令行交互询问用户问题
// 2.根据用户问答的结果生成文件

const fs = require('fs')
const path = require('path')
const inquirer = require('inquirer')
const ejs = require('ejs')

inquirer.prompt([
    {
        type: 'input',
        name: 'name',
        message: 'Project name?'
    }
])
.then(anwsers => {
    //console.log(anwsers)
    //根据用户回答的结果生成文件

    //根据目录
    const tmplDir = path.join(__dirname, 'templates')
    //目标目录
    const destDir = process.cwd()

    //将模板下的文件全部转换到目标目录
    fs.readdir(tmplDir, (err, files) => {
        if (err) throw err
        files.forEach(file => {
            // 通过模板引擎渲染文件
            ejs.renderFile(path.join(tmplDir, file), anwsers,(err, result)=>{
                if (err) throw err

                // 将结果写入目标文件路径
                fs.writeFileSync(path.join(destDir, file), result)
            })
        })
    })
})

2.尝试使用Gulp完成项目的自动化构建

gulp的构建过程分为三部分

  • 输入
    • 读取流——读取文件
  • 加工
    • 转换流——通过插件实现相应的转换效果
  • 输出
    • 写入流——写入文件

任务

  • gulp-sass 编译scss文件
  • gulp-babel 编译JS
  • gulp-imagemin 处理图片、字体
  • 拷贝静态资源
  • gulp-swig 出路HTML模板文件
  • browser-sync 热服务
  • gulp-useref gulp-if 文件引用处理
  • gulp-load-plugins 自动加载插件
  • 使用series parallel组合任务
const { src, dest, parallel, series, watch } = require('gulp')
const del = require('del')
const browserSync = require('browser-sync')
// 自动加载插件
const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins()
const bs = browserSync.create()
const data = {
  menus: [
    {
      name: 'Home',
      icon: 'aperture',
      link: 'index.html'
    },
    {
      name: 'Features',
      link: 'features.html'
    },
    {
      name: 'About',
      link: 'about.html'
    },
    {
      name: 'Contact',
      link: '#',
      children: [
        {
          name: 'Twitter',
          link: 'https://twitter.com/w_zce'
        },
        {
          name: 'About',
          link: 'https://weibo.com/zceme'
        },
        {
          name: 'divider'
        },
        {
          name: 'About',
          link: 'https://github.com/zce'
        }
      ]
    }
  ],
  pkg: require('./package.json'),
  date: new Date()
}
// 其他文件及文件清除
// 插件 del
const clean = () => {
  return del(['dist', 'temp'])
}
// 样式编译
// 插件  gulp-sass
// sass模块工作时,_ 下划线开头的样式文件都是我们在主文件中依赖的文件,不会被转化
const style = () => {
  return src('src/assets/styles/*.scss', { base: 'src' })
    .pipe(plugins.sass({ outputStyle: 'expanded' }))
    .pipe(dest('temp'))
    .pipe(bs.reload({ stream: true }))
}
// 脚本编译
// 插件 gulp-babel
// 同时还需要安装 @babel/core @babel/preset-env
// 在文件流中需要传递babel({ presets: ['@babel/preset-env'] })
const script = () => {
  return src('src/assets/scripts/*.js', { base: 'src' })
    .pipe(plugins.babel({ presets: ['@babel/preset-env'] }))
    .pipe(dest('temp'))
    .pipe(bs.reload({ stream: true }))
}
// 页面模板编译
// swig模板引擎转换插件 gulp-swig
const page = () => {
  return src('src/*.html', { base: 'src' })
    .pipe(plugins.swig({ data, defaults: { cache: false } })) // 防止模板缓存导致页面不能及时更新
    .pipe(dest('temp'))
    .pipe(bs.reload({ stream: true }))
}
// 图片和字体转换
// 插件 gulp-imagemin 
const image = () => {
  return src('src/assets/images/**', { base: 'src' })
    .pipe(plugins.imagemin())
    .pipe(dest('dist'))
}
const font = () => {
  return src('src/assets/fonts/**', { base: 'src' })
    .pipe(plugins.imagemin())
    .pipe(dest('dist'))
}
const extra = () => {
  return src('public/**', { base: 'public' })
    .pipe(dest('dist'))
}
// 热更新开发服务器
// 插件 browser-sync
// 这个插件并不是gulp,只不过我们需要gulp管理
const serve = () => {
  // watch监视路径文件通配符
  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.init({
    notify: false, // 关闭小提示
    port: 2080, // 启动端口
    // open: false, // 取消自动打开浏览器
    // files: 'dist/**',  // 服务启动后,自动监听的目录下文件的改动,同步浏览器
    server: {
      baseDir: ['temp', 'src', 'public'],
      routes: {
        '/node_modules': 'node_modules'
      }
    }
  })
}
// usere文件引用处理
// 插件 gulp-useref
const useref = () => {
  return src('temp/*.html', { base: 'temp' })
    .pipe(plugins.useref({ searchPath: ['temp', '.'] }))
    // html js css
    .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'))
}
const compile = parallel(style, script, page)
// 上线之前执行的任务
const build =  series(
  clean,
  parallel(
    series(compile, useref),
    image,
    font,
    extra
  )
)
const develop = series(compile, serve)
module.exports = {
  clean,
  build,
  develop
}

package.json配置脚本

"script": {
	"clean": "gulp clean",
	"build": "gulp build",
	"develop": "gulp develop"
}

3.使用 Grunt 完成项目的自动化构建

任务

  • grunt-sass 编译 scss 文件
  • grunt-babel编译 js 文件
  • grunt-contrib-watch 监听文件改变
  • grunt-contrib-clean 清除编译后的文件
  • grunt-contrib-copy 拷贝静态文件
  • grunt-contrib-uglify 压缩 js 文件
  • develop用于开发环境 编译scss、编译ES6、监听文件改变
  • default 用于生产 拷贝静态问价、清除编译后的文件、编译scss、编译ES6,压缩JS
// grunt 构建任务

const sass = require('sass')
const loadGruntTask = require('load-grunt-tasks')// 加载grunt插件
module.exports = grunt =>{

    grunt.initConfig({
        babel:{
            options:{
                presets:['@babel/preset-env']
            },
            main:{
                files:{
                    'dist/assets/scripts/main.js':'src/assets/scripts/main.js'
                }
            }
        },
        // 压缩js 
        uglify: {
            my_target: {
              files: {
                'dist/assets/scripts/main.min.js': ['dist/assets/scripts/main.js']
              }
            }
          },
        // 处理scss文件
        sass:{
            options:{
                sourceMap:true,
                implementation:sass//使用sass处理编译
            },
            main:{//配置目标
                files:{
                    'dist/assets/styles/main.css':'src/assets/styles/main.scss'
                }
            }
        },
        // 拷贝静态文件
        copy:{
            main: {
                expand: true,
                src: 'public/*',
                dest: 'dist/',
            }
        },
        clean:{
            dist:'dist/**'
        },
        // 监视文件变化
        watch:{
            js:{
                files:['src/assets/scripts/*.js'],
                task:['babel']
            },
            css:{
                files:['src/assets/styles/*.scss'],
                task:['sass']
            }
        }
    })


    grunt.loadNpmTasks('grunt-contrib-clean') //删除构建后的文件
    // grunt.registerTask('foo',()=>{
    //     console.log('foo task');
        
    // })

    
    // grunt.loadNpmTasks('grunt-sass')
    // grunt.loadNpmTasks('grunt-babel')

    loadGruntTask(grunt)//自动加载所有插件
    grunt.registerTask('develop',['sass','babel','watch'])
    grunt.registerTask('default',['clean','copy','sass','babel','uglify'])

}

package.json脚本

"script": {
	"develop": "yarn grunt develop",
	"build": "yarn grunt"
}
©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页