前端工程化

300 阅读7分钟

一切重复的工作都应该工程化。

创建项目

编码 格式化代码 校验代码风格

预览/测试 webServer / mock live Reloading /HMR source Map

提交 Git Hooks Lint-staged 持续限制

部署 CI/CD 自动部署

工程化

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

脚手架的本质作用

  • 相同的组织结构
  • 相同的开发范式
  • 相同的工具配置
  • 相同的基础代码

Yeoman 基本使用

yarn global add yo
// 先安装全局generator-node
yarn global add generator-node

// 创建文件夹
mkdir my-module
// 创建项目
yo node

```js
## sub Generator
```js
// 安装相应的脚手架
yo node:cli
// 安装yarn link 连接全局
yarn link 
npm link // 我使用npm

使用

  1. 明确你的需求
  2. 找到合适的Generator
  3. 全局范围安装找到的Generator
  4. 通过yo运行的Generator
  5. 通过命令行交互填写选项
  6. 生成你所需要的项目结构
yo webapp

自定义Generator

mkdir generator-sample // 创建文件夹。 必须是generator-${name}结尾。

yarn init // 初始化项目

yarn add yeoman-generator // 提供一些工具函数。

/**
 * 此文件作为Generator核心入口
 * 需要导出一个继承自Yeoman Generator 的类型
 * Yeoman Generator 在工作的时会自动调用我们在此
 * 类型中定义的一些生命周期的方法
 * 我们在这些方法可以通过父类提供的一些工具方法实现一些功能
 * 例如文件写入
 */
const Generator = require('yeoman-generator');
module.exports = class extends Generator{
  wrting() {
    // Yeoman 自动
    this.fs.write(
      this.destinationPath('temp.txt'),
      Math.random().toString()
    )
  }
}

// 使用yarn link在当前目录下执行。 使他成为一个全局模块包。
yarn link | npm link

// 新建一个文件夹
mkdir my-proj

// 接下来就可以使用yo sample 命令 sample>去的文件名字。
yo sample

当前文件就会创建一个txt文件

根据模版创建文件

如果我们需要更多的文件,这个时候就需要字符串模版了

现在generator-sample文件夹下app--> 新建一个模版文件 templates/foo.txt

foo.txt
// 这是一个模版文件
// 内部可以使用EJS模版标记输出数据
// 其他的EJS语法也支持
<% if (success) {%>
哈哈哈
<% } %>

generator-sample/app/index.js

const Generator = require('yeoman-generator');
module.exports = class extends Generator {
	writing () {
    	// 模版文件路径
		    const tmpl = this.templatePath('foo.txt');
        // 输出数据上下文
        const output = this.destinationPath('foo.txt')
        // 模版数据上下文。
        const context = {title: "Hello ", success: true}
        
        this.fs.copyTpl(tmpl, output, context)
        
    }
}

接收用户输入数据

// Yeoman 在询问用户环节会自动调用此方法 // 在此方法中可以调用父类的Promise 方法发出对用户的命令询问

const Generator = require("yeoman-generator");
module.exports = class extends Generator {
	prompting () {
     return this.prompt([
     {
     	 type: 'input',
        name: 'name',
        message: 'Your project name',
        default: this.appname // appname为项目生成目录名称
     }
     ]).then(anewers => {
     	this.anewers = anewers;
     }) 
    }
    writing () {
    	// 模版文件路径
		    const tmpl = this.templatePath('bar.html');
        // 输出数据上下文
        const output = this.destinationPath('bar.html')
        // 模版数据上下文。
        const context = this.anewers;
        
        this.fs.copyTpl(tmpl, output, context);
    }
}

vue generator 案例

// 新建文件夹
mkdir generator-yhb-vue
// 初始化项目
yarn init
// 安装yeoman-generator
code .
创建generator/app/index.js

const Generator = require('yeoman-generator')

