细聊前端工程化

前端工程化通过工具提高效率,解决ES6兼容、CSS预处理、模块化等问题。Node.js驱动前端工程化发展,脚手架如create-react-app、vue-cli等简化项目初始化。自动化构建中,NPM Scripts和Gulp等工具实现任务自动化,减少重复工作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前端工程化概述

1、工程化的定义和主要解决的问题

工程化的定义

  • 前端工程化是指遵循一定的标准和规范,通过工具去提高效率,降低成本的一种手段。
  • 全副武装:通过工程化提升[战斗力]
  • 工程化出现的原因:前端应用功能要求不断提高,业务逻辑日益复杂。

主要解决的问题

技术是为了解决问题而存在的。

  • 想要使用ES6+新特性,但是兼容有问题
  • 想要使用Less/Sass/PostCSS增强CSS的编程性,但是运行环境不能直接支持。
  • 想要使用模块化的方式提高项目的可维护性,但运行环境不能直接支持。
  • 部署上线前需要手动压缩代码及资源文件,部署过程需要手动上传代码到服务器。
  • 多人协作开发,无法硬性统一大家的代码风格,从仓库中pull回来的代码质量无法保证。
  • 部分功能开发时需要等待后端服务接口提前完成。
    在这里插入图片描述

2、一个项目过程中的工程化的表现

  • 一切以提高效率、降低成本、质量保证为目的的手段都属于[工程化]。
  • 一切重复的工作都应该被自动化。 在这里插入图片描述

3、工程化不等于工具

  • 工程化 ≠ 工具
  • 工程化的核心,是对项目整体的规划或架构,而工具只是去帮我们实现这种规划或架构的一种手段。
  • 一个工程化应该有的过程: 在这里插入图片描述
  • 一些成熟的工程化集成
    在这里插入图片描述

4、工程化与Node.js

  • 工程化的一切都应该归功于Node。
  • 如果说Ajax给前端带来了新的生命力,那么Node对于前端而言,它除了让JavaScript有了一个新的舞台,更多的是让我们整个前端行业进行了一次工业革命,可以毫无夸张的说,没有Node.js,就没有今天的前端。
  • 前端工程化是由Node.js强烈驱动的。

脚手架工具

1、脚手架工具概要

  • 前端工程化的发起者。

2、脚手架的作用

  • 本质作用:创建项目基础结构、提供项目规范和约定。
  • 通常开发相同类型的项目时,存在相同的约定:
    • 相同的组织结构
    • 相同的开发范式
    • 相同的模块依赖
    • 相同的工具配置
    • 相同的基础代码
  • 可以通过脚手架工具去快速搭建特定类型项目的骨架,然后去基于这个骨架进行后续开发工作。
  • 比如:Eclipse/Visual Studio 大型IDE创建项目的过程就是一个脚手架的工作流程。
  • 因为前端技术选项比较多样,另外也没有一个统一的标准,所以前端方向的脚手架不会集成在某一个IDE当中,都是以一个独立的工具存在,相对会复杂些。
  • 脚手架目标都是一样的,都是为了解决我们在创建项目过程当中那些复杂的工作。

3、常用的脚手架工具

创建项目时使用的脚手架工具:

  • 适用于特例项目类型服务的脚手架工具
    目前一些成熟的脚手架工具(但大都是为了一些特例项目类型服务的):

    • React项目 => create-react-app
    • Vue.js项目 => vue-cli
    • Angular项目 => angular-cli

    这些工具的实现方式都大同小异,无非都是根据信息创建对应的项目基础结构。

  • 通用性脚手架工具: Yeoman

Yeoman

  • 是一款用于创造现代化web应用的脚手架工具。
  • 不同于cli工具,Yeoman更像是一个脚手架运行平台,我们可以通过它,搭配不同的Generator,去创建任何类型的项目。
  • Yeoman过于通用,不够专注。
  • Yeoman是一款基于Node.js开发的一个工具模块。
  • 使用步骤:
    1. 明确你的需求
    2. 全局范围安装yo:yarn global add yo
    3. 找到合适的Generator
    4. 全局范围安装找到的Generator:yarn global add generator-node
    5. 通过yo运行对应的Generator:yo node
    6. 通过命令行交互填写选项
    7. 生成你所需要的项目结构

