如何为前端项目一键自动添加eslint和prettier的支持

本文来自读者@那个曾经的少年回来了 写的源码共读35期笔记文章,授权投稿,写的真好。

本文参加了由公众号@若川视野 发起的每周源码共读活动,点此加我微信 ruochuan12 了解详情一起参与。

本文属于源码共读第35期 | 为 vite 项目自动添加 eslint 和 prettier点击了解本期详情一起参与 https://juejin.cn/post/7113563466211786783

前言

我之前好多次都是一步一步的安装eslint和prettier及相关依赖,一个配置文件一个配置文件的粘贴复制,并修改其中的相关配置。而且可能会在每个项目中都要去处理,如果项目工程规划化以后,eslint和prettier确实是项目少不了的配置。不知道你有没有像我一样操作过呢?

那么有没有一种更简单的方式去处理呢?答案是我终于遇到了。通过若川大佬的源码共读活动发现了,真的是太棒了。

本文以vite脚手架创建的项目为基础进行研究的,如果是其他脚手架创建的项目,那么就要自己去修改处理,但是原理是一样的。

那么接下来,我就要来一探究竟,先看看如何使用,然后查阅一下它的源码,看看它到底是如何实现的呢?

1、vite创建项目

  • 创建项目

yarn create vite

一顿操作以后项目就创建完毕了

c03962e28400387c46f04b3766320051.png
image.png
  • 2、安装依赖

yarn
  • 3、运行项目

yarn dev
  • 4、运行初始化eslint和prettier命令

yarn create vite-pretty-lint

先来看没有执行命令前的文件目录

3cf2ae21f2502d89f9f5b4e06b7b2535.png
image.png

再来看执行完命令后的文件目录

33d796876ac721ac2df35e508796fd56.png
image.png

可以发现文件目录中增加了eslint和prettier的相关配置,package.json中增加了相关的依赖、以及vite.config.xx文件也增加了相关配置,具体的文件变更可以查看https://github.com/lxchuan12/vite-project/commit/6cb274fded66634191532b2460dbde7e29836d2e。

一个命令干了这么多事情,真的太优秀了。接下来我们就去看看这如此优秀的源代码吧

2、整个过程的示意图

通过大致的查看源代码,简单总结出来的代码执行过程示意图,仅供参考

21dbba1e153b33abf5ae9dd739334212.png
未命名文件 (3).png

3、源码调试过程

3.1、找到调试代码的位置

通过package.json中的bin节点可以发现,yarn create vite-pretty-lint最终执行的便是lib/main.js中的代码

"bin": {"create-vite-pretty-lint": "lib/main.js"},

3.2、 开始调试的命令

因为我们现在只是要执行lib/main.js这个入口文件,通过package.jsonscripts 也没有发现执行命令,所以现在我们可以直接通过node来运行代码

node lib/main.js

调试成功的结果如下图所示

f540aadbfb0b750250caf2349f4c40fc.png
企业微信截图_16564645675849.png

3.3、 查看头部引入的模块

  • chalk终端多色彩输出

npm i chalkimport chalk from 'chalk'const log = console.log
// 字体背景颜色设置
log(chalk.bgGreen('chalk打印设置') )// 字体颜色设置
log(chalk.blue('Hello') + ' World' + chalk.red('!'))// 自定义颜色
const custom = chalk.hex('#F03A17')
const bgCustom = chalk.bgHex('#FFFFFF')
log(custom('customer'))
log(bgCustom('bgCustom'))

执行效果如下图所示

e9f96a108a6d8bbc71fa36851921fa36.png
image.png
  • gradient 文字颜色渐变

// 安装
npm i gradient-string
// 引入
import gradient  from 'gradient-string'// 使用
console.log(gradient('cyan', 'pink')('你好啊赛利亚欢迎来到编码世界'));
console.log(gradient('cyan', 'pink')('你好啊赛利亚欢迎来到编码世界'));
console.log(gradient('cyan', 'pink')('你好啊赛利亚欢迎来到编码世界'));
console.log(gradient('cyan', 'pink')('你好啊赛利亚欢迎来到编码世界'));
console.log(gradient('cyan', 'pink')('你好啊赛利亚欢迎来到编码世界'));

执行效果如下图所示

