2.1 作业
前端工程化是使用软件工程的技术和方法来进行前端的开发流程、 技术、 工具、 经验等规范化、 标准化, 其主要目的为了提高效率和降低成本, 即提高开发过程中的开发效率, 减少不必要的重复工作时间, 而前端工程本质上是软件工程的一种, 因此我们应该从软件工程的角度来研究前端工程。
- 减少重复的机械式工作 比如部署测试环境 部署到线上环境
- 可以使用模块化 组件化 开发项目 提高开发效率
- 保证代码风格的统一,保证代码的质量
提供一种约束和规范,例如:相同的组织结构,相同的代码开发范式、相同的模块依赖、相同的工具配置,相同的基础代码。更加利于代码维护与团队开发。总而提高开发效率,增强代码质量
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?'
},
{
type: 'list',
name: 'theme',
message: 'Select the theme color',
choices: ['Dark', 'Light'],
filter: function (val) {
return val.toLowerCase();
},
},
{
type: 'checkbox',
message: 'Select what to include',
name: 'content',
choices: [
{
name: 'Header',
},
{
name: 'Body',
},
{
name: 'Footer',
},
],
validate: function (answer) {
if (answer.length < 1) {
return 'You must choose at least one content.';
}
return true;
},
},
])
.then(anwsers => {
const tmplDir = path.join(__dirname, 'templates')
const destDir = process.cwd()
fs.readdir(tmplDir, (err, files) => {
if (err) throw err
files.forEach(file => {
ejs.renderFile(path.join(tmplDir, file), anwsers, (err, result) => {
if (err) throw err
fs.writeFileSync(path.join(destDir, file), result)
})
})
})
})
// gulpfile.js
//gulp的入口文件
//导入文件路径API
const {
dest,
src,
series,
parallel,
watch
} = require('gulp')
const loadPlugins = require('gulp-load-plugins')
const browserSync = require('browser-sync')
const plugin = new 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 = () => {
/**
* 但是并没有与src一样的路径。所以需要指定 {base:'src'}
*/
return src('src/assets/styles/*.scss', {
base: 'src'
}).pipe(plugin.sass())
.pipe(dest('dist'))
}
const script = () => {
return src('src/assets/scripts/*.js', {
base: 'src'
}).pipe(plugin.babel({
presets: ['@babel/preset-env']
}))
.pipe(dest('dist'))
}
const page = () => {
return src("src/*.html", {
base: 'src'
}).pipe(plugin.swig({
data
})).pipe(dest('dist'))
}
const image = () => {
return src("src/assets/images/**", {
base: 'src'
}).pipe(plugin.imagemin()).pipe(dest('dist'))
}
const fonts = () => {
return src("src/assets/fonts/**", {
base: 'src'
}).pipe(plugin.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/**",fonts)
// watch("public/**",extra)
watch([
'src/assets/images/**',
'src/assets/scripts/*.js',
'src/*.html'
], bs.reload)
bs.init({
server: {
port: 8080,
// baseDir: 'dist',
baseDir: ["dist", "public", "src"],
files: 'dist/**',
// open:false,
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(page, script)
//上线之前执行的任务
const build = series(
clean,
parallel(
series(compile, useref),
image,
font,
extra
)
)
const develop = series(compile, serve)
module.exports = {
clean,
compile,
build,
develop
}
//Grunt的入口文件
//用于定义一些需要Grunt自动执行的任务
//需要导出一个函数,接收一个grunt的参数
/**
* yarn add grunt-contrib-clean
* 自动清除临时文件
*/
const path = require('path');
const sass = require('sass');
const del = require('del');
const browserSync = require('browser-sync');
const loadGruntTasks = require('load-grunt-tasks');
const autoprefixer = require('autoprefixer');
const stylelint = require('stylelint');
const scss = require('postcss-scss');
const reporter = require('postcss-reporter');
const minimist = require('minimist');
const bs = browserSync.create();
const cwd = process.cwd();
const args = minimist(process.argv.slice(2));
const isProd = process.env.NODE_ENV ? process.env.NODE_ENV === 'production' : args.production || args.prod || false;
const bsInit = {
notify: false,
port: args.port || 2080,
open: args.open || false,
};
let config = {
build: {
src: 'src',
dist: 'dist',
temp: 'temp',
public: 'public',
paths: {
styles: 'assets/styles/**/*.scss',
scripts: 'assets/scripts/**/*.js',
pages: '**/*.html',
images: 'assets/images/**/*.{jpg,jpeg,png,gif,svg}',
fonts: 'assets/fonts/**/*.{eot,svg,ttf,woff,woff2}',
},
},
};
try {
const loadConfig = require(`${cwd}/pages.config.js`);
config = { ...config, ...loadConfig };
} catch (e) { }
module.exports = (grunt) => {
grunt.initConfig({
sass: {
options: {
sourceMap: !isProd,
implementation: sass,
outputStyle: 'expanded',
},
main: {
expand: true,
cwd: config.build.src,
src: [config.build.paths.styles],
dest: config.build.temp,
ext: '.css',
},
},
postcss: {
main: {
options: {
processors: [
autoprefixer(),
],
},
expand: true,
cwd: config.build.temp,
src: ['assets/styles/**/*.css'],
dest: config.build.temp,
},
lint: {
options: {
processors: [
stylelint({ fix: args.fix }),
reporter(),
],
},
src: `${path.join(config.build.src, config.build.paths.styles)}`,
},
},
eslint: {
options: {
fix: args.fix,
},
main: `${path.join(config.build.src, config.build.paths.scripts)}`,
},
babel: {
options: {
sourceMap: !isProd,
presets: ['@babel/preset-env'],
},
main: {
expand: true,
cwd: config.build.src,
src: [config.build.paths.scripts],
dest: config.build.temp,
ext: '.js',
},
},
html_template: {
options: {
cache: false,
locals: config.data,
},
main: {
expand: true,
cwd: config.build.src,
src: [config.build.paths.pages, '!layouts/**', '!partials/**'],
dest: config.build.temp,
ext: '.html',
},
},
imagemin: {
image: {
expand: true,
cwd: config.build.src,
src: [config.build.paths.images],
dest: config.build.dist,
},
font: {
expand: true,
cwd: config.build.src,
src: [config.build.paths.fonts],
dest: config.build.dist,
},
},
copy: {
main: {
expand: true,
cwd: config.build.public,
src: ['**'],
dest: config.build.dist,
},
html: {
expand: true,
cwd: config.build.temp,
src: [config.build.paths.pages],
dest: config.build.dist,
},
},
useminPrepare: {
main: {
expand: true,
cwd: config.build.temp,
src: [config.build.paths.pages],
},
options: {
dest: config.build.dist,
root: [config.build.temp, '.', '..'],
},
},
usemin: {
main: {
expand: true,
cwd: config.build.dist,
src: [config.build.paths.pages],
},
options: {},
},
'gh-pages': {
options: {
base: config.build.dist,
branch: 'gh-pages-grunt',
},
main: ['**'],
},
watch: {
script: {
files: [`${path.join(config.build.src, config.build.paths.scripts)}`],
tasks: ['babel'],
},
style: {
files: [`${path.join(config.build.src, config.build.paths.styles)}`],
tasks: ['style'],
},
page: {
files: [`${path.join(config.build.src, config.build.paths.pages)}`],
tasks: ['html_template'],
},
},
browserSync: {
dev: {
bsFiles: {
src: [
config.build.temp,
config.build.dist,
],
},
options: {
...bsInit,
watchTask: true,
server: {
baseDir: [config.build.temp, config.build.dist, config.build.public, config.build.src],
routes: {
'/node_modules': 'node_modules',
},
},
},
},
prod: {
bsFiles: {
src: config.build.dist,
},
options: {
...bsInit,
server: {
baseDir: config.build.dist,
},
},
},
},
});
loadGruntTasks(grunt);
grunt.registerTask('reload', () => {
bs.reload();
});
grunt.registerTask('stylesLint', []);
grunt.registerTask('scriptsLint', []);
grunt.registerTask('clean', () => {
del.sync([config.build.dist, config.build.temp, '.tmp']);
});
grunt.registerTask('style', ['sass', 'postcss:main']);
grunt.registerTask('compile', ['style', 'babel', 'html_template']);
grunt.registerTask('build', [
'clean',
'compile',
'copy',
'useminPrepare',
'concat:generated',
'cssmin:generated',
'uglify:generated',
'usemin',
'imagemin',
]);
grunt.registerTask('serve', ['compile', 'browserSync:dev', 'watch']);
grunt.registerTask('start', ['build', 'browserSync:prod']);
grunt.registerTask('deploy', ['build', 'gh-pages']);
grunt.registerTask('lint', ['postcss:lint', 'eslint']);
};
gulp 过程
使用 清除 clean
使用 style 和script 进行 代码的 转化 es6转es5 scss 转 css
使用 image fonts 方法 压缩 图片 和 字体
使用 extra 去 拷贝其他文件
使用 watch 去监听代码的改动 通过browserSync 去实现 浏览器实时更新
最后通过useref 方法 去 压缩 混淆 代码
clean: del
compile:拆分为 style script page 同时执行
style:在处理sass的基础上 引入gulp-postcss 处理 autoprefixer, 后期可扩展更多postcss功能
script: 处理js 引入 gulp-babel 并 @babel/preset-env 来处理 es6+ 功能
page: 查看html文件为swig 文件,并且layouts,partials 文件夹下的为非入口文件 所以在src 添加ignore 排除这两个目录下的文件 在进行处理
serve:拆分为 compile devServe 首先生成 temp内容 然后开启开发服务器 监听变化 显示变化
devServe:将生成在 temp 目录下的文件 首先用watch 监听文件变化css js html 进行实时监听,实时编译。 browserSync 开启静态服务 未查询到的文件 可通过 路由处理 及 文件来源查找进行处理
build:拆分为clean 及重新打包 (先 compile 后 useref )在打包静态资源类 image,font,extra
useref: 在temp下 根据 html 注释 解析文件 将资源文件css 和 js 打包 根据引用资源 在 压缩js css html 生成在 dist 目录下
image,font:经过 imagemin 压缩处理 生成在dist目录下
extra:直接拷贝到dist目录下
start:拆分为**build **及 prodServe 处理
prodServe: 将生成的 dist 目录下的文件 通过 browserSync 开启静态服务器
deploy:拆分为 build 及 publish 处理
publish:将 生成的 dist 目录下的文件 通过gulp-gh-pages 插件 进行处理 发布到 gh-pages分支下
lint: 拆分为 stylesLint 及 scriptLint 处理 又添加了 gulp lint --fix 添加修复功能
styleLint: 通过gulp-postcss 结合相应 stylelint 插件 在根目录下.stylelintrc.json 文件引入 stylelint-config-sass-guidelines 对sass 文件进行文件 lint
scriptLint: 通过gulp-eslint 在根目录下.eslintrc.js 引入 eslint-config-airbnb-base 进行 强校验 保证代码质量
-
--production --port 5020 --open --fix 等 可通过 process.argv 获取 查询到 minimist 可进行相应处理 处理结果 可以直接拿到
-
--production 判断是否存在 存在可生成 js,css sourcemaps 文件
-
项目配置化,变量统一化, 可读取pages.config.js文件 可填写相应配置项 及 data数据