module.exports = class extends Generator {
  prompting () {
    return this.prompt([
      {
        type: 'input',
        name: 'name',
        message: 'Your project name',
        default: this.appname
      }
    ])
    .then(answers => {
      this.answers = answers
    })
  }

  writing () {
    // 把每一个文件都通过模板转换到目标路径

    const templates = [
      '.browserslistrc',
      '.editorconfig',
      '.env.development',
      '.env.production',
      '.eslintrc.js',
      '.gitignore',
      'babel.config.js',
      'package.json',
      'postcss.config.js',
      'README.md',
      'public/favicon.ico',
      'public/index.html',
      'src/App.vue',
      'src/main.js',
      'src/router.js',
      'src/assets/logo.png',
      'src/components/HelloWorld.vue',
      'src/store/actions.js',
      'src/store/getters.js',
      'src/store/index.js',
      'src/store/mutations.js',
      'src/store/state.js',
      'src/utils/request.js',
      'src/views/About.vue',
      'src/views/Home.vue'
    ]

    templates.forEach(item => {
      // item => 每个文件路径
      this.fs.copyTpl(
        this.templatePath(item),
        this.destinationPath(item),
        this.answers
      )
    })
  }
}
// 链接到全局
yarn link
// 在任意目录下: 
yo ${name}
会生成你的项目。

发布npm包。

首先.过滤调node_modules echo node_modules > .gitignore 初始化git git init 跟踪所有文件 git add . 查看状态 git status 提交记录 git commit -m 'save' 将申请的git 地址跟本地项目链接 git remote add origin https: //github.coom/17698753015/generator-VUEtor.git push 到master git push -u origin master npm publish// 一般有淘宝原 npm publish --registry=registry.npmjs.org/ // 指定地址发布。

创建脚手架

mkdir  sample-scaffolding
yarn init -y
package.json
"bin": "cli.js"
// 新建cli.js
yarn add inquirer // 发起命令行询问
//进入: cli.js
// Node CLI 应用入口文件必须要这样的文件头
//如果是Linux 或者macOs系统下还需要修改此文件的都写权限为 755 
// 返回文件上一级
// sudo chmod -R 755 文件名
// 具体就是通过chmod 755 cli.js 实现修改

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

#! /usr/bin/env node
const inquirer = require('inquirer');
const fs = require("fs")
const path = require("path")
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)
     }) 
    })
  })
})

// 项目的根目录新建模版
templates/index.html

自动化构建demo

mkdir saas
cd saas 
yarn init -y 
touch index.html
mkdir scss
cd scss
touch main.scss
yarn add sass --dev // 安装sass预编译插件
yarn add browser-sync --dev // 安装测试服务器
yarn add npm-run-all --dev // 同时执行多个命令
// package.json
{
  "name": "saas",
  "version": "1.0.0",
  "main": "index.js",
  "author": "Your name",
  "license": "MIT",
  "scripts": {
    "build": "sass scss/main.scss style/main.css --watch", // 监听scss变化编译成css
    "serve": "browser-sync . --files  \"style/*.css\"", // 启动web server 监听css文变化
    "start": "run-p build serve" // 同时执行以上两个命令, 按顺序执行
  },
  "devDependencies": {
    "browser-sync": "^2.26.12",
    "npm-run-all": "^4.1.5",
    "sass": "^1.26.10"
  }
}

前端自动化构建工具

grunt gulp FIS grunt: 磁盘读写操作。慢 gulp: 内存读写,速度快 FIS: 百度开发。套餐

grunt

yarn init -y ./node_modules/.bin/sass scss/main.scss style/main.css

grunt 的基本使用

mkdir grunt-sample
cd grunt-sample
yarn init -y
yarn add grunt --dev
// 创建gruntfile.js
code gruntfile.js
//打开编辑器。
code .
执行代码


