美文网首页
Part2.模块一:开发脚手架及封装自动化构建工作流

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

作者: 油菜又矮吹 | 来源:发表于2020-08-12 10:41 被阅读0次

    简答题

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

    解:
          工程化指的是在遵循一定标准和规范的基础上,通过使用工具来提高效率,降低成本的一种手段;工程化不等于某种工具,一切以提高效率、降低成本和质量保证为目的的手段都称之为工程化。
    解决的问题:
          1.无法使用模块化/组件化组织代码
          2.代码风格统一,使得项目多人协作开发,质量得以保证
          3.部分功能需要等待后端服务接口完成以后才可以进行开发
          4.重复的机械工作,比如部署上线前需要手动压缩代码及资源文件,部署过程需要手动上传代码到服务器。
    带来的价值:
          1.压缩图片大小,使得请求图片时间降低
          2.代码合并压缩,减少项目整体体积

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

    解:
          脚手架的本质作用除了为我们创建项目结构,还为我们提供了项目规范和约定。脚手架创建的项目包含相同的组织结构、相同的开发范式、相同的模块依赖、相同的工程配置以及相同的基础代码。脚手架作为一种创建项目初始文件的工具被广泛地应用于新项目或迭代初始阶段。使用工具代替人工操作能够避免人为失误引起的低级错误,同时结合整体前端工程化方案,快速生成功能模块配置、自动安装依赖等,优化了时间成本。在公司中使用同一套脚手架工具创建的项目,使得项目成员更换时,能够马上上手,提高开发效率。

    编程题

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

    解:
          实现:
          1.创建一个新的仓库目录:small-node-js
          2.通过yarn init --yes初始化项目并生成package.json文件
          3.创建cli.js文件,并将其路径添加到package.json中bin对应的值

    {
      "name": "small-node-js",
      "version": "1.0.0",
      "main": "index.js",
      "bin": "lib/cli.js",
      "license": "MIT",
      "devDependencies": {},
      "dependencies": {
        "ejs": "^3.1.3",
        "inquirer": "^7.3.3"
      }
    }
    

          4.编写cli.js中的内容

    #!/usr/bin/env node
    
    // Node CLI 应用入口文件必须要有这样的文件头
    // 如果Linux 或者 Mac 系统下,还需要修改此文件权限为755: chmod 755 cli.js
    
    // 脚手架工作过程:
    // 1. 通过命令行交互询问用户问题
    // 2. 根据用户回答的结果生成文件
    
    const path = require('path')
    const fs = require('fs')  // 读取文件
    const inquirer = require('inquirer') // 发起命令行交互询问
    const ejs = require('ejs') // 模板引擎
    inquirer.prompt([
      {
        type: 'input',
        name: 'title',
        message: 'Project name?'
      },
      {
        type: 'input',
        name: 'name',
        message: 'your name?'
      },
      {
        type: 'input',
        name: 'age',
        message: 'your age?'
      },
    ]).then(answer => {
    
      // 模板目录
      const tempDir = path.join(__dirname, 'templates')
      // 目标目录  --当前文件夹路径
      const destDir = process.cwd()
    
      // 将模板下的文件全部转换到目标目录
      fs.readdir(tempDir, (err, files) => {
        if (err) throw err
        files.forEach(file => {
          // 通过模板引擎渲染文件
          ejs.renderFile(path.join(tempDir, file), answer, (err, result) => {
            if(err) throw err
            // 将结果写入到目标目录
            fs.writeFileSync(path.join(destDir, file), result)
          })
        })
      })
    })
    

          5.创建模板文件index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title><%= title %></title>
    </head>
    <body>
      <p><%= name %></p>
      <p><%= age %></p>
    </body>
    </html>
    

          6.执行yarn link命令将该cli程序link到全局
          7.在命令行中执行small-node-js,,并根据提示输入相应的值,则会在项目根目录下创建由该模板生成的index.html


    NodeJS脚手架.png
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>nodejs</title>
    </head>
    <body>
      <p>Tom</p>
      <p>18</p>
    </body>
    </html>
    
    2.尝试使用Gulp完成项目的自动化构建。

    视频地址Gulp脚手架-项目自动化构建
    Gulp讲解:

    • gulpfile.js
    // 实现这个项目的构建任务
    //导入 gulp 下需要使用到的库
    const { src, dest, parallel, series, watch} = require('gulp')
    const del = require('del')
    
    // 自动加载插件
    const loadPlugins = require('gulp-load-plugins')
    const plugins = loadPlugins()
    const {sass, babel, swig, imagemin, uglify, cleanCss, htmlmin} = plugins
    
    // 提供开发服务器,在代码修改后能够热更新
    const browserSync = require('browser-sync')
    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()
    }
    
    // 文件清除
    const clean = () => {
        return del(['dist', 'temp'])
    }
    // 样式编译
    const style = () => {
        return src('src/assets/styles/*.scss', { base: 'src'})
            .pipe(sass({outputStyle: 'expanded'}))
            .pipe(dest('temp'))
            .pipe(bs.reload({stream: true}))
    }
    
    // 脚本编译
    const script = () => {
        return src('src/assets/scripts/*.js', { base: 'src'})
            .pipe(babel({presets: ['@babel/preset-env']}))
            .pipe(dest('temp'))
            .pipe(bs.reload({stream: true}))
    }
    
    // 模板编译
    const page = () => {
        return src('src/*.html', { base: 'src'})
            .pipe(swig({data, defaults: {cache: false}})) // 防止模板缓存导致页面不能及时更新
            .pipe(dest('temp'))
            .pipe(bs.reload({stream: true}))
    }
    
    
    // 图片压缩
    const image = () => {
        return src('src/assets/images/**', { base: 'src'})
            .pipe(imagemin())
            .pipe(dest('dist'))
    }
    
    // 字体压缩
    const font = () => {
        return src('src/assets/fonts/**', { base: 'src'})
            .pipe(imagemin())
            .pipe(dest('dist'))
    }
    
    // 额外的编译:public
    const extra = () => {
        return src('public/**', {base: 'public'})
            .pipe(dest('dist'))
    }
    
    
    // 开发服务器
    const server = () => {
        // 监视文件,决定是否要执行任务
        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,
            // files:'dist/**',
            server: {
                baseDir:['temp', 'src', 'public'],//图片只是压缩了,请求dist和src上并无区别,只是进行压缩了下,这里让他请求原文件,减少了一次构建,提高开发效率
                routes:{
                    '/node_modules' : 'node_modules'
                }
            }
        })
    }
    
    // 文件引用处理---合并
    const useref = () => {
        return src('temp/*.html',{base: 'temp'})
            .pipe(plugins.useref({searchPath: ['temp','.']}))
            .pipe(plugins.if(/\.js$/,uglify()))
            .pipe(plugins.if(/\.css$/,cleanCss()))
            .pipe(plugins.if(/\.html$/,htmlmin({
                collapseWhitespace: true, // 折叠空白字符和换行符
                minifyCSS: true, // 样式压缩
                minefyJS: 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, server)
    module.exports = {
        build,
        develop,
        compile,
    }
    
    /**
     * 运行命令
     * yarn gulp build
     * yarn gulp develop
     * yarn gulp compile
     */
    
    • pacjage.json
    {
      "name": "pages-boilerplate",
      "version": "0.1.0",
      "private": true,
      "description": "Always a pleasure scaffolding your awesome static sites.",
      "keywords": [
        "pages-boilerplate",
        "boilerplate",
        "pages",
        "zce"
      ],
      "homepage": "https://github.com/zce/pages-boilerplate#readme",
      "bugs": {
        "url": "https://github.com/zce/pages-boilerplate/issues"
      },
      "repository": {
        "type": "git",
        "url": "git+https://github.com/zce/pages-boilerplate.git"
      },
      "license": "MIT",
      "author": {
        "name": "zce",
        "email": "w@zce.me",
        "url": "https://zce.me"
      },
      "scripts": {
        "clean": "gulp clean",
        "lint": "gulp lint",
        "serve": "gulp serve",
        "build": "gulp build",
        "start": "gulp start",
        "deploy": "gulp deploy --production"
      },
      "browserslist": [
        "last 1 version",
        "> 1%",
        "maintained node versions",
        "not dead"
      ],
      "dependencies": {
        "bootstrap": "4.4.1",
        "jquery": "3.4.1",
        "popper.js": "1.16.1"
      },
      "devDependencies": {
        "@babel/core": "^7.11.1",
        "@babel/preset-env": "^7.11.0",
        "browser-sync": "^2.26.12",
        "del": "^5.1.0",
        "gulp": "^4.0.2",
        "gulp-babel": "^8.0.0",
        "gulp-clean-css": "^4.3.0",
        "gulp-htmlmin": "^5.0.1",
        "gulp-if": "^3.0.0",
        "gulp-imagemin": "^7.1.0",
        "gulp-load-plugins": "^2.0.3",
        "gulp-sass": "^4.1.0",
        "gulp-swig": "^0.9.1",
        "gulp-uglify": "^3.0.2",
        "gulp-useref": "^4.0.1"
      },
      "engines": {
        "node": ">=6"
      }
    }
    
    
    3.使用Grunt完成项目的自动化构建。

    未完待续。。。。。

    相关文章

      网友评论

          本文标题:Part2.模块一:开发脚手架及封装自动化构建工作流

          本文链接:https://www.haomeiwen.com/subject/bosrdktx.html