近几年来,前端工程化已经被越来越多的提起,在 2018 年的 iweb 大会到今年的 GMTC 全球大前端技术大会上,都可以看到前端工程化的身影。希望通过本场 Chat 可以让大家了解到,如何从无到有搭建一个适合我们使用的前端工程化工具,使我们在少代码或者无代码的情况帮我们处理大部分重复繁琐的工作。
本场 Chat 主要内容:
- 什么是前端自动化构建工具
- 如何搭建前端自动化构建工具
- 自动化构建工具的缺陷
- 前端工程化工具
- 前端工程化工具的开发和发布
- 如何搭建企业私用仓库管理前端工程化工具
- 小结
什么是前端自动化构建工具
在传统的前端项目开发过程中,前端的任务清单是这样的
从上面的用例图我们可以看到,在前端正式开发项目之前,需要先解决大量的问题,在解决上面的这些问题时,我们需要使用不同的工具,比如代码编译工具,css 转译工具等等,一个项目开发过程中我们需要用到很多种工具,这个过程单调而且容易出错,特别是当我们下一步依赖上一个步骤的结果是,比如 less 的编译和 css 的压缩,我们需要编译完成之后在进行压缩。
为了防止这些错误,我们应该尽量的减少操作步骤,我们仔细分析,除了在项目中的开发逻辑之外,其他任务都只是在不同阶段帮我们处理代码而已。如果我们可以把处理代码的地方整合成一个自动化构建工具,帮我们自动完成出了逻辑开发以外所有的任务,那我们的任务清单就变成了这样
从上面我们可以看出,前端自动化构建工具的作用是帮我们解决了 less 编辑,图片 js 压缩,构建环境等等,换句话讲,它帮我们实现了从开发到构建再到打包部署的一个完整的工作流。在 web 项目开发流程中,工作了决定了生产力,那么如何搭建一个前端自动化构建工具呢?
如何搭建前端自动化构建工具
要搭建前端自动构建工具,首先我们要了解它的组成。
前端自动化构建工具组成
构建系统:只需一个命令,可以处理大量的文件变更
依赖管理:管理常用的类库版本信息,提醒类库冲突
脚手架:提供一个项目运行所需的基本文件,只需一个命令就可以创建一个全新的应用或者模板.一个完整的脚手架包含构建系统和依赖管理。
其实在日常的开发中,我们已经用到了很多个前端自动化构建工具了,比如 vue 的 vue-cli,react 的 create-react-app。使用这些构建工具,我们可以通过简单的命令无需做任何配置就能快速的搭建 vue/react 开发环境,并且从开发到单元测试再到我们最后上线之前打包都是一个命令行搞定。
那么如何创建一个简单的自动化构建工具呢?我们以 gulp 举例(Gulp.js 是一个自动化构建工具,开发者可以使用它在项目开发过程中自动执行常见任务)。
var gulp = require('gulp'), //获取 gulp uglify = require('gulp-uglify'), //js 压缩插件 concat = require('gulp-concat'), //js 合并插件 del=require('del'), //删除 cssnano = require('gulp-cssnano'), //css 压缩插件 less=require('gulp-less') , //less 文件编译 autoprefixer = require('gulp-autoprefixer'), //添加 css 前缀 imagemin = require('gulp-imagemin'), //图片压缩插件 htmlmin = require('gulp-htmlmin'), //html 压缩插件 fileinclude = require('gulp-file-include'), //模块化合并 connect=require('gulp-connect'), //服务 proxy = require('http-proxy-middleware'), //代理 rename = require('gulp-rename'), //重命名 revCollector=require('gulp-rev-collector'), //hash reva = require('gulp-rev-append'), //hash rev = require('gulp-rev'), //hash clean = require('gulp-clean');; //清楚//删除 dist 目录下文件gulp.task('clean', done=> { gulp.src("./dist") .pipe(clean()) done(); })//操作 js 文件gulp.task('scripts', done=> { gulp.src('src/js/*.js') //需要操作的源文件 .pipe(uglify()) //压缩 js 文件 .pipe(gulp.dest('dist/js')) //把操作好的文件放到 dist/js 目录下 done(); });//操作 css 文件gulp.task('style', done=> { gulp.src('src/style/*.less') .pipe(less()) //编译 less 文件 .pipe(autoprefixer({//添加 css 前缀 browsers: ['last 4 versions'], cascade: true, //是否美化属性值 默认:true 像这样: remove:false //是否去掉不必要的前缀 默认:true })) .pipe(cssnano()) //css 压缩 .pipe(gulp.dest('dist/style')) done(); });gulp.task('image', done=> { gulp.src('src/images/*.{png,jpg,jpeg,gif}') .pipe(imagemin()) .pipe(gulp.dest('dist/images')) done();});gulp.task('html', done=> { gulp.src(['src/**/*.html','src/*.html']) .pipe(fileinclude({ prefix: '@@', basepath: '@file' })) .pipe(htmlmin({ collapseWhitespace: true, //压缩 html collapseBooleanAttributes: true, //省略布尔属性的值 removeComments: true, //清除 html 注释 removeEmptyAttributes: true, //删除所有空格作为属性值 removeScriptTypeAttributes: true, //删除 type=text/javascript removeStyleLinkTypeAttributes: true, //删除 type=text/css minifyJS:true, //压缩页面 js minifyCSS:true //压缩页面 css })) .pipe(gulp.dest('dist')) done();});//生成 hashcssgulp.task('revCss',done=>{return gulp.src('dist/**/*.css') .pipe(rev()) //文件名加 MD5 后缀 .pipe(rev.manifest()) //必须有这个方法 生成一个 rev-manifest.json .pipe(gulp.dest('dist')); //将 rev-manifest.json 保存到 dist/css 目录内 done();});//js 生成文件 hash 编码并生成 rev-manifest.json 文件名对照映射gulp.task('revJs', done=>{return gulp.src('dist/**/*.js') .pipe(rev()) .pipe(rev.manifest()) .pipe(gulp.dest('dist')); done();});//Html 替换 css、js、img 文件版本gulp.task('revHtml', done=> {return gulp.src(['dist/*.json', 'dist/*.html']) .pipe(revCollector()) .pipe(gulp.dest('dist')); done();});//dev 任务 需要异步执行 axml,ascc,json,js,image 任务gulp.task('server', gulp.series('scripts','style','image','html',done=> { connect.server({ root:'dist', livereload:true, host:'172.30.82.16', port:"8080", middleware:function(req,res,next){ return[proxy('/',{ target:"https://www.example.com", changeOrigin:true }), ] } }) done();}));
上述代码运行 gulp server 就实现了:开发过程中启动本地服务,使用反向代理解决请求跨域,发布阶段自动压缩混淆 js,压缩图片减少应用大小,增加时间戳防止浏览器缓存等等。在开发过程中,使用这个工具,我们简单做到了只关心代码逻辑,这个大大减少了开发时间。
注:针对不同的项目我们可以搭建不同的适合我们使用的脚手架,使用工具也可以选择 gulp,grunt,webpack 等等。总之一句话选择合适的工具创建合适的工作流。
自动化构建工具的缺陷
前端自动化构建帮我们解决了开发过程中的除了逻辑之外的大部分问题,但是却也带来了新的问题。
开发困难:
几乎每个新的项目我们都要走初始化这一步,如果针对每个项目我们都从新开发脚手架,这种费时过长,如果直接粘贴复制以前的脚手架也并一定符合当前项目需要。
碎片化严重:
在不同的项目中,我们可能使用不同的构建工具,比如 vue 项目使用 vue-cli,react 项目使用 create-react-app,或者是其它我们自己开发的构建工具,这就导致了我们在开发过程中需要掌握和使用不同的构建工具构建项目。
前端工程化工具
我们期望出现一个工具,帮我们统一管理这些不同的脚手架,这样我们在初始化项目的时候,输入不同的模板就会生成不同的脚手架。
在我们使用 vue-cli 和 create-react-app 的时候,会发现我们使用命令行和直接 clone vue/react 模板下载到本地的项目是一样的,那就说明,命令行工具给我们提供的就是下载服务,如果我们自己开发一个命令行工具,可以通过不同命令行下载不同的搭建好的脚手架模板,就算是实现了一个简单的前端工程化工具。这里我们就需要了解一下 cli。
命令行页面(command-line interface,缩写 CLI),是在图形用户界面得到普及之前使用最为广泛的用户界面。
前端工程化工具的开发和发布
在搭建 cli 之前,我们首先确定 cli 的功能是什么我们需要知道我们当前已存在的脚手架/模板有哪些,我们需要对脚手架/模板执行增删改查操作,其次我们要对模板有下载 clone 的功能。这就确定了我们工具大体的放向和技术:我们需要用的使用到 node 的 fs 模块对文件进行增删改的操作,我们需要使用 download-git-repo 插件让我们可以实现从远程仓库的 clone 和下载等等。
具体代码实现这里不做过多描述,因为这个我也是从网上跟别人学的,重点放这里有偷剽嫌疑,这个有很多的成品直接给大家提供一个仅供参考。链接:https://pan.baidu.com/s/1QRcdnLiqJ1xshH2DbZp-wA 密码:0nv3。
开发完成之后,我们希望可以像 vue-cli 一样,那就要把开发好的代码发布到 npm 中了,npm 的发布需要账号和密码,申请方式很简单,输入账号密码邮箱就可以了,准备就绪之后发布包之前,我们需要先确定我们们想发布的包名是否被使用,使用 npm search 包名,如果存在会返回作者发布时间版本号等信息,如果报错,恭喜你,这个包名还没有人使用,你可以放心的使用了。
npm login 登录我们的 npm 账号,执行 npm publish 就可以了。更新的话,每次记得修改版本号否则会发布失败。另外 npm 不提供下架功能,所以发布之前注意。
发布完成之后使用方法:拿上面链接中的代码示例。
使用方法:npm install spring-cli -gspring initTemplate name: 模板名称Project name: 自定义项目名称//其他命令添加模板spring add删除模板spring delete初始化模板spring init查看模板列表spring list本地测试需先执行,npm link 全局安装开发好的工具测试
如何搭建企业私用仓库管理前端工程化工具
如果公司处于隐私保护的目的,不想将开发好的工具推到 npm 社区,但是又急需一套完整的包管理工具来管理很多的封装组件,以方便公司内部人员使用,创建一套私有的 npm 仓库很有必要。verdaccio 刚好的解决了这个问题。
安装环境:
centos 服务器,nodejs
搭建过程:
使用 SecureCRT 进入服务器
安装 node.js
yum install -y nodejs
安装 verdaccio
npm install -g verdaccio --unsafe-perm
注:加上--unsafe-pern 的原因是防止包 grywarn 权限错误
修改配置文件 config.yaml,在最后添加监听的端口,端口可修改
listen:0.0.0.0:4873
注:如果不知道 config.yaml 的路径,可以先直接启动 verdaccio,启动日志里面会显示完整路径
warn --- config file - /root/.config/verdaccio/config.yaml
启动 verdaccio
verdaccio
进程守护
为了让 verdaccio 服务不会因为我们关闭 SecureCRT 或者其他情况而停止,采用 nohup 做进程守护
nohup verdaccio &
到此,安装完成,那么如何使用呢使用:
安装 nrm,nrm 是一个 npm 的资源管理器,允许快速的在 npm 源之间切换
npm install -g nrm
使用 nrm 增加私有仓库的源
nrm add exampleName http://www.example.com:8080
执行 nrm ls 查看本机的可选源
nrm ls
显示的所有本机源
npm ---- https://registry.npmjs.org/cnpm --- http://r.cnpmjs.org/taobao - https://registry.npm.taobao.org/* exampleName --- http://www.example.com:8080/
注:带星号的代表当前所使用的源可以使用 nrm use name 切换不同的源
nrm use name
私有仓库搭建完成之后,切换到私有仓库源从新进行 npm 的发布流程就可以了。npm 包管理工具没有提供下架服务,但是私有 npm 包管理工具可以通过删除包内容实现下架。
cd /root/.config/verdaccio
进入 verdaccio 的安装路径,当前路径下有三个文件,config.yaml htpasswd storage。其中 store 文件夹保存的是当前私有仓库已有的 npm 包,找到对应的就可以删除下架。htpasswd 是保存当前私有 npm 包用户名和密码的。config.yaml 中可以设置那些人有权限上传修改内容,那些人有权限使用,还有是否开启注册等等。具体配置方法可以去 verdaccio 的 gitHub 地址 https://github.com/verdaccio/verdaccio 查看配置。
小结
一个完整的前端工程化应该是从编码到发布形成一个完整的闭环的,就像是微信小程序/支付宝小程序的 IDE,它们都提供了从开发到发布的所有服务。因此前面讲的只能算是一个前端工程化工具的半成品,如果可以在项目的自动化构建工具中加入上传打包文件至服务器的脚本才算完整,但是这个需要提前和运维商议好,定好服务器的前端静态资源路径。另外还要考虑到版本回退等等问题。
使用 node.js 开发了一个小的发布管理系统,配合自动化构建工具已经实现了前端发布,版本回退,历史版本等等功能,但是还不完善,没有正式使用。后期有时间会再单独分享。
前端自动化构建帮我们创建了一整套的工作流,前端工程化工具帮我们统一管理繁多的自动化构建工具。在开发中我是这样使用的,对已存在的如 vue-cli,create-react-app 创建出来的项目进行了二次的封装,将项目中常用的如自定义弹框、时间过滤器、价格过滤器、接口过滤等等都加入进去当做项目模板。对支付宝小程序,微信小程序项目,增加了切换不同开发环境的脚本和使用 html+less 开发小程序的脚本,另外把小程序数据请求的封装和常用的自定义组件过滤器等等加入构成支付宝小程序模板和微信小程序模板。
对于普通的 html 页面开发,增加了开发过程中启动本地服务、使用反向代理解决请求跨域、发布阶段自动压缩混淆 js、压缩图片减少应用大小、增加时间戳防止浏览器缓存的脚本。将这几种模板维护至前端工程化工具中,当遇到不同类型项目时,使用命令行初始化对应模板。
总结知识查漏补缺,如有错误或者不足欢迎大神指正补充,在此多谢。
本文首发于 GitChat,未经授权不得转载,转载需与 GitChat 联系。
阅读全文: http://gitbook.cn/gitchat/activity/5d774c4825d32446730a0748
您还可以下载 CSDN 旗下精品原创内容社区 GitChat App ,阅读更多 GitChat 专享技术内容哦。