文章内容输出来源:拉勾教育大前端高薪训练营
简答题
1、谈谈你对工程化的初步认识,结合你之前遇到过的问题说出三个以上工程化能够解决问题或者带来的价值。
工程化就是通过一些方法去提升研发效率和研发质量的手段。
- 提升效率
- 脚手架
- 自动化构建
- 组件化
- 模块化
- 保证质量
- ESlint代码检测
- git commit提交规范
- 单元测试
2、你认为脚手架除了为我们创建项目结构,还有什么更深的意义?
- 提升效率,可以快速搭建一个基础项目架构
- 规范化 对技术选型、项目结构等做一些规范,以降低沟通成本
编程题
1、概述脚手架实现的过程,并使用 NodeJS 完成一个自定义的小型脚手架工具
- 实现过程
- 创建一个仓库(目录)
- 通过
npm init
初始化 - 创建一个入口js文件
- package.json 文件增加
"bin":"入口文件路径"
- 通过
npm link
命令连接全局 - 命令行运行脚手架命令
- 后面可以通过
npm publish
发布到npm仓库
- 实操 ( toy-cli 文件夹)
- 1、创建一个目录toy-cli,在改目录下执行
npm init -y
初始化 - 2、目录下创建bin文件夹,文件夹下新建index.js文件
#! /usr/bin/env node // index.js初始内容 console.log('toy cli 入口文件');
- 3、package.json增加一行
"bin":"bin/index.js"
- 4、通过
npm link
命令链接到全局 - 5、命令行运行
toy-cli
就能看到在index.js文件中的log语句输出了
- 6、剩下的工作就是在index.js 文件写自定义逻辑了
demo:通过命令行询问的方式,让用户输入、选择一些信息,然后通过fs模块读取模板文件,使用ejs渲染数据后写入到项目目录的dist文件夹下。
结果:
主要代码片段
- 1、创建一个目录toy-cli,在改目录下执行
#! /usr/bin/env node
// console.log('toy cli 入口文件');
const inquirer = require('inquirer')
const path = require('path')
const fs = require('fs')
const ejs = require('ejs')
// 命令行询问配置项
const {selectConfig} = require('./select.config')
inquirer.prompt(selectConfig).then(answer => {
const tmpl = path.join(process.cwd(),'template');
const dist = process.cwd()
fs.readdir(tmpl,(err,files)=>{
if(err) throw err;
files.forEach(file=>{
// console.log(path.join(tmpl,file));
ejs.renderFile(path.join(tmpl,file),answer,(renderErr,res)=>{
if(renderErr) throw renderErr;
let sonDir = path.join(dist,'dist')
fs.mkdir(sonDir, {recursive: true}, (err) => {
if (err) throw err;
fs.writeFileSync(path.join(sonDir,file), res);
});
})
})
})
})
2、尝试使用 Gulp 完成 项目 的自动化构建
-
主要任务
- gulp-sass 编译scss文件
- gulp-babel 编译JS
- gulp-imagemin 处理图片、 字体
- 拷贝静态资源
- gulp-swig 处理HTML模板文件
- browser-sync 搭建开发服务器
- 监听文件改变
- gulp-useref gulp-if文件引用处理
- gulp-load-plugins 自动加载插件
-
组合任务
- develop 用于开发环境
- build 用于生产
const develop = series(parallel(style,js,html),ref, server) const build = series(clean,parallel(style,js,html,img,extra,font))
-
package.json配置脚本
"scripts": {
"dev": "yarn gulp develop",
"build":"yarn gulp build"
},
任务配置
// 实现这个项目的构建任务
const { src, dest ,watch,series,parallel} = require('gulp')
const del = require('del')
// const sass = require('gulp-sass')
// const babel = require('gulp-babel')
// const imagemin = require('gulp-imagemin')
// const swig = require('gulp-swig')
// const ifg = require('gulp-if')
// const useref = require('gulp-useref')
// const uglify = require('gulp-uglify')
// const cleanCss = require('gulp-clean-css')
const gulpLoadPlugins = require('gulp-load-plugins')
const plugins = gulpLoadPlugins()
//
const browserSync = require('browser-sync')
const bs = browserSync.create()
const data = require('./package.json')
// 编译scss
const style = () => {
return src('src/assets/styles/*.scss')
.pipe(plugins.sass({ outputStyle: 'expanded' }))
.pipe(dest('dist/css'))
}
// 编译JS
const js = () => {
return src('src/assets/scripts/*.js')
.pipe(plugins.babel({ presets: ['@babel/preset-env'] }))
.pipe(dest('dist/js'))
}
// 处理图片
const img = () => {
return src('src/assets/images/**')
.pipe(plugins.imagemin())
.pipe(dest('dist/img'))
}
// 处理字体
const font = () => {
return src('src/assets/fonts/**')
.pipe(plugins.imagemin())
.pipe(dest('dist/font'))
}
// 拷贝静态资源
const extra = () => {
return src('public/**')
.pipe(dest('dist/public'))
}
// 处理HTML文件
const html = ()=>{
return src(['src/*.html','src/layouts/*.html','src/partials/*.html'])
.pipe(plugins.swig({data:{pkg:data}}))
.pipe(dest('dist'))
}
// 清除构建后的目录
const clean = () => {
return del('dist')
}
const server = ()=>{
watch('src/assets/styles/*.scss',style)
watch('src/assets/scripts/*.js',js)
watch(['src/assets/fonts/**','src/assets/images/**'],bs.reload)
bs.init({
notify:false,
files:'dist',
server:{
baseDir:['dist','src','public'],
routes:{
'/node_modules':'node_modules'
}
}
})
}
// 文件引用处理
const ref = ()=>{
return src('dist/*.html')
.pipe(plugins.useref({searchPath:['dist','.']}))
.pipe(plugins.if(/\.js$/,plugins.uglify()))
.pipe(plugins.if(/\.html$/,plugins.htmlmin({collapseWhitespace:true,minifyCSS:true,minifyJS:true})))
.pipe(plugins.if(/\.css$/,plugins.cleanCss()))
.pipe(dest('dist'))
}
const develop = series(parallel(style,js,html),ref, server)
const build = series(clean,parallel(style,js,html,img,extra,font))
module.exports = {
clean,
develop,
build
}
3、使用 Grunt 完成 项目 的自动化构建
- 主要任务(这个项目主要做了以下几个任务)
- grunt-sass 编译scss文件
- grunt-babel编译ES6—>ES5
- grunt-contrib-watch 监听文件改变
- grunt-contrib-clean 清除编译后的文件
- grunt-contrib-copy 拷贝静态文件
- grunt-contrib-uglify 压缩js文件
- 组合任务
- develop 用于开发环境 编译scss、编译ES6、监听文件改变
- default 用于生产 拷贝静态文件、清除编译后的文件、编译scss、编译ES6、,压缩JS
grunt.registerTask('develop',['sass','babel','watch']) grunt.registerTask('default',['clean','copy','sass','babel','uglify'])
- 配置package.json脚本
"scripts": {
"dev":"yarn grunt develop",
"build":"yarn grunt"
},
参考配置
// grunt 构建任务
const sass = require('sass')
const loadGruntTask = require('load-grunt-tasks')// 加载grunt插件
module.exports = grunt =>{
grunt.initConfig({
babel:{
options:{
presets:['@babel/preset-env']
},
main:{
files:{
'dist/assets/scripts/main.js':'src/assets/scripts/main.js'
}
}
},
// 压缩js
uglify: {
my_target: {
files: {
'dist/assets/scripts/main.min.js': ['dist/assets/scripts/main.js']
}
}
},
// 处理scss文件
sass:{
options:{
sourceMap:true,
implementation:sass//使用sass处理编译
},
main:{//配置目标
files:{
'dist/assets/styles/main.css':'src/assets/styles/main.scss'
}
}
},
// 拷贝静态文件
copy:{
main: {
expand: true,
src: 'public/*',
dest: 'dist/',
}
},
clean:{
dist:'dist/**'
},
// 监视文件变化
watch:{
js:{
files:['src/assets/scripts/*.js'],
task:['babel']
},
css:{
files:['src/assets/styles/*.scss'],
task:['sass']
}
}
})
grunt.loadNpmTasks('grunt-contrib-clean') //删除构建后的文件
// grunt.registerTask('foo',()=>{
// console.log('foo task');
// })
// grunt.loadNpmTasks('grunt-sass')
// grunt.loadNpmTasks('grunt-babel')
loadGruntTask(grunt)//自动加载所有插件
grunt.registerTask('develop',['sass','babel','watch'])
grunt.registerTask('default',['clean','copy','sass','babel','uglify'])
}
答案仅供参考