项目开发过程中使用的脚手架工具:

  • Plop
    用于在项目开发过程中去创建一些特定类型的文件,例如创建一个组件/模板所需要的文件。
    Plop是一款小而美的脚手架工具。

4、脚手架的工作原理

脚手架工具其实就是一个node cli应用。

自动化构建

一切重复化工作本应被自动化。

1、NPM Scripts

实现自动化构建工作流最简单的方式。

2、常用的自动化构建工具

Grunt

  • Grunt是最早的自动化构建工具,它的插件生态非常完善。
  • 由于它的工作过程是基于临时文件生成的,所以它的构建速度相对较慢。

Gulp

  • 很好的解决了Grunt中构建速度非常慢的问题,因为它是基于内存去实现的。
  • 它默认支持同时去执行多个任务,效率自然大大提高。
  • 使用方式相对于Grunt直观很多。
  • 插件生态也同样非常完善。
  • Gulp的组合任务
const { series, parallel } = require('gulp')

const task1 = done => {
    setTimeout(() => {
        console.log('task1 working');
        done()  //任务完成    
    }, 1000)
}

const task2 = done => {
    setTimeout(() => {
        console.log('task2 working');
        done()  //任务完成    
    }, 1000)
}

const task3 = done => {
    setTimeout(() => {
        console.log('task3 working');
        done()  //任务完成    
    }, 1000)
}

exports.foo = series(task1, task2, task3)  //串行任务
exports.bar = parallel(task1, task2, task3)  //并行任务
  • Gulp的异步任务
//Gulp的异步任务的三种方式
//1、回调函数方式
exports.callback = done => {
    console.log('callback task');
    done()
}
exports.callback_error = done => {
    console.log('callback error task');
    done(new Error('task failed!'))
}
//2、Promise方式
exports.promise = () => {
    console.log('promise task');
    return Promise.resolve()
}
exports.promise_error = () => {
    console.log('promise error task');
    return Promise.reject(new Error('task failed!'))
}
//3、语法糖方式
const timeout = time => {
    return new Promise(resolve => {
        setTimeout(resolve, time)
    })
}
exports.async = async () => {
    await timeout(1000)
    console.log('async task');
}

//其他方式
const fs = require('fs')
// exports.stream = () => {
//     const readStream = fs.createReadStream('package.json')
//     const writeStream = fs.createWriteStream('temp.txt')
//     readStream.pipe(writeStream)
//     return readStream
// }

exports.stream = done => {
    const readStream = fs.createReadStream('package.json')
    const writeStream = fs.createWriteStream('temp.txt')
    readStream.pipe(writeStream)
    readStream.on('end', () => {
        done()
    })
}
  • Gulp文件操作
const { src, dest } = require('gulp')
const cleanCss = require('gulp-clean-css')
const rename = require('gulp-rename')

exports.default = () => {
    return src('src/normal.css')
        .pipe(cleanCss())
        .pipe(rename({ extname: '.min.css' }))
        .pipe(dest('dist'))
}
  • Gulp构建过程核心工作原理
    在这里插入图片描述
//Gulp构建过程核心工作原理
const fs = require('fs')
const { Transform } = require('stream')

exports.default = () => {
    //文件读取流
    const read = fs.createReadStream('a.css')
    //文件写入流
    const write = fs.createWriteStream('a.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, output)
        }
    })
    //把读取处理的文件流导入写入文件流
    read.pipe(transform) //转换
        .pipe(write) //写入
    return read
}
  • Gulp实现的自动化构建
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()
}

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 = () => {
    return src('src/*.html', { base: 'src' })
        .pipe(plugins.swig({ data, defaults: { cache: false } })) // 防止模板缓存导致页面不能及时更新
        .pipe(dest('temp'))
        .pipe(bs.reload({ stream: true }))
}

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'))
}

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)
    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'
            }
        }
    })
}

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
}

封装自动化构建工作流

FIS

  • 是百度前端推荐的一款前端构建系统。
  • FIS更像是一种捆绑套餐。
  • 可以很轻松地去处理资源加载,模块化开发、代码部署和性能优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值