d2e6138a52d2da91f8d06128a9ff4653.png
image.png
  • child_process node.js中的子进程。

    在node.js中,只有一个线程执行所有的操作,如果某个操作需要大量消耗CPU资源的话,后续的操作就需要等待。后来node.js就提供了一个child_process模块,通过它可以开启多个子进程,在多个子进程之间可以共享内存空间,可以通过子进程的互相通信来实现信息的交换。

import { exec } from 'child_process';exec('ls',(error, stdout,stderr)=> {if(error) {console.log(error)return;}console.log('stdout: ' + stdout)console.log('执行其他操作')
})

执行效果如下图所示

b1832c9e216eb73383adf0db1c20e12d.png
image.png
  • fs fs用来操作文件的模块

import fs from 'fs'// 同步的读取方法,用来读取指定文件中的内容
fs.readFileSync() 
// 同步的写入方法,用来向指定文件中写内容
fs.writeFileSync()
  • path路径分类

import path from 'path';// 拼接路径
console.log(path.join('src', 'task.js'));  // src/task.js
  • nanospinner命令行中的加载动画

// 安装
npm i nanospinner// 引入模块
import { createSpinner } from 'nanospinner';const spinner = createSpinner('Run test').start()setTimeout(() => {spinner.success()
}, 1000)

执行效果如下图所示(Run test在加载的一个效果)

51ed08a085933103f10a0d2a21676894.gif
3.gif
  • enquirer (utils.js文件)

交互式询问CLI 简单说就是交互式询问用户输入

npm i enquirer import enquirer from 'enquirer' let tempArray = ['major(1.0.0)','minor(0.1.0)', 'patch(0.0.4)', "customer" ]
const { release } = await enquirer.prompt({type: 'select',name: 'release',message: 'Select release type',choices: tempArray
})if(release === 'customer') {console.log(release, 'customer')
} else {const targetVersion = release.match(/\((.*)\)/)[1]console.log(targetVersion, 'targetVersion')
}

执行效果如下图所示:先出来一个下拉选择,选择完后根据if判断进行输出

892cd71996558ba99c78aa0ae6a6a064.gif
4.gif

3.4、 调试具体代码

3.4.1、 main.js中的入口
async function run() {// 所有的逻辑代码
}run().catch((e) => {console.error(e);
});

通过run函数封装异步方法,这样最外面调用run函数时可以通过异步方法的catch捕获错误异常。

看一个小例子

const runTest = async () => {console.log('Running test')throw new Error('run test报错了')
}runTest().catch(err => {console.log('Error: ' + err)
})

执行后打印顺序如下

Running test
Error: Error: run test报错了

可以发现catch中截获了异常

接下来开始进入run函数了

3.4.2、 打印色彩字体
// 这个看上面的引入模块解析即可
console.log(chalk.bold(gradient.morning('\n🚀 Welcome to Eslint & Prettier Setup for Vite!\n'))
);
3.4.3、 交互式命令行
export function getOptions() {const OPTIONS = [];fs.readdirSync(path.join(__dirname, 'templates')).forEach((template) => {const { name } = path.parse(path.join(__dirname, 'templates', template));OPTIONS.push(name);});return OPTIONS;
}export function askForProjectType() {return enquirer.prompt([{type: 'select',name: 'projectType',message: 'What type of project do you have?',choices: getOptions(),},{type: 'select',name: 'packageManager',message: 'What package manager do you use?',choices: ['npm', 'yarn'],},]);
}try {const answers = await askForProjectType();projectType = answers.projectType;packageManager = answers.packageManager;} catch (error) {console.log(chalk.blue('\n👋 Goodbye!'));return;}

getOptions 函数根据fs.readdirSync读取项目工程template文件夹下的所有文件,并通过path.parse转换对象,来获取文件名称name

askForProjectType函数通过enquirer.prompt返回两个交互式命令行,供用户进行选择projectType选择项目类型:【react-ts】 【react】【vue-ts】 【vue】packageManager选择项目包管理方式:【npm】 【yarn】

3.4.4、根据交互命令行返回结果进行匹配模板

假如我们上面选择的是[vue-ts]

const { packages, eslintOverrides } = await import(`./templates/${projectType}.js`
);

/template/vue-ts.js模板中的代码(其中代码较多但一看就明白我就不贴了),就是export导出了两个固定的模板变量数组,packages则相当于要引入的npm模块列表,eslintOverrides这算是.eslintrc.json初始化模板。

