前端工程化

1 篇文章 0 订阅
1 篇文章 0 订阅

第一章: 概述

前端工程化: 提高效率, 降低成本, 保证质量

解决的问题:颜色代表不同问题分类

使用es6 兼容, lass sass 等无法直接运行 模块化方式无法直接运行, 手动重复性动作(部署/压缩), 团队风格统一,github 拉的代码质量不可保证。    开发/整体依赖后端接口。 

 涉及领域:(对照下图)

第二章:脚手架(scaffolding) Yeoman

本质: 创建项目基础结构,规范和约定

Yeoman + generators => 各种脚手架

Yoeman 平A 技能 

yeoman  使用 node-generator 创建 node modules 流程

Guohais-MBP:~ guohaiqu$ node -v  |v16.0.0   |v10.16.2
Guohais-MBP:~ guohaiqu$ npm -v   |7.19.0    |6.9.0
Guohais-MBP:~ guohaiqu$ yarn -v  |1.22.10   |1.17.3

Guohais-MBP:~ guohaiqu$ yarn global add yo              |全局安装 yoeman
Guohais-MBP:~ guohaiqu$ yarn global add generator-node  |全局安装 generator-node

|进入文件|

Guohais-MBP:my_module guohaiqu$ yo node

|回答一些问题| => 安装

Yeoman Sub Generator (子生成器)

Guohais-MBP:my_module guohaiqu$ yo node:cli


Overwrite package.json yes

报错: premisson denied  

sudo chmod -R 755 文件目录(my_module)
sudo chmod -R 755 文件目录(my_module/lib)

yarn unlink 
yarn link

使用 yoeman + generator-webapp

yarn global add generator-wbapp
yo webapp

自定义Genertator = 创建npm 模块

        1. 文件结构 固定(如下图,是否包含子生成器) 

        2. 文件名 固定 generator-filename

|| terminal
mkdir generator-sample              // 创建生成器模块的目录
cd generator-sample                 // 进入文件夹
yarn init                           // 创建 package.json
yarn add yeoman-generator           // 安装 模块 yeoman-generator = 提供生成器 基类 


|| vs code 
generators/app/index.js             // 创建 index.js(generator核心入口)


||index.js
具体功能
const Generator = require('yeoman-generator')
module.exports = class extends Generator {
    writing() {
        this.fs.write(
            this.destinationPath('temp.txt'),
            Math.random().toString()
        )
    }
}
Guohais-MacBook-Pro:generator-sample guohaiqu$ yarn link
cd ..
mkdir my-test
cd my-test
yo sample

添加模版文件

app/templates/foo.txt 

//   模版文件创建   
     writing() {
        const tmpl = this.templatePath('foo.txt')
        const output = this.destinationPath('foo.txt')
        const context = { title:'hello', success:false }
        this.fs.copyTpl(tmpl, output, context)
    }
//  命令行交互方法    
    prompting () {
        return this.prompt([
            {
                type: "input",
                name: "title",
                message: "your project name", // 提示
                default: this.appname // 项目目录名
            },
            {
                type: "input",
                name: "gg",
                message: "second", // 提示
                default: "gg"
            }
        ])
        .then (answers =>{
            this.answers = answers
            console.log(this.answers) //{ title: 'ggg', gg: 'yyy' }
        })
    }
// in foo.txt : eg: <%= title %><%= gg %>

批量添加模版文件

const Generator =  require('yeoman-generator')

module.exports = class extends Generator {
    prompting() {
        return this.prompt([
            {
                type:"input",
                name:"project_name",
                message:"enter project name",
                default: this.appname            
            }
        ])
        .then(answers => {
            this.answers = answers
        })
    }
    writing() {
        const templates = [
            'public/first.html',
            'public/first.css',
            'src/second.html',
            'src/second.css'
        ]
        templates.forEach(item => {
                this.fs.copyTpl(
                this.templatePath(item),
                this.destinationPath(item),
                this.answers
            )
        });
    }
}

.gitignore 忽略 node_modules

第三章:脚手架 Plop

是: 配合项目使用的小型脚手架

实例: react + plop 在react 中使用 plop 创建文件

1. 作为项目以来安装 plop  | yarn add plop --dev |

