《前端那些事》从0到1开发简单脚手架

简介: 上一篇树酱讲《前端工程化那些事》,聊到脚手架,不过时间比较仓促,导致内容较少,而在我实践开发中,随着新项目愈来愈多,脚手架工具就起到提高效能的作用,借此机会跟小伙伴们分享下我是如何从0到1开发一个简单脚手架

微信截图_20220512150229.png


上一篇树酱讲《前端工程化那些事》,聊到脚手架,不过时间比较仓促,导致内容较少,而在我实践开发中,随着新项目愈来愈多,脚手架工具就起到提高效能的作用,借此机会跟小伙伴们分享下我是如何从0到1开发一个简单脚手架


1.什么是脚手架


脚手架用于快速生成新项目的目录模板,并集成一系列体系化工具的安装,能够提升前端开发人员的效率,减少copy操作


目前比较主流的脚手架:


  • Vue脚手架:Vue-cli
  • React脚手架:create-react-app
  • Yeoman


2.我期望的脚手架


而我所期望的脚手架是怎么样的呢?


当我要开启一个新项目的开发,可以快速生成新项目的目录模板,而这个目录结构是每个项目统一个模版规范(目录规范),同时也设定了通用的配置包括如下


  • 通用的Webpack配置(vue cli 3x 以上是vue.config.js)
  • 统一的Eslint 校验规则:如Airbnb、eslint-plugin-vue等(eslintConfig)
  • 统一的单元测试框架配置:单元测试覆盖率、测试的目录等
  • 统一的Dockerfile和jenkinsfile (用来打包成镜像和部署流水线定义)
  • 统一babel的配置(.babelrc或babel.config.js)
  • 统一的常量配置(缓存字段等等)
  • 不同环境的配置文件(development、test、production)


没有脚手架,我只能通过copy拷贝代码来完成,这样繁琐又机械化的操作浪费大量时间,而且还可能在拷贝过程中,因为某个细节出错,导致项目出错,排查问题又耗时。或许你可能会想,我们不是可以用vue或者react官方的脚手架来生成模版吗?是,但是这种方式创建的模版不一定符合你内部结构化标准


为了解决上述问题,脚手架就起到一个至关重要的角色,我们可以通过脚手架来约束好规范,统一的配置,来打通新项目的开发工具链,一方面提升开发效率,一方面则提高项目对接可维护性及新员工熟悉项目简易性。


3.开发脚手架


3.1 如何开发


如果是要开发一个高度可定制化的脚手架,需要考虑的因素很多,因为某种限制,选择了一种简易的方式来实现内部的脚手架工具,远离就是通过准备两个模版,一个是pc端的,另一个是mobile端的模版,然后用git管理起来,我需要如下工具:


  • 可用于控制台选择的工具:inquirer
  • 可处理控制台命令的工具:commander
  • 可改变输出log颜色的工具:chalk
  • 可执行shell命令的工具: child_process


入口文件 index.js


#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const chalk = require('chalk');
const commander = require('commander');
const inquirer = require('inquirer');
const checkDire = require('./utils/checkDire.js');
const { exec } = require('child_process');
const { version } = require('../package.json');
const { promptTypeList } = require('./config');
//version 版本号
commander.version(version, '-v, --version')
  .command('init <projectName>')
  .alias("i")
  .description("输入项目名称,初始化项目模版")
  .action(async (projectName,cmd) => {
    await checkDire(path.join(process.cwd(),projectName),projectName);   // 检测创建项目文件夹是否存在
    inquirer.prompt(promptTypeList).then(result => {
      const {url, gitName, val} = result.type;
      console.log("您选择的模版类型信息如下:" + val);
      console.log('项目初始化拷贝获取中...');
      if(!url){
        console.log(chalk.red(`${val} 该类型暂不支持...`));
        process.exit(1);
      }
      exec('git clone ' + url, function (error, stdout, stderr) {
        if (error !== null) {
          console.log(chalk.red(
            `clone fail,${error}`
          ));
          return;
        }
        fs.rename(gitName, projectName, (err)=>{
          if (err) {
            exec('rm -rf '+gitName, function (err, out) {});
            console.log(chalk.red(`The ${projectName} project template already exist`));
          } else {
            console.log(chalk.green(`The ${projectName} project template successfully create(项目模版创建成功)`));
          }
        });
      });
    })
  });
commander.parse(process.argv);


这里定义的是npm包命令bin的入口文件


微信截图_20220512150255.png


需要注意在文件前面定义#!/usr/bin/env node


#!/usr/bin/env node设置后,可以让系统动态的去查找node,已解决不同机器不同用户设置不一致问题


检测目录是否存在