// grunt 的入口文件
// 用于定义一些Grunt 自动执行的的任务
// 需要导出一个函数
// 此函数接收一个grunt形参。
// 内部提供一些创建任务时可以用到API
module.exports = grunt => {
  // 第一个参数是任务名字自定义。 第二个参数可以是一个箭头函数
  // 来执行这个任务的具体代码
  // yarn grunt foo
  grunt.registerTask('foo', () => {
    console.log("hello")
  })
  // 第二个参数可以是字符串对任务的具体描述。
  // yarn grunt --help 可以看到任务描述
  // 三个参数是一个函数来执具体代码
  // yarn grunt bar
  grunt.registerTask('bar', '任务描述', () => {
    console.log("任务描述")
  })
  // grunt 默认执行default 任务。 yarn grunt 不带任务名字
  grunt.registerTask('default', 'default', () => {
    console.log("default")
  })
  // 当默认任务是一个数组的里面可以是我们定义的其他任务。
  // 里面任务会同步执行。
  grunt.registerTask('default', ['foo', 'bar'])
  // grunt 任务是默认同步任务的。如果直接使用异步代码
  // 将不会执行
  grunt.registerTask('async-test', function () {
    setTimeout(() => {
      console.log('async task working');
    }, 1000)
  })
  // 当我们需要执行异步代码的时候。需使用this.async()
  // 并且在异步任务执行一下。才会执行异步任务。
  grunt.registerTask('async', function () {
    const done = this.async();
    setTimeout(() => {
      console.log('async task working');
      done()
    }, 1000)
  })
}

grunt 标记任务失败

const { set } = require("grunt")

module.exports = grunt => {
  grunt.registerTask('foo1', () => {
    console.log("1")
  })
  grunt.registerTask('foo2', () => {
    console.log("2")
    // 返回false 表明任务失败
    return false;
  })
  grunt.registerTask('foo3', () => {
    console.log("3")
  })
  // 异步返回false 需要在done执行的时候传过去
  grunt.registerTask('foo4', function () {
    const done = this.async()
    setTimeout(() => {
      console.log(55555);
      done(false)
    }, 1000)
  })
   // 直接执行的yarn grunt 的话会报错 如图1 
   // 使用yarn grunt --force 标记错误其他任务也能正常执行
  grunt.registerTask('default', ['foo1', 'foo2', 'foo3'])
}

grunt 配置方法

module.exports = grunt => {
  // 添加配置的方法
  grunt.initConfig({
    foo: 'bar',
    foo01: {
      bar: 123
    }
  })
  grunt.registerTask('foo', () => {
    // 可以这样获取配置的值
    console.log(grunt.config('foo'))
    // 可以这样.bar获取下一层。
    console.log(grunt.config('foo01.bar'))
  })
}

Grunt多目标任务配置

module.exports = grunt => {
  grunt.initConfig({
    // 健需要跟任务同名。
    build: {
      // 他类似build全局的选择配置
      options: {
        foo: 'bar' // 1
      },
      css: {
        options: {
          foo: 'baz' // 和1相同会覆盖1的值
        }
      },
      js: '2'
    }
  })
  // 多目标模式, 可以让任务根据配置形成多个子任务
  //   >> No "build" targets found.
  // Warning: Task "build" failed. Use --force to continue.

  // Aborted due to warnings.
  // error Command failed with exit code 3.
  // 需要配置 grunt.initConfig 配置不同的目标
  grunt.registerMultiTask('build', function () {
    console.log(this.options())
    // 拿到initConfig配置的build的任务选项。
    console.log(`target: ${this.target}, data: ${this.data}`)
    console.log('build task')
  })
//Running "build:css" (build) task
// build task

// Running "build:js" (build) task
// build task
// yarn grunt build:css
// yarn grunt build:js

}

grunt 插件使用。

yarn add grunt-contrib-clean --dev

