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

简答题

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完成项目的自动化构建。

未完待续。。。。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,264评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,549评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,389评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,616评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,461评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,351评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,776评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,414评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,722评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,760评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,537评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,381评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,787评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,030评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,304评论 1 252
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,734评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,943评论 2 336