Hi!~
可以叫我Doho,我是一名前端开发,开源社区的爱好者。
前言
对,你没有看错,不是标题党,十分钟后你将会完全成为一名超酷的开源社区贡献者!当然,可能暂时只有0.0000...0001%点酷,但正因为有这一点,才打开了整个%,hhh~
这篇文章会涉及到一些社区内的常用开源工具,大家看完感兴趣可以自行跳转了解,嘻嘻。
做什么
平时我经常会对组件做这样的目录结构
--- Button
|---index.tsx
|---styles.css.ts
在一个Button目录下,会存放一个关于组件的入口文件(index.tsx),关于描述样式的style文件。
并且在这两个文件中,我会初始化一些代码
// index.tsx
import React from 'react';
// 导出props为 [组件名]Props
export interface ButtonProps {
}
// 导出组件名为 [组件名], 并且组件自动引用[组件名]Props
export const Button: React.FC<ButtonProps> = props => {
return null
}
// styles.css.ts
import styled from "styled-components";
// 这里我使用的是styled-components,我会习惯性的导出一个root style
// 不过对于我们写这样一个VSCode插件来说这并不是重点
export const Container = styled.div`
`;
但其实当我们想要创建这样的组件时,它可能会导致我们不能准时下班
--- Page1
|---index.tsx
|---styles.css.ts
|--- SubPage1
|---index.tsx
|---styles.css.ts
|--- SubPage2
|---index.tsx
|---styles.css.ts
|--- SubPage3
|---index.tsx
|---styles.css.ts
|--- ...
所以我们可以有一个按钮,点击它会自动帮我们完成这件事,或许它来自右键目录后的菜单栏并且它长这样
起个名字
Gold-Right 言简意赅,黄金右键!
开始
开始前让我们先来拆解一下要做的事情
- GitHub上找一个关于VSCode插件的starter,让我们可以更快的开一个项目
- 初始化项目,修改信息
- 写插件逻辑
- 右键文件侧边栏/目录,菜单可以展示Create Component按钮
- 点击按钮可以弹出VSCode的输入框,设置组件名称
- 输入组件名称可以执行创建文件的逻辑
- 发布项目
OK,开始。
先来找个VSCode插件starter,这里我使用了这个github.com/antfu/start… 它提供了pnpm、ts、eslint、prettier、pack、build、release这基本已经完成了大部分前置的工作。
# 这可以让我们clone整个项目,但不含.git,过往提交记录
npx degit https://github.com/antfu/starter-vscode.git
# 也可以登陆github后访问这个网址,直接使用这个模版创建项目
https://github.com/antfu/starter-vscode/generate
接着来,我们要修改一下这个作者的信息,毕竟人家是给自己用的轮子嘛,一些基本信息搜一搜,改一改。比如:
// package.json
// name/displayName/publisher... 改啦改啦全都改了,一定要细致的检查项目内的每一处
{
"name": "name",
"displayName": "My Extension",
"version": "0.0.0",
"publisher": "antfu",
"packageManager": "pnpm@7.0.1",
"description": "",
"keywords": [],
"homepage": "https://github.com/antfu/[name]#readme",
"bugs": {
"url": "https://github.com/antfu/[name]/issues"
},
...
}
我改的地方
- LICENSE开源协议
- README.md文件
- 项目内和author/prject name相关的所有部分
- .github/FUNDING.yml(影响到Sponsor指定的人员)
- 删除 .github/workflows
- .vscode/settings.json(这个项目使用了antfu/eslint-config的eslint预设规则,这里我在项目范围内开启当保存时自动格式化)
- 配置了SponsorKit,这是一个Git Action可以自动在CI上更新Sponsor信息,展示在README.md上,大概长这样
其实这些开启一个项目需要修改的信息,我们都可以根据自己的需求写成一个一个仓库,A仓库是关于ESlint-config的,B仓库是起一个插件项目的模板,C仓库能给我们提供现成的构建CI配置...
无论是针对我们平时的工作还是业余项目都是能提高效率的,这也是某种意义上的工程化,这些其实也都是工程化中的具体步骤,只不过可以被我们拆解封装而已。
正是写代码之前,我们先安装一下依赖
# 没有安装pnpm的同学自行google
pnpm install
并且按下F5正式开始开发模式,此时VSCode会打开一个编辑器,在这个编辑器中已经预设好了我们写的插件,并且我们的开发编辑器也打开了log终端,可以查看我们的日志信息。
现在我们要开始写逻辑部分,这里我不会过多的介绍关于VSCode的API,我会把我搜索到的API资料发出来,因为当我有这个想法时我是完全没有接触过这方面内容的,也仅仅是通过搜索来完成这个需求,所以大家也可以找找看代码中还有没有更好的实现方式(【贡献】)。
- 右键文件侧边栏/目录,菜单可以展示Create Component按钮
{
...
"contributes": {
// 弹出命令框时可输入 Create Component 执行命令
"commands": [
{
// gold-right为我们的组件名,createComponent为命令名
"command": "gold-right.createComponent",
"title": "Create Component"
}
],
// 设置按钮展示在菜单栏的位置
"menus": {
"explorer/context": [
{
"command": "gold-right.createComponent",
"group": "1_modification"
}
]
},
"configuration": {
// 标题,确切名称
"title": "Gold Right",
"properties": {
// 组件的后缀名,用户可以在.vscode/settings.json进行配置
// "goldRight.componentExtension": jsx (默认tsx)
"goldRight.componentExtension": {
"type": "string",
"default": "tsx",
"description": "component's main file extension "
},
// 组件默认的文件名
"goldRight.componentFilename": {
"type": "string",
"default": "index",
"description": "component's main filename"
},
// css文件的后缀名
"goldRight.cssExtension": {
"type": "string",
"default": "css.ts",
"description": "component's css file extension "
},
// css文件的文件名
"goldRight.cssFilename": {
"type": "string",
"default": "styled",
"description": "component's css filename"
}
}
}
Ï}
...
}
- 点击按钮可以弹出VSCode的输入框,设置组件名称
// src/index.ts
import fs from 'fs'
import path from 'path'
import type { ExtensionContext } from 'vscode'
import { commands, window, workspace } from 'vscode'
export function activate(context: ExtensionContext) {
function createComponent(){}
// 现在我们要注册指令,在这个回调中我们会拿到VSCode给到我们的一些参数
// 通过这些参数我们可以找出任何我们需要的信息
const cfc = commands.registerCommand(
'gold-right.createComponent',
(param) => {
// 找到用户选择的目录信息
const folderPath = param.fsPath
// 给组件一个默认值,默认为当前右键的目录名
const defaultComponentName = folderPath.split('/').pop()
// 弹出提示框的内容
const options = {
prompt: 'Please input the component name: ',
placeHolder: `Component Name (default:${defaultComponentName})`,
}
// 这些信息是从配置中提取出的(package.json)
const componentExtension = workspace
// goldRight.componentExtension 中的 goldRight
.getConfiguration('goldRight')
// goldRight.componentExtension 中的 componentExtension
.get('componentExtension') as string
const componentFilename = workspace
.getConfiguration('goldRight')
.get('componentFilename') as string
const cssExtension = workspace
.getConfiguration('goldRight')
.get('cssExtension') as string
const cssFilename = workspace
.getConfiguration('goldRight')
.get('cssFilename') as string
if (!componentExtension)
window.showInformationMessage('Please set the componentExtension in the settings. ')
if (!cssExtension)
window.showInformationMessage('Please set the cssExtension in the the settings.')
if (!cssFilename)
window.showInformationMessage('Please set the cssFilename in the settings.')
// 展示输入框
window.showInputBox(options).then((componentName) => {
// createComponent是我们要具体编写的创建目录/文件的方法
// 现在我们把找到的资料传递给我们创建目录/文件的方法
createComponent({
folderPath,
componentName: componentName || defaultComponentName,
componentFilename,
componentExtension,
cssExtension,
cssFilename,
})
})
},
)
context.subscriptions.push(cfc)
}
export function deactivate() { }
- 输入组件名称可以执行创建文件的逻辑
...
// 一些很简单的nodejs代码,这里不展开讲解API
function createComponent(dirInfo: {
folderPath: string
componentName: string
componentExtension: string
componentFilename: string
cssExtension: string
cssFilename: string
}) {
const { folderPath, componentName: _componentName, componentExtension, componentFilename, cssExtension, cssFilename } = dirInfo
const componentName = _componentName.charAt(0).toLocaleUpperCase() + _componentName.slice(1)
// 下面的内容大致是我们根据传入的信息,去对目标位置创建目录/文件
const componentTemplateSrc = path.resolve(__dirname, 'template/component')
const styledTemplateSrc = path.resolve(__dirname, 'template/styled')
const dest = path.join(folderPath, componentName)
const componentTemplate = fs.readFileSync(componentTemplateSrc, { encoding: 'utf-8' })
const styledTemplate = fs.readFileSync(styledTemplateSrc, { encoding: 'utf-8' })
if (fs.existsSync(dest)) {
window.showInformationMessage(`${componentName} already exists, please choose another name.`)
return
}
fs.mkdirSync(dest)
fs.writeFileSync(path.resolve(`${dest}/${cssFilename}.${cssExtension}`), styledTemplate)
fs.writeFileSync(
path.resolve(`${dest}/${componentFilename}.${componentExtension}`),
componentTemplate
.replace(/\[componentName\]/g, componentName)
.replace(/\[cssExtension\]/, cssExtension)
.replace(/\[cssFileName\]/, cssFilename),
)
// 创建完成后我们提示用户创建成功
window.showInformationMessage(
`Succeeded in creating ${componentName} component!`,
)
}
...
到这里肯定会有同学注意到代码中有对template解析的部分,这其实就是我们预设的模板文件,里面存放了一些我们要创建的代码,然后对文件内的[]内容进行替换,来达到更换变量名的目的。我们也可以使用一些模板引擎,但这里其实需求很简单,就也没做,大家可以考虑来一个PR,用解析模板文件的方式来替换这部分逻辑(【贡献】)。
# 根目录创建一个template目录
...
--- template
|--- component
|--- styled
...
// component
import React from 'react';
export interface [componentName]Props {
}
export const [componentName]: React.FC<[componentName]Props> = props => {
return null
}
----------------------------------------
// styled
import styled from "styled-components";
export const Container = styled.div`
`;
紧接着我们还要做一件事,代码中我们对template目录的引用会出错,因为其实build到dist目录后我们并没有办法找到template,因为我们并没有将其放到dist中,这里我们需要对package.json中的build命令做一些修改。
"build": "tsup src/index.ts --external vscode"
// tsup提供了勾子,可以在构建成功时提供回调执行我们预设的命令
// 这里我们想要他将template挪动到dist中
"build": "tsup src/index.ts --external vscode --onSuccess 'cp -a template dist'"
做到这儿,如果我没忘记什么步骤的话应该就能完成我们预期的功能了,如果我漏掉了什么就去仓库康康,也可以提醒我补上,hh。
如果看过我上篇文章的同学可能看到这里也会有所感触。
- "最后回过头来看,貌似我的这次“开源经历”其实就起始于一次工作需求,它看起来就像是一次巧合,但仔细想想更因为是这样所以我们能很好的去参与开源。我们的每次需求,都可以被更细致的拆解,然后思考中间我们能做的事情,完善中间的缺漏,最后产生一个新的解决方案"
这个需求我做的很局限,因为我只想完成我自己的需求,但其实它可以扩展出更多内容,比方说我们可以让用户提供一个template目录的路径,我们去读取它的模板信息,并且他可以跟根据我们预设的[]来决定替换哪些内容,这些我想都很简单,大家可以尝试去做一做,即便是发出一个issue也是参与了贡献,对于想参加开源项目的同学是很酷的事情(【贡献】)。
最后我们要发布我们的插件,当我们查阅完发布一个插件所需要的步骤时(插件信息/icon/VSCode商店账号注册/token获取设置... 等等需要了解的内容后)
# 剩下的在一开始我们都准备好了,执行即发布。
pnpm run release
# 这里提示一下,获取完token后如果遇到401的情况,看这里
https://code.visualstudio.com/api/working-with-extensions/publishing-extension#i-get-403-forbidden-or-401-unauthorized-error-when-i-try-to-publish-my-extension
结尾
这篇文章我省略了一些我觉得并不是很重要的内容,比方说文末我们如何去准备上架前的信息,这些google一下,官方都有很详细的解答,大家可以自行google就不占篇幅了哈。
文中也藏了一些(【贡献】)的标记,大家可以跳转仓库,自行提issue/pr,而且目前文档也并没有编写,也可以选择写一份大家易读的文档,怎样都可以,重要的是赶快来参与吧!~
Gold-Right: github.com/dohooo/Gold…
Github: github.com/dohooo
Twitter:twitter.com/doho_1016