3.4.5、拼接变量数组
const packageList = [...commonPackages, ...packages];
const eslintConfigOverrides = [...eslintConfig.overrides, ...eslintOverrides];
const eslint = { ...eslintConfig, overrides: eslintConfigOverrides };

commonPackagesshared.js中预定义的公共的npm 模块eslint则是通过公共npm模块中的eslintConfig和上面选择的template/xxxx.js中的进行拼接组成。

3.4.6、 生成安装依赖包的命令
const commandMap = {npm: `npm install --save-dev ${packageList.join(' ')}`,yarn: `yarn add --dev ${packageList.join(' ')}`,
};

packageList数组通过join转换为字符串,通过命令将所有拼接npm模块一起安装

058007c459991d312805f6178e1508ee.png
image.png
3.4.7、 读取项目的vite配置文件
const projectDirectory = process.cwd();const viteJs = path.join(projectDirectory, 'vite.config.js');const viteTs = path.join(projectDirectory, 'vite.config.ts');const viteMap = {vue: viteJs,react: viteJs,'vue-ts': viteTs,'react-ts': viteTs,};const viteFile = viteMap[projectType];const viteConfig = viteEslint(fs.readFileSync(viteFile, 'utf8'));const installCommand = commandMap[packageManager];if (!installCommand) {console.log(chalk.red('\n✖ Sorry, we only support npm and yarn!'));return;}

根据选择的项目类型,来拼接vite.config的路径,并读取项目中的vite.config配置文件

上面用到了一个函数viteEslint,这个具体的实现可以去看shared.js中,主要就是读取文件内容后,传入的参数code,就是vite.config.ts中的所有字符

6e446af53b8b683d3c39da2a45847c5a.png通过babel的parseSync转换为ast。ast对象如下图所示

41e19b28d740ff66e4a79bdc80acf64e.png
1656558646620.png

对ast数据进行了一系列的处理后,再通过babeltransformFromAstSync将ast转换为代码字符串。

对于babel处理这一块我也不太了解,有时间我得去加一下餐,具体的可以参考 https://juejin.cn/post/6844904008679686152

3.4.8 执行命令、执行完将eslint和prettier配置重写
const spinner = createSpinner('Installing packages...').start();exec(`${commandMap[packageManager]}`, { cwd: projectDirectory }, (error) => {if (error) {spinner.error({text: chalk.bold.red('Failed to install packages!'),mark: '✖',});console.error(error);return;}const eslintFile = path.join(projectDirectory, '.eslintrc.json');const prettierFile = path.join(projectDirectory, '.prettierrc.json');const eslintIgnoreFile = path.join(projectDirectory, '.eslintignore');fs.writeFileSync(eslintFile, JSON.stringify(eslint, null, 2));fs.writeFileSync(prettierFile, JSON.stringify(prettierConfig, null, 2));fs.writeFileSync(eslintIgnoreFile, eslintIgnore.join('\n'));fs.writeFileSync(viteFile, viteConfig);spinner.success({ text: chalk.bold.green('All done! 🎉'), mark: '✔' });console.log(chalk.bold.cyan('\n🔥 Reload your editor to activate the settings!'));});

首先通过createSpinner来创建一个命令行中的加载,然后通过child_process中的exec来执行[3.4.6]中生成的命令,去安装依赖并进行等待。

如果命令执行成功,则通过fs.writeFileSync将生成的数据写入到三个文件当中.eslintrc.json.prettierrc.json.eslintignorevite.config.xx

4、npm init、npx

印象里面大家可能对它的记忆可能都停留在,npm init之后是快速的初始化package.json,并通过交互式的命令行让我们输入需要的字段值,当然如果想直接使用默认值,也可以使用npm init -y

create-app-react创建项目命令,官网链接可以直接查看 https://create-react-app.dev/docs/getting-started

//官网的三种命令
npx create-react-app my-app
npm init react-app my-app
yarn create react-app my-app//我又发现npm create也是可以的
npm create react-app my-app

上述这些命令最终效果都是可以执行创建项目的

同样的vite创建项目的命令

