简答题
1、谈谈你对工程化的初步认识,结合你之前遇到过的问题说出三个以上工程化能够解决问题或者带来的价值
初步认识:所谓工程化是指遵循一定的标准和规范通过工具提高效率的一种手段,一切以提高效率、降低成本、质量保证为目的的手段都属于工程化。
解决的问题:
(1)重复的机械工作,比如部署上线前需要手动压缩代码及资源文件,部署过程需要手动上传代码到服务器。
(2)团队开发时,很难做到风格统一,保证质量的完成需求开发
(3)部分功能需要等待后端服务接口完成以后才可以进行开发
(4)无法使用模块化或组件化组织代码
2、你认为脚手架除了为我们创建项目结构,还有什么更深的意义
脚手架可以帮我们快速生成项目,创建项目基础结构。
不仅是创建项目基础结构,更重要的是给开发者提供一种约束和规范,
例如:相同的组织结构,相同的代码开发范式、相同的模块依赖、相同的工具配置,相同的基础代码。更加利于代码维护与团队开发。
编程题
3、概述脚手架实现的过程,并使用 NodeJS 完成一个自定义的小型脚手架工具 (说明文档)
脚手架的工作过程:
1、通过命令行交换询问用户问题
2、根据用户回答的结果产生文件
创建一个node-cli应用
1、yarn init 初始化一个package.json文件
2、在package.json文件中添加bin字段指定自定义cli的入口js文件
//安装项目所需的依赖
3、yarn add inquirer模块 -->prompt方法 发起命令行询问
4、yarn add ejs 模板引擎
5、创建cli.js入口文件 (#!/user/bin/env node 必须有文件头)
通过inquirer模块中prompt方法发起命令行询问,得到问题返回值,
脚手架根据模板生成项目目录,要在根目录下新建一个templates,用于存放模板文件
通过then接受命令行询问得到的答案,
将模板下的文件全部转换到目标目录
首先明确模板目录,path.join(__dirname,'templates')
目标目录,process.cwd()
通过fs.readdir读取模板文件,将得到的文件通过模板引擎ejs.renderFile渲染相对路径对应得文件
将结果通过fs.writeFileSync写入目标目录
const fs=require('fs')
const path=require('path')
const inquirer=require('inquirer')
const ejs=require('ejs')
inquirer.prompt([
{
type:'input',//命令行的输入方式
name:'name',//问题返回值的键
message:'Project name?'//显示的问题
}
])
//根据模板生成项目目录 根目录下新建一个templates
.then(anwsers=>{ //接收答案
//明确模板目录
const tmpDir=path.join(__dirname,'templates')
//目标目录
const destDir=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 err
console.log(result)
//将结果写入目标文件路径
fs.writeFileSync(path.join(destDir,file),result)
})
});
})
})
6、yarn link将自定义脚手架模块link到全局
7、可以在全局使用sample-scaffolding命令
4、尝试使用 Gulp 完成项目的自动化构建(说明文档)
一、安装gulp
yarn add gulp --dev
二、创建gulp入口文件
gulpfile.js
三、安装项目依赖
1、样式编译
yarn add gulp-sass --dev
cnpm install gulp-sass --save-dev
2、脚本编译
yarn add gulp-babel --dev (转换es6平台)
yarn add @babel/core @babel/preset-env --dev (做转换的是插件)
3、页面模板编译
yarn add gulp-swig --dev html模板转换
6、图片和文字编译
yarn add gulp-imagemin --dev
cnpm install gulp-imagemin --save-dev
7、其他文件转换
8、清除项目过程中无指定的无用的文件
yarn add del --dev
9、自动化 加载插件
yarn add gulp-load-plugins --dev
10、热更新开发服务器 引入gulp提供的watch 方法监听文件的修改
yarn add browser-sync --dev
11、将构建之后的js和css文件合并一下
yarn add gulp-useref --dev
12、压缩html、js、css
yarn add gulp-htmlmin gulp-uglify gulp-clean-css --dev
13、yarn add gulp-if --dev
// 实现这个项目的构建任务
const { src, dest, parallel, series, watch } = require('gulp')
const del = require('del') //yarn add del --dev 删除指定文件
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 = () => {
//yarn add @babel/core @babel/preset-env --dev
return src('src/assets/scripts/*.js', { base: 'src' })
.pipe(plugins.babel({ presets: ['@babel/preset-env'] }))//转换平台 presets平台的转换插件
.pipe(dest('temp'))
.pipe(bs.reload({ stream: true }))
}
const page = () => {//yarn add gulp-swig --dev
return src('src/*.html', { base: 'src' })
.pipe(plugins.swig({ data, defaults: { cache: false } })) // 防止模板缓存导致页面不能及时更新
.pipe(dest('temp'))
.pipe(bs.reload({ stream: true }))
}
const image = () => { //yarn add gulp-imagemin --dev
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'))
}
// series 异步执行, parallel, 同步执行
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
}