# Task-02-01 **Repository Path**: fishlyn/Fed-Task-02-01 ## Basic Information - **Project Name**: Task-02-01 - **Description**: No description available - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-06-20 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Part2 模块一作业 ## 简答题 ### 第一题 1、谈谈你对工程化的初步认识,结合你之前遇到过的问题说出三个以上工程化能够解决问题或者带来的价值。 答:工程化指的是一切以提高项目开发效率、降低成本、提高代码质量的手段,不仅如此,工程化还能够解决项目中遇到的一些问题 工程化的意义: * 可以解决 ES6 + 无法在浏览器上运行的问题 * 可以解决 less、sass 预处理器编译的问题 * 可以实现代码的自动压缩,自动部署服务器 * 保持项目的代码风格,代码规范统一 * 通过部署本地服务器,减少对后端服务的依赖 ### 第二题 2、你认为脚手架除了为我们创建项目结构,还有什么更深的意义? 答:脚手架不仅创建了项目结构,还对项目进行了一些规范和约定,比如: * 规定了相同的开发范式 * 规定了相同的模块依赖 * 规定了相同的工具配置 * 规定了相同的基础代码 ## 编程题 ### 第一题 1、概述脚手架实现的过程,并使用 NodeJS 完成一个自定义的小型脚手架工具 答:脚手架实现的过程: 1. 通过命令行交互询问用户问题,获取用户的输入 2. 通过用户输入,动态的生成项目的结构 ```js #!/usr/bin/env node // 必须的头文件,声明以下代码在node环境下运行 const inquirer = require('inquirer') // 实现脚手架的第一步,命令行询问用户配置 // 实现脚手架的第二步,获取模板文件路径,根据用户的输入,动态生成经过模板引擎渲染的文件 const fs = require('fs') const path = require('path') const ejs = require('ejs') // 命令行询问的类型配置对象 const promptList = [ { type: 'input', name: 'name', message: 'Your project name?' } ] // inquirer 的 prompt 方法在全部问题执行完之后会返回所有回答的集合,是个 promise 对象 inquirer.prompt(promptList).then(answers => { // 获取模板目录路径 const tempDir = path.join(__dirname, 'templates') // 获取目标目录路径 const destDir = process.cwd() // 读取模板目录内所有的文件并循环依次在目标目录生成对应的文件 fs.readdir(tempDir, (err, files) => { if (err) throw err files.forEach(file => { ejs.renderFile(path.join(tempDir, file), answers, (err, res) => { if (err) throw err fs.writeFileSync(path.join(destDir, file), res) }) }) }) }) ``` ### 第二题 2、尝试使用 Gulp 完成项目的自动化构建 答:项目的自动化构建需要实现以下几个需求 1. 实现 css 和 js 文件的代码检查 2. 实现 html 的模板编译、less/sass的编译、es6 + 的编译 3. 实现 html、css、js、图片、文字的代码压缩 4. 实现本地开发服务器和监听文件修改并实时编译 5. 将编译后的静态文件发布到 github 的 gh-page 分支预览 6. 将项目提交到 github 仓库做成自动化 ```js // 实现这个项目的构建任务 const { src, dest, series, parallel, watch } = require('gulp') const loadPlugins = require('gulp-load-plugins') const browserSync = require('browser-sync') const minimist = require('minimist') const del = require('del') const Comb = require('csscomb') const standard = require('standard') const plugins = loadPlugins() const bs = browserSync.create() const argv = minimist(process.argv.slice(2)) const data = { menus: [ { name: 'Home', icon: 'aperture', link: 'index.html' }, { name: 'About', link: 'about.html' }, { name: 'Content', link: '#', children: [ { name: 'Twitter', link: 'https://twitter.com' }, { name: 'About', link: 'https://weibo.com' }, { name: 'divider' }, { name: 'About', link: 'https://github.com' } ] } ], pkg: require('./package.json'), date: new Date() } // 清除文件命令 const clean = () => { return del(['temp', 'dist']) } // css 和 js 代码检查 const lint = done => { const comb = new Comb(require('./.csscomb.json')) comb.processPath('src') standard.lintFiles('./src/assets/scripts/*.js', { fix: true }, done) } // 代码编译 const style = () => { return src('src/assets/styles/*.scss', { base: 'src' }) .pipe(plugins.sass()) .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')) } // 将html的引用文件合并压缩 const useref = () => { return src('temp/*.html', { base: 'temp' }) .pipe(plugins.useref({ searchPath: ['temp', '.'] })) .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 devServer = () => { watch('src/assets/styles/**', style) watch('src/assets/scripts/**', script) watch('src/*.html', page) watch([ 'src/assets/image/**', 'src/assets/fonts/**', 'public/**' ], bs.reload) bs.init({ notify: false, port: 3002, server: { baseDir: ['temp', 'src', 'public'], routes: { '/node_modules': 'node_modules' } } }) } // 打开服务器跑生产环境代码 const distServer = () => { bs.init({ notify: false, port: 3003, server: 'dist' }) } // 将编译后的静态项目部署到 github 的 gh-pages 分支预览 const upload = () => { return src('**', { cwd: 'dist' }) .pipe(plugins.ghPages({ cacheDir: 'temp/publish', branch: 'gh-pages' })) } // 添加修改的文件 const gitAdd = () => { return src('.') .pipe(plugins.git.add()) } // 更新本地仓库 const gitCommit = () => { const message = argv.message || 'update' return src('.') .pipe( plugins.git.commit(undefined, { args: `-m "${message}"`, disableMessageRequirement: true }) ) } // 推送到远程仓库 const gitPush = done => { plugins.git.push('origin', 'master', (err) => { if (err) throw err }) done() } // 编译组合任务 const compile = parallel(style, script, page) // 打包生成线上项目 const build = series(clean, parallel(series(compile, useref), image, font, extra)) // 测试生产环境代码是否正常运行 const start = series(build, distServer) // 打开服务器监听开发代码,实时编译 const serve = series(compile, devServer) // 将编译后的静态项目部署到 github 的 gh-pages 分支下 const deploy = series(build, upload) const update = series(gitAdd, gitCommit, gitPush) module.exports = { lint, serve, build, start, clean, deploy, update } ``` ### 第三题 3、使用 Grunt 完成项目的自动化构建 答:项目实现的功能: 1. 实现 html 的模板编译、less/sass的编译、es6 + 的编译 2. 实现 html、css、js、图片、文字的代码压缩 3. 实现本地开发服务器和监听文件修改并实时编译 ```js // 实现这个项目的构建任务 const loadGruntTasks = require('load-grunt-tasks') const sass = require('node-sass') const data = { menus: [ { name: 'Home', icon: 'aperture', link: 'index.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() } module.exports = grunt => { grunt.initConfig({ clean: ['dist', 'temp', '.tmp'], // 清理临时文件 sass: { options: { implementation: sass, outputStyle: 'expanded', sourceMap: true }, main: { files: [{ expand: true, cwd: 'src/assets/styles', src: ['*.scss'], dest: 'temp/assets/styles', ext: '.css' }] } }, babel: { options: { presets: ['@babel/preset-env'], sourceMap: true }, main: { files: [{ expand: true, cwd: 'src/assets/scripts', src: ['*.js'], dest: 'temp/assets/scripts' }] } }, swigtemplates: { options: { templatesDir: 'src' }, main: { context: data, dest: 'temp', src: ['src/*.html'] } }, watch: { styles: { files: ['src/assets/styles/*.scss'], tasks: ['sass'] }, scripts: { files: ['src/assets/scripts/*.js'], tasks: ['babel'] }, pages: { files: ['src/**/*.html'], tasks: ['swigtemplates'] } }, browserSync: { devServer: { bsFiles: { src: ['temp'] }, options: { notify: false, open: true, port: 3002, watchTask: true, server: { baseDir: ['temp', 'src', 'public'], routes: { '/node_modules': 'node_modules' } } } }, distServer: { bsFiles: { src: ['dist'] }, options: { notify: false, open: true, port:3003, server: { baseDir: ['dist'] } } } }, copy: { main: { files: [ { expand: true, cwd: 'public', src: '**', dest: 'dist' }, { expand: true, cwd: 'src', src: ['assets/fonts/**', 'assets/images/**'], dest: 'dist' } ] } }, useminPrepare: { html: 'temp/*.html', options: { dest: 'dist', root: ['temp', '.'] } }, usemin: { html : 'temp/*.html', options: { assetsDirs: ['temp'] } }, htmlmin: { main: { options: { collapseWhitespace: true, minifyCSS: true, minifyJS: true }, files: [{ expand: true, cwd: 'temp', src: ['*.html'], dest: 'dist' }] } } }) loadGruntTasks(grunt) // 编译 sass, es6+, swig模板文件 grunt.registerTask('compile', ['sass', 'babel', 'swigtemplates']) // 开启开发服务器并监听文件变化 grunt.registerTask('serve', ['compile', 'browserSync:devServer', 'watch']) // 将开发文件编译,压缩,打包生成生产目录 grunt.registerTask( 'build', [ 'clean', 'compile', 'useminPrepare', 'concat:generated', 'cssmin:generated', 'uglify:generated', 'usemin', 'htmlmin', 'copy' ] ) // 开启生产服务器,检查生成的文件 grunt.registerTask('start', ['build', 'browserSync:distServer']) } ```