简答题
1、谈谈你对工程化的初步认识,结合你之前遇到过的问题说出三个以上工程化能够解决问题或者带来的价值。
解答:工程化是指遵循一定的标准和规范通过工具去提高效率,降低成本的一种手段,一切以提高效率、降低成本、质量保证为目的的手段都属于工程化。
工程化主要解决的问题:
(1)重复的机械工作,比如部署上线前需要手动压缩代码及资源文件,部署过程需要手动上传代码到服务器。
(2)团队开发时,很难做到风格统一,保证质量的完成需求开发
(3)部分功能需要等待后端服务接口完成以后才可以进行开发
(4)无法使用模块化或组件化组织代码
2、你认为脚手架除了为我们创建项目结构,还有什么更深的意义?
解答:脚手架可以帮我们快速生成项目,创建项目基础结构。不仅是创建项目基础结构,更重要的是给开发者提供一种约束和规范,例如:相同的组织结构,相同的代码开发范式、相同的模块依赖、相同的工具配置,相同的基础代码。更加利于代码维护与团队开发。
编程题
1、概述脚手架实现的过程,并使用 NodeJS 完成一个自定义的小型脚手架工具
工作原理:启用时自动询问预设的问题,然后将回答的结果结合模板文件生成所需要的项目结构。
- 创建目录 sjj-scaffolding
- 创建 package.json
npm init
- 在package.json中添加bin字段,指定cli文件的入口文件: "bin":"./cli.js"
- 安装所需要得依赖
npm install inquirer --save //询问
npm install ejs --save //添加模板引擎
- 创建cli.js文件
#!/usr/bin/env node
const fs = require('fs')
const path = require('path')
const inquirer = require('inquirer')
const ejs = require('ejs')
const { tmpdir } = require('os')
inquirer.prompt([
{
type: 'input',
name: 'name',
message: 'Project name'
}
]).then(answers => {
console.log(answers)
// 根据用户的回答的结果生成文件
// 模板目录
const templDir = path.join(__dirname, 'templates');
// 目标目录
const destDir = process.cwd();
// 将模板下的文件全部转换到目目录
fs.readdir(templDir, (err, files) => {
if (err) throw err
files.forEach(file => {
// 通过模板引擎渲染文件
ejs.renderFile(path.join(templDir, file), answers, (err, result) => {
if (err) throw err
console.log(result)
// 将结果写入目标目录文件
fs.writeFileSync(path.join(destDir, file), result)
})
});
})
})
- templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= name %></title>
</head>
<body>
</body>
</html>
- npm link 关联到全局变量
npm link
- 执行测试
mkdir test //创建测试文件夹
cd test //切换文件夹
sjj-scaffolding //执行脚手架
2、尝试使用 Gulp 完成项目的自动化构建
- 准备工作
mkdir my-gulp
cd my-gulp
npm init --yes //初始化package文件
- 安装gulp
npm install gulp --save //安裝gulp模块
- 创建gulpfile.js文件
// 实现这个项目的构建任务
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('dist'))
}
// 脚本编译
const script = () => {
return src('src/assets/scripts/*.js', { base: 'src' })
.pipe(plugins.babel({ presets: ['@babel/preset-env'] }))
.pipe(dest('dist'))
}
// 页面模板编译
const page = () => {
return src('src/*.html', { base: 'src' })
.pipe(plugins.swig({ data }))
.pipe(dest('dist'))
}
// 图片和文字编译
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: ['dist','src','public'],
routes: {
'/node_modules': 'node_modules'
}
}
})
}
const compile = parallel(style, script, page, image, font);
const build = series(clean, parallel(compile, extra))
module.exports = {
clean,
compile,
build,
serve
}