module.exports = grunt =>  {
  grunt.initConfig({
    clean: {
      // 执行yarn grunt clean app.js将被删除。
      // * 删除该文件下所以文件
      // ** 所有子目录和子目录下的文件
      temp: 'temp/*.js'
    }
  })
  //  >> No "clean" targets found.
  // Warning: Task "clean" failed. Use --force to continue.
  grunt.loadNpmTasks('grunt-contrib-clean');
}

grunt 常用插件

// yarn add load-grunt-tasks --dev
// 监听grunt 所有安装的插件
const loadGruntTasks = require('load-grunt-tasks');


const sass = require('sass')
module.exports = grunt =>  {
  grunt.initConfig({
    // grunt-sass 是grunt 的插件 。需要运行在sass 环境里
    // sass插件 yarn add grunt-sass sass --dev
    sass: {
      // 配置选项
      options: {
        // 源码
        sourceMap: true,
        // 加载sass
        implementation: sass
      },
      // 配置
      main: {
        files: {
          // 编译完成的地址: 和需要编译的地址
          'dist/css/main.css': 'src/scss/main.scss'
        }
      }
    },
    // 安装babel yarn add grunt-babel @babel/core @babel/preset-env --dev
    babel: {
      options: {
        // 源码
        sourceMap: true,
        // 执行babel 预装插件
        presets: ['@babel/preset-env']
      },
      // 任务配置
      main: {
        files: {
          // 编译完成的地址: 和需要编译的地址
          'dist/js/app.js': 'src/js/app.js'
        }
      }
    },
    // 监听插件 yarn add grunt-contrib-watch --dev
    watch: {
      js: {
        // 指定监听的文件
        files: ['src/js/*.js'],
        // 根据文件的变化执行对于应的任务
        tasks: ['babel']
      },
      css: {
        // 指定监听的文件
        files: ['src/scss/*.scss'],
        // 根据文件的变化执行对于应的任务
        tasks: ['sass']
      }
    },
  })
  // 单个执行某一个插件。如果任务特别多的话我们需要写很多grunt.loadNpmTasks('grunt-sass')
  // 类似的代码。load-grunt-tasks 这个插件可以执行我们安装的所有的grunt
  // 插件。不需要我们引入。只需要配置它就可以执行。
  // grunt.loadNpmTasks('grunt-sass')
  
  loadGruntTasks(grunt) // 会自动加载所有的grunt插件里的任务
  // 开启默认任务。当sass babel 执行完之后会执行watch会一直监听文件的变化。从而执行相应的任务
  grunt.registerTask('default', ['sass', 'babel', 'watch'])
}

Gulp的基本使用

// gulp 最新版本取消来同步,都是异步执行
// 需要手调一个回调函数
// 推荐导出gulp 成员的方法。
// yarn gulp foo
exports.foo = done => {
  console.log('foo task worhing~')
  done() // 标示任务完成
}
// yarn gulp
exports.default = done => {
  console.log('default---------')
  done()
}

// gulp 4.0 以前
// yarn gulp bar
// 不推荐使用
const gulp = require('gulp');
gulp.task('bar', done => {
  console.log("bar working");
  done();
})

gulp 创建组合任务

const { series, parallel } = require('gulp');
const task1 = done => {
  setTimeout(() => {
    console.log('task1 woring');
    done();
  }, 1000)
}
const task2 = done => {
  setTimeout(() => {
    console.log('task2 woring');
    done();
  }, 1000)
}
const task3 = done => {
  setTimeout(() => {
    console.log('task3 woring');
    done();
  }, 1000)
}
// exports.${name}自定义任务名字
// series 任务组合方法。依次执行 串行
exports.foo = series(task1,task2,task3)
// parallel 任务组合方法。 并行执行
exports.bar = parallel(task1,task2,task3)

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("Promise task~");
  return Promise.resolve() // 成功返回的参数会被gulp忽略。
}