//官网的命令
npm create vite@latest
yarn create vite
pnpm create vite// 指定具体模板的
// npm 6.x 
npm create vite@latest my-vue-app --template vue 
//npm 7+, extra double-dash is needed: 
npm create vite@latest my-vue-app -- --template vueyarn create vite my-vue-app --template vuepnpm create vite my-vue-app --template vue

可以发现vite官网没有使用npx命令,不过我在我自己电脑上尝试了另外几个命令确实也是可以的

npx create-vite my-app
npm init vite my-app
b2536e5aaabf11187f826307fe184b97.png
image.png

通过上面的对比可以一个小问题,yarn create去官网查了是存在这个指令的,官网地址可看 https://classic.yarnpkg.com/en/docs/cli/create#search

而对于npm create这个命令在npm官网是看不到的,但是在一篇博客中发现了更新日志

ceb6ebbc4b18d2b63b971f3737548d34.png
image.png

意思就是说npm create xxxnpm init xxx 以及yarn create xxx效果是一致的。那么我们来本文的命令行

// 我们是通过npm安装的,并且包名里是包含create的
npm i create-vite-pretty-lint// 那么以下几种方式都可以使用的
npm init vite-pretty-lint
npm create vite-pretty-lint
yarn create vite-pretty-lint
npx create-vite-pretty-lint

再来看一下npx

假如我们只在项目中安装了vite,那么node_modules.bin文件夹下是会存在vite指令的

d1926712c93afb1fc639b03496075aff.png
image.png

如果我们想在该项目下执行该命令第一种方式便是

90df14eda5afec9652312282c5605bd5.png
image.png

第二种方式就是直接在package.json的scripts属性下

932bcaf30626a0f17763f039d5c31b07.png
image.png

关于npx的详细说明可以看一下阮一峰大佬的精彩分享 http://www.ruanyifeng.com/blog/2019/02/npx.html

5、总结

  • npm init xxx的妙用,以及对npx的了解,感觉对package.json的每一个属性,可以专门去学习一下

  • 对于自动添加eslint和prettier配置的原理分析

  • .eslintrc.json、.eslintignore、.prettierrc.json算是直接新增文件,处理相对简单一些

  • 最重要的学习点:对vite.config文件在原有基础上的修改,这里就涉及到了AST抽象语法树

6、加餐 V8下的AST抽象语法树

有兴趣的话可以看看我前几天刚刚总结的关于V8引擎是如何运行JavaScript代码的,其中就涉及到关于AST的部分https://juejin.cn/post/7109410330295402509。

接下来有时间我会简单的把AST详细的学习一下,查了很多资料发现AST还是非常重要的,无论是babel、webpack、vite、vue、react、typescript等都使用到了AST。

c8917c257eeedc0945322f0fa8c056e9.gif

················· 若川简介 ·················

你好,我是若川,毕业于江西高校。现在是一名前端开发“工程师”。写有《学习源码整体架构系列》20余篇,在知乎、掘金收获超百万阅读。
从2014年起,每年都会写一篇年度总结,已经坚持写了8年,点击查看年度总结。
同时,最近组织了源码共读活动,帮助4000+前端人学会看源码。公众号愿景:帮助5年内前端人走向前列。

fceedffdbba1ccb5b21d6126ef31b6e6.jpeg

扫码加我微信 ruochuan12、拉你进源码共读

今日话题

目前建有江西|湖南|湖北 籍 前端群,想进群的可以加我微信 ruochuan12 进群。分享、收藏、点赞、在看我的文章就是对我最大的支持

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/274607.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

极端原理_为极端而设计

极端原理*You can also read this article in German here.*您也可以 在此处 阅读 德语文章 。 In this article I’m going to draw on the Design thinking concept of designing for extreme users and I will argue that designing for extreme users can be considered a…

当CV工程师碰到了拷贝粘贴的需求——useClipboard的使用及源码解析

大家好,我是若川。持续组织了近一年的源码共读活动,感兴趣的可以 点此加我微信ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。…

ux和ui_从UI切换到UX设计

ux和uiI still remember those days, when I was a soon-to-be graphic design graduate who started to question what my future will be. At that time, I realized that I loved graphic design, but I wasn’t sure if I enjoyed doing it. Creating logos, posters, broc…

春季招聘后前端工程师的就业指南

尽管疫情反复,大厂裁员,招聘季仍是在困难中有条不紊地落下了尾声。回顾今年的春季招聘,北京青年报记者发现,互联网“大厂”依然对“研发岗”需求最为旺盛。但许多企业最近都在围绕“降本提效”来进行业务调整,这对技术…