// utils/checkDire.js
const fs = require('fs');
const chalk = require('chalk');
const path = require('path');
module.exports = function (dir,name) {
  let isExists = fs.existsSync(dir);
  if (isExists) {
    console.log(chalk.red(
      `The ${name} project already exists in  directory. Please try to use another projectName`
    ));
    process.exit(1);
  }


配置文件


// config/index.js
配置文件
/*
  @dest: 使用配置文件
  @Author: tree
 */
module.exports  = {
  promptTypeList:[{
      type: 'list',
      message: '请选择拉取的模版类型:',
      name: 'type',
      choices: [{
        name: 'mobile',
        value: {
          url: '',
          gitName: 'vue-web-template',
          val:'移动端模版'
        }
      },{
        name: 'pc',
        value: {
          url: 'https://github.com/littleTreeme/vue-web-template.git',
          gitName: 'vue-web-template',
          val:'PC端模版'
        }
      }]
  }],
};


源码链接:github.com/littleTreem…  如果你觉得实用请给个🌟支持,在此感谢


3.2 工具详解


  • inquirer


一个用户与命令行交互的工具


基本用法  🔗使用文档


const inquirer = require('inquirer');
const promptList = [
     type: 'list',
     message: '请选择拉取的模版类型:',
     name: 'type',
      choices: ['mobile','pc']
];
inquirer.prompt(promptList).then(type => {
    console.log(type); // 返回 mobile 或 pc
})


场景如下


微信截图_20220512150307.png


  • commander


commander是一个轻巧的nodejs模块,提供了用户命令行输入和参数解析强大功能


使用到的commander API 🔗使用文档


const commander = require('commander');
commander.version(version, '-v, --version')
  .command('init <projectName>') 
  .alias("i") 
  .description("输入项目名称,初始化项目模版") 
  .action(async (projectName,cmd) => {
      console.log(projectName,'你输入的<projectName>')
  })
commander.parse(process.argv);
// command – 定义命令行指令,后面可跟上一个name,用空格隔开
// alias – 定义一个更短的命令行指令
// description – 描述,它会在help里面展示
// option – 定义参数
// action – 注册一个callback函数
// parse - 解析命令行


  • chalk


node终端样式库,让你的日志样式更美观,主要用chalk来区别错误与成功的日志


如何使用 🔗使用文档


const chalk = require('chalk');
// 报错日志用红色来显示
chalk.red(`The project already exists in  directory. Please try to use another projectName`));
// 成功日志用绿色来显示
chalk.green(`The project template successfully create(项目模版创建成功)`);


3.3 如何使用


可以先通过试着本地安装尝试流程阅读使用文档


微信截图_20220512150317.png


如下所示是自己开发的一个kdv-cli运行时的示意图


微信截图_20220512150329.png


那么 kdv-cli 命令是怎样映射进去的?,原因在于 package.json 里面的 定义了 bin 字段;


// package.json
"bin": {
    "kdv-cli": "./bin/index.js"
 },


我选择pc类型,然后创建名为 test的项目(暂还不支持mobile)

微信截图_20220512150344.png

重复创建则报错

微信截图_20220512150355.png

拉取后的项目目录结构如下所示:


微信截图_20220512150405.png


4.注意事项


  • 注意事项


当你完成脚手架开发时,你想本地测试是否成功运作,会出现这种情况


微信截图_20220512150419.png


这是因为你本地找不到命令执行的路径,没有映射到bin中去,那么如何在本地测试刚开发玩的脚手架工具命令,那就是用npm link,如下所示即可


微信截图_20220512150432.png

5.结尾


通过上文所述,我们就从0到1完成kdv-cli脚手架开发 ,该工具或许不太适用于每个场景,但可以梳理一个简单的脚手架的搭建过程,为后期做更全面、功能更强大的脚手架奠定基础,如果你喜欢,请给树酱点个✨ github.com/littleTreem…


往期文章