exports.promisee_error = () => {
  console.log('promise task~');
  // 调用promise.reject() 
  // 传给new Error('meessage');错误实例。
  // 会结束后面代码的执行
  return Promise.reject(new Error('task faileed~'))
}
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;
//   // console.log(23456)
// }
exports.stream = done => {
  const readStream = fs.createReadStream('package.json');
  const writeStream = fs.createWriteStream('temp.txt');
  readStream.pipe(writeStream);
  readStream.on('end', () => {
    done()
  })
  // console.log(23456)
}

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

// 构建过程
// 复制 > 压缩 > 粘贴到一个文件里。

const fs = require('fs');
const { Transform } = require('stream')
exports.default = () => {
  // 文件读取流
  const readStream = fs.createReadStream('temp.css');
  // 文件写入流
  const writeStream = fs.createWriteStream('temp.min.css');
  // 文件转换流。
  const transform = new Transform({
    transform: (chunk, encoding, callback) => {
      // 和核心转换实现
      // chunk => 读取流中读取到的内容(BUffer)
      const input = chunk.toString();
      const output = input.replace(/\s+/g, '').replace(/\/\*.+?\*\//g, '');
      // callback 第一个参数传入错误对象 没有的话传如 - null;
      callback(null, output);
    }
  })
  // 把读取出来的文件导入写入流。
  readStream
          .pipe(transform)
          .pipe(writeStream);
  return readStream;
}

文件操作API + 插件的使用

// 文件操作API + 插件的使用
// src 读取流。
// yarn add gulp-clean-css 压缩css 转换流
// dest 写入流。
// 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') // 返回执行结果告诉gulp任务已经结束
         .pipe(cleanCss())
         .pipe(rename({extname: '.min.css'}))
         .pipe(dest('dist'))
}

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

// ## 开发脚手架及封装自动化构建工作流
// yarn add gulp --dev 安装gulp
// yarn add gulp-sass --dev 安装gulp-sass
// yarn add gulp-babel --dev 安装gulp-babel
// 需要安装babel 的核心模块 
// yarn add @babel/core @babel/cli --dev
// yarn add @babel/core @babel/preset-env --dev
const { src, dest } = require('gulp');
const sass = require('gulp-sass');
const babel = require('gulp-babel');
const style = () => {
  return src('src/assets/styles/*.scss', {base: 'src'})
  .pipe(sass({outputStyle: 'expanded'}))
  .pipe(dest('dist'))
}

const script = () => {
  return src('src/assets/scripts/*.js', {base: 'src'})
  .pipe(babel({presets: ['@babel/preset-env']}))
  .pipe(dest('dist'))
}

// 导出需要执行的模块
// exports.style = () => {} 相同
module.exports = {
  style,
  script
}

gulp项目案例



// ## 开发脚手架及封装自动化构建工作流
// yarn add gulp --dev 安装gulp
// yarn add gulp-sass --dev 安装gulp-sass
// yarn add gulp-babel --dev 安装gulp-babel
// 需要安装babel 的核心模块 
// yarn add @babel/core @babel/cli --dev
// yarn add @babel/core @babel/preset-env --dev
// yarn add gulp-swig --dev 转换模版文件
// yarn add gulp-imagemin --dev 图片压缩
// yarn add del --dev 删除指定文件
// yarn add browser-sync --dev // 启动本地服务器
// yarn add gulp-useref --dev 代码中引用node_modules 里面的css
// 打包的时候并没有打包进去。线上的时候并不能这样。所以使用gulp-useref 还可以合并代码。
// yarn add gulp-htmlmin gulp-uglify gulp-clean-css --dev // html js css 处理插件
// yarn add gulp-if // 判断插件
const { src, dest, parallel, series, watch } = require('gulp');
const del = require('del');
const bs = require('browser-sync').create();
// 自动只加载gulp, 所有安装gulp插件。gulp-load-plugins
const plugins = require('gulp-load-plugins')();
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(plugins.sass({outputStyle: 'expanded'}))
  .pipe(dest('temp'))
  .pipe(bs.reload({ stream: true }))
}

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 }))
}
const page = () => {
  // 匹配src下的所有html
  return src('src/**/*.html', {base: 'src'})
  // swig 有缓存。需要配置cache: false,否则效果不好。
  .pipe(plugins.swig({ data, defaults: { cache: false } }))
  .pipe(dest('temp'))
  .pipe(bs.reload({ stream: true }))
}

