前端工程化解决的问题:
- 传统语言或语法的弊端 ;
- 无法使用模块化/组件化
- 重复的机械式工作
- 代码风格统一、质量保证
- 依赖后端服务接口支持
- 整体依赖后端项目
脚手架工具
脚手架本质作用:创建项目基础结构、提供项目规范和约定
- 相同的组织结构
- 相同的开发范式
- 相同的模块依赖
- 相同的工具配置
- 相同的基础代码
步骤:
- 在全部范围安装yo
npm install yo --global or yarn global add yo
- 安装对应的generator
npm install generator-node or yarn global add genertor-node
- 安装yo运行generator
yo node
yeoman的常规使用步骤
- 明确你的需求
- 找到合适的Generator
- 全局范围安装找到的Generator
- 通过Yo运行对应的Generator
- 通过命令行交互填写选项
- 生成你所需要的项目结构
自定义Generator
Generator基本结构index.js1
index.js2
Plop
小而美的脚手架
- 将plop模块作为项目开发依赖
- 在项目根目录下创建一个plopfile.js文件
- 在plopfile.js文件中定义脚手架任务
- 编写用于生成特定类型文件的模板
-
通过Plop提供的CLI运行脚手架任务
plop应用文件
自动化构建工具
grunt 的基本使用:
gruntfile.js 文件
module.exports = grunt => {
grunt.registerTask('foo', () => {
console.log('hello grunt~')
})
grunt.registerTask('bar', '任务描述', () => {
console.log('other task~')
})
grunt.registerTask('default', ['foo', 'bar'])
// grunt.registerTask('async-task', () => {
// setTimeout(() => {
// console.log('async task working~')
// }, 1000)
// })
grunt.registerTask('async-task', function () {
const done = this.async()
setTimeout(() => {
console.log('async task working~')
done(false) //标记任务失败
}, 1000)
})
}
grunt的配置
module.exports = grunt => {
grunt.initConfig({
foo: {
bar: 123
}
})
grunt.registerTask('foo', () => {
console.log(grunt.config('foo'))
})
}
grunt 的多目标任务
module.exports = grunt => {
grunt.initConfig({
build:{
options: {
foo: 'bar'
},
css: {
options: {
foo: 'baz'
}
},
js: '2'
}
})
//多目标模式,可以让任务根据配置形成多个子任务
grunt.registerMultiTask('build', function () {
console.log(this.options())
console.log(`target: ${this.target}, data: ${this.data}`)
})
}
grunt 的插件的使用
- 导入插件模块
- 然后使用
grunt.loadNpmTasks()
创建插件任务 - 在
initConfig()
中配置选项
插件使用
grunt 使用案例
const sass = require('sass')
const loadGruntTasks = require('load-grunt-tasks')
module.exports = grunt => {
grunt.initConfig({
sass: {
options: {
sourceMap: true,
implementation: sass
},
main: {
files: {
'dist/css/main.css': 'src/scss/main.scss'
}
}
},
babel: {
options: {
sourceMap: true,
presets: ['@babel/preset-env']
},
main: {
files: {
'dist/js/app.js': 'src/js/main.js'
}
}
},
watch: {
js: {
files: ['src/js/*.js'],
task: ['babel']
},
css: {
files: ['src/scss/*.scss'],
tasks: ['sass']
}
}
})
//自动加载所有grunt 插件任务
loadGruntTasks(grunt)
grunt.registerTask('default', ['sass', 'babel', 'watch'])
// grunt.loadNpmTasks('grunt-sass')
}
gulp
gulpfile.js
exports.foo = (done) => {
console.log('foo task working~')
done() //回调函数,标识任务完成
}
exports.default = (done) => {
console.log('default task working~')
done() //回调函数,标识任务完成
}
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文件操作API
const {src, dest} = require('gulp')
const cleanCss = require('gulp-clean-css')
const rename = require('gulp-rename')
exports.default = () => {
return src('src/*.css')
.pipe(cleanCss())
.pipe(rename({extname: '.min.css'}))
.pipe(dest('dist'))
}
gulp-demo
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
}
网友评论