博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
前端脚手架,听起来玄乎,实际呢?
阅读量:6177 次
发布时间:2019-06-21

本文共 5798 字,大约阅读时间需要 19 分钟。

开篇

第一次听说脚手架, 是我刚接触Vue,跟着网上大佬的文章,用Vue-cli从0搭建了一个Vue项目,一步一步配置,然后npm i, npm run dev,打开链接,一个网页就这么写好了,当时对于npm,webpack这些前端工程化一无所知,嘴里不自觉的吐出了两个字:'NB'。一年以后,一位新猿在Segmentfault上发出了:

clipboard.png

然后我就装着知道的样子就去回答了一下,答案是这样的:

clipboard.png

粗狂的讲,这样的回答,好像没什么毛病。但既然是本着学习的态度,那这次就好好的讲一讲前端脚手架存在的意义,到底是个什么鬼,以及写一个脚手架到底有多难?所以接下来,文章将围绕下面几部分来讨论:

  • 前端脚手架存在的意义
  • 脚手架的实质
  • 写一个属于自己的脚手架有多难

前端脚手架存在的意义

随着前端工程化的概念越来越深入人心,脚手架的出现就是为减少重复性工作而引入的命令行工具,摆脱ctrl + c, ctrl + v,此话zenjiang? 现在新建一个前端项目,已经不是在html头部引入css,尾部引入js那么简单的事了,css都是采用Sass或则Less编写,在js中引入,然后动态构建注入到html中;除了学习基本的js,css语法和热门框架,还需要学习构建工具webpack,babel这些怎么配置,怎么起前端服务,怎么热更新;为了在编写过程中让编辑器帮我们查错以及更加规范,我们还需要引入ESlint;甚至,有些项目还需要引入单元测试(Jest)。对于一个更入门的人来说,这无疑会让人望而却步。而前端脚手架的出现,就让事情简单化,一键命令,新建一个工程,再执行两个npm命令,跑起一个项目。在入门时,无需关注配置什么的,只需要开心的写代码;另外,对于很多系统,他们的页面相似度非常高,所以就可以基于一套模板来搭建,虽然是不同的人开发,但用脚手架来搭建,相同的项目结构与代码书写规范,是很利于项目的后期维护的;以上就是为什么脚手架存在的意义, 让项目从"搭建-开发-部署"更加快速以及规范 (出自于某乎达人)。

脚手架的实质

现在流行的前端脚手架都是基于NodeJs编写,比如前面提到的Vue-CLI,比较火的create-react-app,还有Dva-CLI和我司自己curie,都是热门框架react和vue的项目脚手架,其功能都是生成一个通用的目录结构,并配上构建、编译、检查等工程环境。大致流程如下:

  1. 解析用户输入的命令;
  2. 生成一些配置化文件,如package.json, 或webpack.config.js等;
  3. 根据用户的输入生成对应的模板项目;(高级一点的ctrl + c, ctrl + v)
  4. 安装该模板所需要的环境。

先以create-react-app为例,网上有很多读create-react-app源码的文章,可以网上搜索一下,。它的代码不多,读起来也比较容易,最主要的是create-react-app在某种程度上来讲它只做了1,2步的事情(当然4也做了一些),第3步是由react-scripts完成的,当然其还有一个重要作用,就是作为这个项目的构建编译工具,所以你在package.json中还能看到下图靠右这样的命令(熟悉的nmp start, 有木有):

clipboard.png

所以我们知道,create-react-app主要解析命令,执行文件的操作,react-scripts主要提供模板与模板所需要的项目工程化配置,如上图左侧所示,我们能看到其包含了webpack与jest测试的相关配置文件。

而vue-cli的实现与create-react-app稍微有点不一样。首先vue-cli新建工程是那种一步一步问答式命令来进行个性化定制的,而后者是一键搞定的;vue-cli的项目模板来源于github,支持多种模板(可通过vue list查看),通过git下载的,具体模板配置参照,而后者模板来自于react-scripts目录下的两个文件夹(上图中的template与template-typescript);vue-cli构建的项目其构建编译是直接依赖于browserify或webpack这样的构建工具,配置是完全暴露给使用者的,可以再次自定义,而后者是基于webpack进行了一层封装,然后将其暴露为一种新的构建命令,当然也可以运行npm run eject将配置暴露出来。dva是一个比较成熟的react解决方案,比较适合中后台系统,dva-cli与前两者具有较强的相似性,采用roadhog作为其构建编译工具,开发人员,无须关心构建配置,只需关心业务代码的实现(所以大厂的码农自己不注意的话容易发展成码畜)。其还有一个扩展功能,就是项目生成后,可以采用命令添加一个页面,这样确实也能减少一部分的ctrl + c, ctrl + v。
综上,前端脚手架的实质包含两项,命令式的构建项目(解析命令,拷贝项目到本地),提供项目的配置(构建,编译,代码规范检查)。

写一个属于自己的脚手架有多难

整理思路

从上两节的描述,大致整理一下即将要实现的功能:

  1. 命令的解析,这个可以借助实现;
  2. 文件的操作,复制,粘贴,增加,删除,文件内容的新增,替换;这个可以借助实现;
  3. 模板文件,就以自己对前端工程化粗浅的认识,写一个最牛(cu)逼(lou)的模板项目;
  4. 申请一个npm账号,这个不算实现的功能,算附属工作;

以上,感觉是不是实现特简单。不是感觉,是确实很简单。流程如下:

clipboard.png

实现代码

命令解析:

// 四种模板。对应我git仓库四个仓库地址    const tempIndex = {      react: 'reactTemplate', // react 模板      vue: 'vueTemplate', // vue 模板      h5: 'h5Template', // h5模板      dva: 'dvaTemplate', // dva模板    };        let projectName;  // 存储目录    let templateName; // 模板名称    let inputIndex; // 除了拷贝模板,还支持自定义模板路径下载,但感觉有点多此一举    const program = new commander.Command(packageJson.name)      .version('v' + packageJson.version, '-v, --version')      .arguments('
') .arguments('
') .option('-f, --force', 'force delete the exist director') .option('-d, --directly', 'copy the not specified template') .alias('cp') .description('create-doddle react myProject') .action(function (index,name) { inputIndex = index; // 允许目标项目名和要复制的模板类型名顺序颠倒 if (tempIndex[index] || tempIndex[name]) { if (tempIndex[index]) { templateName = tempIndex[index]; projectName = name; } else { templateName = tempIndex[name]; projectName = index; } } if (program.directly) { templateName = index; } }); program.parse(process.argv) // 没有输入任何参数,报语法错误,并打印help if (program.args.length === 0) { console.log(chalk.red('syntax error')); program.help() } if (templateName) { excute(templateName, projectName, program.force); } else { console.log(`the template ${inputIndex} you want download do not exist`); }

文件拷贝:

async function create(temp, project, force = false) {      tempName = temp;      projectName = project;      forceDel = force;      const file = currentPath + projectName;      try {        // 检测项目文件夹是否已存在, 若存在,抛出错误        const res = await fs.pathExists(file);        if (res) {          if (forceDel) {            console.log(green('force remove the exist directory'));            await fs.remove(file);            downloadByGit(renameFile, tempName);          } else {            // 抛出错误,并提示可以使用-f参数来强制删除已存在的项目            console.log(chalk.red('Error, In this directory, the project name already exsits !'));            console.log(chalk.green('you can use option -f to force delete the directory !'));          }          return;        }        // 若不存在,直接从git下载        downloadByGit(renameFile, tempName);      } catch (err) {        console.error(red(err));      }    }

关于chalk,这是一款颜色标记插件,将要打印的文字用不同的颜色标记出来,像下面这样:

clipboard.png

git文件下载:

function downloadByGit(callback, template) {      console.log(green('start download'));      console.log(`git@github.com:closertb/${template}.git`);      const result = spawn(        'git',        ['clone', `git@github.com:closertb/${template}.git`],        { stdio: 'inherit' }      );      const error = result.error;      if (error) {        console.log(red(error));        return;      }      // 定义回调;      callback && callback();    }

主要就这三段代码,就实现了命令的解析,和从git源端拷贝模板到本地。

创建可执行命令

稍微对前端工程化了解的就知道,对于项目,想创建npm run start或npm run dev这样的可执行命令,只需要在package.json的scripts进行定义。而想要创建vue init webpack myapp或dva init myapp这样的命令又怎样做呢?广告之后,马上揭晓(自娱自乐中,请忽视O(∩~∩)O!)

第一步:在你项目的package.json中填上一个bin属性,表明它是可执行的, 并配置好可执行命令和入口文件

clipboard.png

第二步: 在你的入口文件(我这里是根目录的index.js)首行加上一段代码: #!/usr/bin/env node,告诉操作系统执行这个脚本的时候,调用/usr/bin下的node解释器;

第三步:登录你的npm账号,运行npm publish发布你的npm包,

到此,一个简易的脚手架就写好了。

最后

人老了,总喜欢最后唠叨两句,其实不论vue-cli,还是create-react-app,或则dva,其核心功能(最牛逼的)不是命令的解析或者模板的拷贝,这部分只占了它脚手架很小的部分,看起来多,是因为它做了很多兼容,比如帮助、错误检测、系统网络环境检测、回滚这些操作,但这也不是核心。个人觉得核心还是是react-scripts或则roadhog这些构建编译脚本,但归根接地还是得对babel和webpack这些库的深入理解,送给观看这篇文章到这里的你,也勉励一下自己,继续加油。

项目源码地址:

npm包地址:
首发地址:

转载地址:http://hpzda.baihongyu.com/

你可能感兴趣的文章
SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)
查看>>
Apache和PHP结合 及 Apache默认虚拟主机
查看>>
添加自定义监控项目配置邮件告警测试告警不发邮件的问题处理
查看>>
solidity智能合约的经典设计模式
查看>>
华为交换网络基础、基本配置、STP/RSTP
查看>>
SpringCloud 微服务 (十七) 容器部署 Docker
查看>>
不定项选择题
查看>>
netty 分析博客
查看>>
Spring Cloud构建微服务架构服务注册与发现
查看>>
BCGControlBar教程:如何将MFC控件的BCGControlBarBCGSuite添加到对话框中
查看>>
深入理解Java8 Lambda表达式
查看>>
Java集合框架面试问题集锦
查看>>
Java每天10道面试题,跟我走,offer有!(六)
查看>>
四种途径提高RabbitMQ传输数据的可靠性(二)
查看>>
c语言实现多态
查看>>
Linux 在 TOP 命令中切换内存的显示单位
查看>>
浏览器的加载与页面性能优化
查看>>
RabbitMQ学习总结(2)——安装、配置与监控
查看>>
Java基础学习总结(5)——多态
查看>>
shell: demo
查看>>