2. 项目根下 :创建 plopfile.js , plop入口文件, 定义脚手架

3. 编写模版 hbs   | plop-teamplates > filename.filetype.hbs  ( handle bar)

4. plop cli 运行 脚手架  |yarn plop component/生成器名|

plopfile.js

plopfile.js :导出一个函数 ,| module.exports = () => {} |

其接收一个plop 对象(形式参数), 用来创建 generator  | module.exports = plop => {} |

plop 对象 : > (成员) plop.setGenerator (参数1: 生成器名string , 参数2: 配置选项object

配置选项  :  description「string」 | prompts「array > object」 |actions 「array > object」

npx create-react-app my-app
yarn add plop --dev
module.exports = plop => {
    plop.setGenerator ('component', { 
        description : "create component",
        prompts: [
            {
                type: "input",
                name: "name",
                message: "component name",
                default: "myComponent"
            }
        ],
        actions: [
            {
                type: "add",
                path: "src/components/{{name}}/{{name}}.js",
                templateFile: "plop-templates/component.js.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.js.hbs"
            },
        ] 
    })
}

第四章:scaffolding 原理

创建项目 - 添加package.json 文件 - 添加"bin": "cli.js" 字段(指定cli 应用入口文件)

cli应用:  必备的两个条件 如下

#!/usr/bin/env node  |必须添加文件头|
Guohais-MacBook-Pro:scaffolding-logic guohaiqu$ chmod 755 cli.js

「mac linux 修改 755 权限」

调用:

yarn link 

scaffolding-logic(文件名)

step 1 : scaffolding logic - 询问信息

yarn add inquirer
const inquirer = require("inquirer")
inquirer.prompt([
    {
        type:"input",
        name: "name",
        message:"project name"
    }
])
.then(anwsers =>{
    console.log(anwsers)
})

// in console: scaffloding-logic (FILENAME)

step 2 : scaffolding logic - 添加文件(读取 + 写入)

const path = require("path")  // 读取路径
const fs = require("fs")      // 读取文件
const ejs = require("ejs")    // 渲染文件
  

  const tmpDir = path.join(__dirname, 'templates') 
    const distDir = process.cwd() // node process cwd 获取当前工作环境

    fs.readdir(tmpDir,(err, files)=>{
        if(err) throw err
        files.forEach(file => {
            ejs.renderFile(path.join(tmpDir, file), anwsers,(err, result)=>{
                if(err) throw new err
                fs.writeFileSync(path.join(distDir,file),result) //绝对路径,文件内容
            })
        }) 
       
    })

第五章:自动化构建

一句话概述:自动转换代码| 如:scss - css

npm scripts 可自动发现 node_modules 下的命令, 在 bin 下面

yarn add sass --dev

//without npm scripts
./node_modules/.bin/sass scss/main.scss css/style.css
 
// with npm scripts

scripts:{
    // NPM SCRIPTS : 自动找到node_modules\bin
    build: "sass scss/main.scss css/style.css" 
}

npm run build

测试服务器模块

yarn add browser-sync --dev

ATTENTION!

<head>

        <style media="screen" type="text/css">

                @import "css/style.css";

        </style>

</head>

开启服务器前 需要先编译scss

 方式1 : hook 

  "scripts": {
    "build": "sass scss/main.scss css/style.css",
    "preserve":"yarn build",
    "serve":"browser-sync ."
  },

 方式2 : npm-run-all 模块

yarn add npm-run-all --dev

"scripts": {
    "build": "sass scss/main.scss css/style.css --watch",
    "serve": "browser-sync . --files \"css/*.css\"",
    "start": "run-p build serve".  
},

yarn start

解释: 
scripts: {                   | 自动查找 bin 下的命令
    --watch                  | 监听scss的文件变化, 改变就转译
    --files \"css/*.css\"    | 监听文件变化,改变就刷新页面
    -- run-p                 | 同时运行多个命令 
}

话题: 对比grunt gulp fis

grunt :速度慢|磁盘读写|生态完善|急于临时文件 | 微内核|灵活

gulp  :速度相对块 |内存处理|默认多任务同时执行|易懂 |生态完善 |微内核|灵活

fis     :捆绑套餐 |适合新手 |大而全 |适合初学者

第七章: Grunt

mkdir grunt                    | 创建文件目录

cd grunt                       | 进入项目

yarn init                      | 初始化package.json

yarn add grunt                 | 安装 grunt 模块

touch gruntfile.js             | 创建 grunt 入口文件

 gruntfile.js 入口文件 说明

1. gruntfile.js :导出一个函数 ,| module.exports = () => {} |

2. 其接收一个grunt 形式参数 | module.exports = grunt => {} |

3. grunt : > (成员) grunt.registerTask (参数1: 任务名 ,参数2(可选):任务描述stringm 参数3: 函数)

4. grunt.registerTask(‘default’,【“任务1”,“任务2”】)

备注: grunt 默认同步模式

备注:grunt 任务名 |执行特定任务

备注:grunt  |执行默认任务

const { registerTask } = require("grunt")            |导入grunt

module.exports = grunt => {
    grunt.registerTask('foo','its a foo' , ()=>{     |同步任务
        console.log('gg')
        return false                                 |同步任务标记失败

    })

    grunt.registerTask('bar', function(){            |异步任务
        const done = this.async()
        setTimeout(()=>{
            console.log("2s delay")
            done()
            done(false)                              |异步任务标记失败
        }, 1000)
    })

    grunt.registerTask('default', ['foo','bar'])     |默认任务
}

// yarn grunt <function-name> | --force

多目标任务 和 配置选项

 grunt.registerMutiTask ('参数1:任务名 ', 参数2: 函数 )

grunt.initConfig ({

        任务名:{

                options:{

                        foo: 'bar'

                }

                目标名1 : {

                        options: {

                                foo:'baz'  // 覆盖

                        }

                }

                目标名2  : ‘目标2 执行的 任务’

        }

})

${this.target}    | 获取目标名

${this.data}     |获取值的名


    grunt.initConfig({
        build: {
            options: {
                foo: 'baz'    |为build 添加配置选项
            },
            js: {
                options:{
                    foo:'bar' | 覆盖外圈的foo
                },
                val: 'something'
            },
            css: '123'
        }
    })

grunt.registerMultiTask('build', function(){
    console.log(this.options())        |this.options是一个函数,调用他得到配置选项            
    console.log(this.data)
})
yarn grunt build

Running "build:js" (build) task
{ foo: 'bar' }
{ options: { foo: 'bar' }, val: 'gg' }

Running "build:css" (build) task
{ foo: 'baz' }
123

Grunt 插件

1. 安装插件 |2. 导入插件  |3. 配置选项

//1. 安装
 yarn add grunt-contrib-clean

2. 导入
grunt.loadNpmTasks('grunt-contrib-clean')

3. 配置选项
grunt.initConfig({
    clean: {
        temp:'temp'
    }
})

4. 使用
yarn grunt clean
yarn add grunt-sass sass --dev        |grunt-sass 需要依赖sass 来完成 

const sass = require('sass')          |导入sass 模块

grunt.initConfig({
   
     sass:{
            options: {                         
                sourceMap: true,
                implementation: sass          
            },
            main:{
                files:{
                    'dist/css/main.css':'src/scss/main.scss'
                }
            }
    }
})

grunt.loadNpmTasks('grunt-sass')      |导入grunt-sass 任务
yarn add grunt-babel @babel/core @babel/preset-env --dev
grunt.initConfig {
    main: {
        options:{
            sourceMap: true,
            presets: ['@babel/preset-env']     |最新 ECMA 特性
        },
        files:{
            'dist/js/app.js':'src/js/app.js'
        }
    }
}
grunt-contrib-watch --dev

grunt.initConfig({
    watch:{
        js:{
            files: ['src/js/*js'],                  | 监视 js 文件
            tasks: ['babel']                        | 执行 babel 任务
        }
    }
})

grunt.registerTasks('default' ['babel', 'watch'])   | 开始时先编译一下再监视
yarn add load-grunt-tasks --dev

const loadGruntTasks = require ('load-grunt-tasks')

loadGruntTasks(grunt) 

 第八章 - Gulp

预备: 安装 glup --dev| 2. gulpfile.js |gulp commands (yarn gulp <任务名>)

yarn init --yes
yarn add gulp --dev
touch gulpfile.js

导出任务

exports.foo = done =>{           // 传入异步任务
    console.log('foo')
    done()                       // 标记异步任务任务完成
}

exports.default = done =>{       // 默认任务
    console.log('default')
    done()                       // 标记异步任务任务完成
}

const gulp = require ('gulp')    // 以前的方法
gulp.task('bar',done=>{
    console.log('working')
    done()
})

 series + parallel 任务 

const {series, parallel} = require('gulp') |导入顺序和并行执行

注: 未被导出的任务被视为私有
const task1 = done=>{
    setTimeout(() => {
        console.log('task1')
        done()
    },1000)
}

exports.foo = series(task1, task2, task3)
exports.bar = parallel(task1, task2, task3)

异步任务

//1. 回调函数实现异步任务

exports.callback = done =>{
    console.log('callback function')
    done()
}

exports.callback_err = done =>{
    console.log('callback function')
    done(new Error('task failed!'))   //错误优先,第一个参数时错误 // 终止后续任务
}


2. promise 实现异步

exports.promise_error = () =>{
    console.log('promise task!')
    return Promise.reject(new Error('task failed!'))   // 终止后续任务
   // return Promise.resolve()       // gulp 会忽略值, 因此留空就可

}


// 3. async await       node环境限制   version>8 
const timeout = time => {
    return new Promise(resolve =>{
        setTimeout(resolve, time)
    })
}

exports.async = async()=>{
    console.log(async)
    await timeout(1000)      // await 异步任务(promise 对象)
}


4. stream    最常见方式

exports.stream = () => {
    const readStream = fs.createReadStream('package.json')
    const writeStream = fs.createWriteStream('temp.txt')
    readStream.pipe(writeStream)
    // done()
    // return readStream
    //readStream.on('end',()=>{
    //    done()
    //})
}

核心原理

读取 转换 写入 :基于 流 的操作

const  fs = require('fs')
const {Transfrom} = require ('stream')

exports.default =()=> {                              导出默认任务
const read = fs.createReadStream(' file_url')        创建文件读取流
const write = fs.createWriteStream(' file_url')      创建文件读取流 
const transform = new Transform({                    创建文件转换流
        transform:(chunk, encoding, callback) {
                const input = chunk.toString()
                const output = input.reaplace('正则')
        }
})
read
    .pipe(transform)
    .pipe(write)
} 

Gulp 插件使用:

 { src dest } , gulp-clean-css, gulp-rename 

安装 | 导入|放入pipe(something(明确参数))

const {src, dest} = require('gulp')
const cleanCss = require('gulp-clean-css')
const rename = require('gulp-rename')

exports.default = () => {
    return src('src/normalize.css')
    .pipe(cleanCss())
    .pipe(rename({extname:'.min.css'}))
    .pipe(dest('dist'))
}

Gulp 案例:scss  > css (gulp-sass)

{ base: "src" }, 导出文件的文件架构保留

sass({outputsytle: "expanded"}),使用sass 导出css 时的文件格式

const {src, dest} = require('gulp')
//const sass = require('gulp-sass')                       // gulp-sass 导入
const sass = require('gulp-sass')(require('sass'));     // gulp-sass 5


const style = ()=>{
    src('src/styles/scss/*.scss', {base: 'src'})        // 保留内部文件路径
        .pipe(sass({outputsytle: "expanded"}))          // css书写格式
        .pipe(dest('dist'))
}

module.exports = {                                     // = exports.style 另一种写法
    style
}

Gulp 案例:ECMA (gulp-babel)

gulp-babel 是一个转换 平台

需要安装@babel/core  @babel/preset-env 来转换(babely具体实施

yarn add gulp-babel --dev   
yarn add @babel/core @babel/preset-env --dev

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

module.exports = {
    script
}

Gulp 案例:HTML (gulp-swig)

传入需要的 数据, 定义 data 对象, 传入 swig()

const {src, dest} = require('gulp')
const swig = require('gulp-swig')

const data = {
    menus: [{},{},{}],
    pkg: require('./package.json'),
    data: new Data()
}

const page = () => {
    src('src/**/*html')
        .pipe(swig({defaults:{cache:false}})) // 加入清除缓存
        //.pipe(swig({data}))   //传入数据
        .pipe(dest('dist'))
}

module.exports = {
    page
}

Gulp 案例:ALL TOGETHER

const compile = parallel(style, script, page)

module.exports = {
   compile
}

// yarn gulp compile

Gulp 案例:图片压缩 (gulp-imagemin)

yarn add gulp-imagemin --dev

const imagemin = require ('gulp-imagemin')

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

}

module.exports = {
    image
}

// yarn gulp image

Gulp 案例:复制 + 删除 ( del :不是gulp插件)

其他文件如 public 下的 直接 复制源文件, src('....'). pipe(dest('dist'))

删除: yarn add del --dev

build 前删除 dist, 确保不覆盖

const del = require('del')

cosnt clean = () => {
    return del(['dist'])
}

const build = series(clean, compile)

Gulp 案例: 自动加载插件 (grunt-load-plugins)

//只适用于 grunt 插件

​
const loadPlugins = require( 'grunt-load-plugins' )

const plugins = loadPlugins()

省略了: const imagemin = require( 'grunt-imagemin' )

使用插件时:pipe( plugins.imagemin() )

而不是: pipe(imagemin())

Gulp 案例: dev-server (browser-sync --dev: 不是gulp插件)

导入插件 | 创建服务器 |创建函数 | 定义配置

配置: notify |port |files|server(baseDir,r)|

const browserSync = require('browser-sync')  // 引入 browser-sync
const bs = browserSync.create()              // 创建服务器

const serve = ()=> {
    bs.init({
        notify: false,                        // 开启显示
        port: 2080,                           // 设置服务器端口 
        files: "dist/**",                     // 监视dist 下文件的变化
        server: {
            baseDir: "dist",                  // 指定文件路径
            routes: {
                '/node_modules': 'node_modules'  
            }
        }
    })
}

监视dist 文件

添加init 配置, 监视文件

files: "dist/**",   // 监视dist 下文件的变化 刷新页面

Gulp 案例: dev-server (监视src 文件变化)

const {watch} = require ('gulp') , 监视文件,判断知否执行任务

watch('参数1:路径',参数2: 任务)

开启server前使用

const serve = ()=> {
    watch('src/assets/styles/*.scss', style)
    watch('src/assets/scripts/*.js', script)
    watch('src/*.html', page)

Gulp 案例: useref 

yarn add gulp-useref --dev

dist 中html 文件内的文件引用打包成vendor 

.pipe( useRef( {searchPath:['dist','.']} ) )

const useRef = require('gulp-useref');

 const ref = ()=>{
     return src('dist/*.html',{base:'dist'})
            .pipe(useRef({searchPath:['dist','.']}))
            .pipe(dest('dist'))
 }

Gulp 案例: 文件压缩(gulp-htmlmin,gulp-clean-css,gulp-uglify)

压缩html,css, js

yarn add gulp-if --dev

compile 完成后 会生成<start> <end> 字符, 根据此来进行压缩, 因此需要先compile 并在写入dist 前完成 压缩

const isif = require('gulp-if');
const htmlMin = require('gulp-htmlmin');
const cleanCss = require('gulp-clean-css');
const uglify = require('gulp-uglify');

 const ref = ()=>{
     return src('dist/*.html',{base:'dist'})
            .pipe(useRef({searchPath:['dist','.']}))
            .pipe(isif(/\.js$/, uglify()) )
            .pipe(isif(/\.css$/, cleanCss()) )
            .pipe(isif(/\.html$/, htmlmin({ 
                collapseWhitespace:true,
                minifyCSS:true,
                minifyJS:true,
            })) )
            .pipe(dest('release'))
 }

第九章: 可复用_自动化构建_工作流

使用脚手架创建新项目 => github 托管

复制 pulpfile.js 至 新项目入口文件 lib/index.js

将源中的devDependencies复制到目标的dependencies 并在目标项目中安装这些文件 yarn

删除 源: gulpfile.js 内容, devDependencies 字符,node_modules文件

将模版在全局link, yarn link

在源文件中 yarn link <name>pages

在源文件中有 scripts 字符, 运行他们,

关于.pipe(babel({ presets:[require('@babel/preset-env')] }))

require()会在自己目录下找,一直向上级找。

yarn add gulp-cli --dev

yarn add gulp --dev

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值