const image = () => {
  // 匹配src下的所有html
  return src('src/assets/images/**', {base: 'src'})
  .pipe(plugins.imagemin())
  .pipe(dest('dist'))
}

const font = () => {
  // 匹配src下的所有html
  return src('src/assets/fonts/**', {base: 'src'})
  .pipe(plugins.imagemin())
  .pipe(dest('dist'))
}

const extra = () => {
  return src('public/**', {base: 'public'})
  .pipe(dest('dist'))
}

const serve = () => {
  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)
  // 当这些文件又变化的时候,执行bs.reload重新加载浏览器。
  watch([
    'src/assets/images/**',
    'src/assets/fonts/**',
    'public/**',
  ], bs.reload)

  bs.init({
    // 禁止右上角提示
    notify: false,
    // 设置端口号
    open: false,
    port: 2080,
    // 可以在每个任务下执行bs.reload()
    // files: 'dist/**',
    server: {
      // 启动服务的基准文件
      // 从左到右一次执行。如果在dist找不到的文件回去src里找。以此类推。
      baseDir: ['temp', 'src', 'public'],
      // baseDir: 'temp',
      // 发现有以/node_modules开头的路径。
      // 就会在node_modules文件夹查找。
      routes: {
        '/node_modules': 'node_modules'
      }
    }
  })
}

const useref = () => {
  return src('temp/**/*.html', {base: 'temp'})
  .pipe(plugins.useref({
    searchPath: ['temp', '.']
  }))
  .pipe(plugins.if(/\.js$/, plugins.uglify()))
  .pipe(plugins.if(/\.css$/, plugins.cleanCss()))
  .pipe(plugins.if(/\.html$/, plugins.htmlmin({
    collapseWhitespace: true, // html里面的空格
    minifyCSS: true, // html里面的css
    minifyJS: true,  // html里面的js
  })))
  .pipe(dest('dist'))
}
const comppile = parallel(style, script, page);
// 先执行串行任务。在执行并行任务。
const build = series(clean, parallel(series(comppile, useref), image, font, extra));
const develop = series(comppile, serve);
// 导出需要执行的模块
// exports.style = () => {} 相同
module.exports = {
  build,
  develop,
  clean,
}

目录结构

git地址: github.com/17698753015…

自动化构建工作流

自动更新包: npm.taobao.org

  1. mkdir yhb-pages
  2. git init -y
  3. mkdir bin && touch yhb-pages.js
  4. mkdir lib && touch index.js
  • 将写好的gulp项目。提取gulpfile
  • 将gulpfile.js放入到lib/index.js里面 现在是空的
  • 将gulp项目中的package.json的开发依赖放到yhb-pages项目的生产依赖上面。
  • package.json里面加一个"bin": "biin/yhb-pages.js"
  • 将gulp项目node-modules.
  • 在yhb-pages项目安装所有依赖。
  • yarn link 将当前项目命令链接到全局。
  • 在gulp项目中执行 yarn lint 'yhb-pages'
  • 在gulp项目中的gulpfile.js 写如下代码
module.exports = require('yhb-pages')
  • gulp项目中执行: yarn

  • gulp项目中执行: yarn build

  • yarn add gulp-cli --dev 里面有gulp命令

  • yarn build

  • 临时安装yarn add gulp --dev

  • yarn build 在gulp项目中根目录新建一个pages.config.js

module.exports = {
  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('zce-pages/package'),
    date: new Date()
  }
}
  • yhb-pages/lib/index.js