相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
4天前
|
缓存 监控 前端开发
【Flutter 前端技术开发专栏】Flutter 应用的启动优化策略
【4月更文挑战第30天】本文探讨了Flutter应用启动优化策略,包括理解启动过程、资源加载优化、减少初始化工作、界面布局简化、异步初始化、预加载关键数据、性能监控分析以及案例和未来优化方向。通过这些方法,可以缩短启动时间,提升用户体验。使用Flutter DevTools等工具可助于识别和解决性能瓶颈,实现持续优化。
【Flutter 前端技术开发专栏】Flutter 应用的启动优化策略
|
2天前
|
移动开发 前端开发 JavaScript
前端高效开发JavaScript库!
前端高效开发JavaScript库!
|
2天前
|
设计模式 存储 前端开发
JS的几种设计模式,Web前端基础三剑客学习知识分享,前端零基础开发
JS的几种设计模式,Web前端基础三剑客学习知识分享,前端零基础开发
|
4天前
|
Web App开发 前端开发 JavaScript
什么是 Web 应用开发领域的 Frontend Fragmentation(前端碎片化)现象
什么是 Web 应用开发领域的 Frontend Fragmentation(前端碎片化)现象
10 0
|
4天前
|
Dart 前端开发 测试技术
【Flutter前端技术开发专栏】Flutter开发中的代码质量与重构实践
【4月更文挑战第30天】随着Flutter在跨平台开发的普及,保证代码质量成为开发者关注的重点。优质代码能确保应用性能与稳定性,提高开发效率。关键策略包括遵循最佳实践,编写可读性强的代码,实施代码审查和自动化测试。重构实践在项目扩展时尤为重要,适时重构能优化结构,降低维护成本。开发者应重视代码质量和重构,以促进项目成功。
【Flutter前端技术开发专栏】Flutter开发中的代码质量与重构实践
|
4天前
|
存储 缓存 监控
【Flutter前端技术开发专栏】Flutter中的列表滚动性能优化
【4月更文挑战第30天】本文探讨了Flutter中优化列表滚动性能的策略。建议使用`ListView.builder`以节省内存,避免一次性渲染所有列表项。为防止列表项重建,可使用`UniqueKey`或`ObjectKey`。缓存已渲染项、减少不必要的重绘和异步加载大数据集也是关键。此外,选择轻量级组件,如`StatelessWidget`,并利用Flutter DevTools监控性能以识别和解决瓶颈。持续测试和调整以提升用户体验。
【Flutter前端技术开发专栏】Flutter中的列表滚动性能优化
|
4天前
|
Dart 前端开发 安全
【Flutter前端技术开发专栏】Flutter中的线程与并发编程实践
【4月更文挑战第30天】本文探讨了Flutter中线程管理和并发编程的关键性,强调其对应用性能和用户体验的影响。Dart语言提供了`async`、`await`、`Stream`和`Future`等原生异步支持。Flutter采用事件驱动的单线程模型,通过`Isolate`实现线程隔离。实践中,可利用`async/await`、`StreamBuilder`和`Isolate`处理异步任务,同时注意线程安全和性能调优。参考文献包括Dart异步编程、Flutter线程模型和DevTools文档。
【Flutter前端技术开发专栏】Flutter中的线程与并发编程实践
|
4天前
|
Dart 前端开发 开发者
【Flutter前端技术开发专栏】Flutter中的性能分析工具Profiler
【4月更文挑战第30天】Flutter Profiler是用于性能优化的关键工具,提供CPU、GPU、内存和网络分析。它帮助开发者识别性能瓶颈,如CPU过度使用、渲染延迟、内存泄漏和网络效率低。通过实时监控和分析,开发者能优化代码、减少内存占用、改善渲染速度和网络请求,从而提升应用性能和用户体验。定期使用并结合实际场景与其它工具进行综合分析,是实现最佳实践的关键。
【Flutter前端技术开发专栏】Flutter中的性能分析工具Profiler
|
4天前
|
前端开发 数据处理 Android开发
【Flutter 前端技术开发专栏】Flutter 中的调试技巧与工具使用
【4月更文挑战第30天】本文探讨了Flutter开发中的调试技巧和工具,强调其在及时发现问题和提高效率上的重要性。介绍了基本的调试方法如打印日志和断点调试,以及Android Studio/VS Code的调试器和Flutter Inspector的使用。文章还涉及调试常见问题的解决、性能和内存分析等高级技巧,并通过实际案例演示调试过程。在团队协作中,有效调试能提升整体开发效率,而随着技术发展,调试工具也将持续进化。
【Flutter 前端技术开发专栏】Flutter 中的调试技巧与工具使用
|
4天前
|
Dart 前端开发 Java
【Flutter前端技术开发专栏】Flutter中的内存泄漏检测与解决
【4月更文挑战第30天】本文探讨了Flutter应用中的内存泄漏检测与解决方法。内存泄漏影响性能和用户体验,常见原因包括全局变量、不恰当的闭包使用等。开发者可借助`observatory`工具或`dart_inspector`插件监测内存使用。解决内存泄漏的策略包括避免长期持有的全局变量、正确管理闭包、及时清理资源、妥善处理Stream和RxDart订阅、正确 disposal 动画和控制器,以及管理原生插件资源。通过这些方法,开发者能有效防止内存泄漏,优化应用性能。
【Flutter前端技术开发专栏】Flutter中的内存泄漏检测与解决