探索式测试的思维模型

上一章介绍了探索式测试的定义。在实际项目的测试执行过程中,读者是否曾遇到如下的几个现象: 测试人员按照一个测试用例来执行测试,得到的程序输出与预期输出不一致。 测试人员判断程序的行为并不是缺陷,但根据新的输出想到了新的…

图解Git分支和命令

大家好,我是若川。持续组织了近一年的源码共读活动,感兴趣的可以 点此加我微信ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。…

vsco_VSCO重新设计:更直观,更简化的界面

vscoAmong the many photo-editing apps, VSCO has definitely become a popular favorite among both experienced photographers as well as “aesthetic” Instagram users. However, my interaction with the app starts and ends with using a few key filters and (maybe…

浅谈前端埋点监控

大家好,我是若川。持续组织了近一年的源码共读活动,感兴趣的可以 加我微信lxchuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外&…

css版式_第2部分:使版式具有响应能力,并为以后的版本奠定基础

css版式The feedback I’ve received over the past week has been amazing, and matches my own excitement about this project. I’ve spent a lot of time researching, writing, and teaching about creating better typography for reading on digital devices over the …

BBS项目--登录

BBS阶段性测试总要求 django登录报错 Error: [WinError 10013] 以一种访问权限不允许的方式做了一个访问套接字的尝试。 原因分析:出现这种情况在Windows中很常见,就是端口被占用 解决措施:这时我们只需改一下端口便可以了 登录前端页面(HTML…

【声明】

我的公众号和朋友圈有时会有一些课程推广广告,微博的收入来源。我接的广告一般来说都是比自己去买会优惠不少,我也会想方设法争取到更多福利(优惠)。买过的都知道确实优惠。如果有人看到觉得不合适,不想看到&#xff0…

怎么实现页面友好跳转_如何实现软,友好和一致的UI设计

怎么实现页面友好跳转重点 (Top highlight)Design trends are constantly changing, aren’t they? Each month there is a new visual effect or a trick that becomes “设计趋势在不断变化,不是吗? 每个月都有一个新的视觉效果或技巧,成为…

前端趋势 2022

大家好,我是若川。持续组织了近一年的源码共读活动,感兴趣的可以 加我微信lxchuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外&…

lightroom预设使用_在Lightroom中使用全景图增强照片游戏

lightroom预设使用Everyone here has taken a panorama with an iphone. We’ve spun around in a circle, trying to keep that arrow right on the line, and more than likely ended up with a strange, squiggly, horizontal photo. Every so often you might get lucky an…

第91次TC39会议举行,这还是我认识的JS吗?

大家好,我是若川。持续组织了近一年的源码共读活动,感兴趣的可以 加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外…

android调节音量——AudioManager的应用

Android中可以通过程序获取系统手机的铃声和音量。同样,也可以设置铃声和音量。Android中给出了AudioManager类来实现音量获取、音量控制。本篇基于 Android API 中的 AudioManager 作讲述,最后给出实例。下面是本篇大纲:1、认识 AudioManage…

静态创意和动态创意_再次发挥创意需要什么?

静态创意和动态创意重点 (Top highlight)According to Oxford dictionary, creativity means “1. Inventiveness. 2. the use of imagination or original ideas to create something.”根据牛津词典,创造力意味着“ 1。 创造力。 2.利用想象力或独创性的思想来创造…

我写了 ahooks 源码分析系列,收到官方邀请我一起维护,这是一次提 PR 的记录...

大家好,我是若川。持续组织了近一年的源码共读活动,感兴趣的可以 加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外…

Hdu 4415 Assassin's Creed 【贪心】.cpp

题意: 某A有一个剑 坚韧度为m 他可以用这个剑去攻打别的队伍 杀掉第 i 个队伍需要消耗的坚韧度为 Ai 并可以用得到的剑去打别的队(Bi个) 但是打完别的队这个剑就不能用了 问怎么用最少的坚韧度击败最多的队伍 给出T组样例 每个样例给出n m n表示有n个队 接下来n行给…

ahooks 整体架构篇,大家都能看得懂

大家好,我是若川。持续组织了近一年的源码共读活动,感兴趣的可以 加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列。另外…