使用 React、TypeScript、Tailwind CSS 创建 VS Code 扩展

介绍

本文专门针对那些喜欢VS Code代码编辑器的人而创作,您是否只是使用VSCode来开发代码呢?他其实并未被充分使用。

代码编辑器内部有一个扩展部分,可以在编码时提供额外的帮助,例如片段(自动完成)、调试、主题以及更多有用的扩展。

例如,Postman VS Code 扩展使您能够直接从 Visual Studio Code 在 Postman 中开发和测试 API。

在上面的扩展中,显示的 UI 界面位于 VS Code 内部,这得益于 Postman 扩展的帮助。它也是代码编辑器不可或缺的一部分,这是使用htmlcssjavascript制作的,这意味着开发者,尤其是前端大佬们都可以进行轻松制作。

您只需按 Ctrl + Shift + P然后选择Developer: Toggle Developer Tools显示 VS Code 中的开发者工具。

正如上面的 gif 中看到的,我们可以像检查任何网页一样轻松地检查任何扩展。现在到了重要的部分:如何制作这样的扩展。

让我们开始吧~


了解扩展创建

为了创建扩展,VS Code 使用名为YeomanCode-Generator 的cli 工具。

在开始之前,您需要安装 npm 并了解 Node 的基本知识。

全局安装包

css 复制代码
npm install --global yo generator-code

启动扩展安装

css 复制代码
yo code

之后,您将看到这个 Yeomen 扩展菜单

sql 复制代码
     _-----_     ╭──────────────────────────╮
    |       |    │   Welcome to the Visual  │
    |--(o)--|    │   Studio Code Extension  │
   `---------´   │        generator!        │
    ( _´U`_ )    ╰──────────────────────────╯
    /___A___\   /
     |  ~  |     
   __'.___.'__   
 ´   `  |° ´ Y ` 

? What type of extension do you want to create? (Use arrow keys)
> New Extension (TypeScript) 
  New Extension (JavaScript)
  New Color Theme
  New Language Support
  New Code Snippets
  New Keymap
  New Extension Pack
  New Language Pack (Localization)
  New Web Extension (TypeScript)
  New Notebook Renderer (TypeScript)

选择不同类型的扩展,在我们的例子中,我们将使用如下选项

vbnet 复制代码
? What type of extension do you want to create? New Extension (TypeScript)
? Whats the name of your extension? HelloWorld
? Whats the identifier of your extension? helloworld
? Whats the description of your extension? LEAVE BLANK
? Initialize a git repository? Yes
? Bundle the source code with webpack? No
? Which package manager to use? npm

? Do you want to open the new folder with Visual Studio Code? Open with `code`

您可以通过更改 src/extension.ts 中的内容来进行尝试: 在编辑器中,打开src/extension.ts并按F5。会在新的扩展开发主机窗口中编译并运行扩展。

从新窗口中的命令面板 Ctrl + Shift + P 运行 Hello World 命令

输出将产生 VS Code 信息消息(默认):Hello World

您可以通过更改 src/extension.ts 中的内容来进行尝试:

javascript 复制代码
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';

// This method is called when your extension is activated
// Your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {

    // Use the console to output diagnostic information (console.log) and errors (console.error)
    // This line of code will only be executed once when your extension is activated
    console.log('Congratulations, your extension "helloworld" is now active!');

    // The command has been defined in the package.json file
    // Now provide the implementation of the command with registerCommand
    // The commandId parameter must match the command field in package.json
    let disposable = vscode.commands.registerCommand('helloworld.helloWorld', () => {
        // The code you place here will be executed every time your command is executed
        // Display a message box to the user
        vscode.window.showInformationMessage('Hello World from Helloworld!');
    });

    context.subscriptions.push(disposable);
}

// This method is called when your extension is deactivated
export function deactivate() {}

该文件是您的扩展基础。它包含 2 个重要的方法:activatedeactivate 。导入的vscode.command 模块注册命令和上下文参数共同订阅它们。

package.json

json 复制代码
{
...,
  "activationEvents": [],
  "contributes": {
    "commands": [
      {
        "command": "helloworld.helloWorld",
        "title": "Hello World"
      }
    ]
  },
}

Contributes.command:帮助在命令面板中显示带有标题的命令,还包含视图等。

激活事件:在特定条件下自动触发已注册的命令

为了更清楚地了解,您可以访问您的第一个 VS Code 扩展

本文不只涉及任何正常的扩展。对于 UI 部分,我们将通过 VS Code使用WebView 。


用于 UI 的 Webview API

Webview 允许扩展在 Visual Studio Code 中创建完全可自定义的视图。为了快速实施,请按照以下步骤操作:

使用以下代码覆盖src/extension.ts 文件:

javascript 复制代码
import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {

    console.log('Congratulations, your extension "Webview" is up and running now');

    let webview = vscode.commands.registerCommand('helloworld.webview', () => {

        let panel = vscode.window.createWebviewPanel("webview", "Web View", {
            viewColumn: vscode.ViewColumn.One,
        })

        // will set the html here
                 panel.webview.html = `<h1>This is Heading 1</h1>
    <h2>This is Heading 2</h2>
    <h3>This is Heading 3</h3>
    <h4>This is Heading 4</h4>
    <h5>This is Heading 5</h5>`

    });

    });

    context.subscriptions.push(webview);
}

export function deactivate() { }

需要注意的要点:

  1. 为了借助命令创建 Webview 面板helloworld.webview,我们需要使用它的回调来注册它。panel用于将 html 设置到 webview 中。
  2. 在回调中,调用 vscode.window.createWebviewPanel 方法,该方法接受 4 个参数, viewTypetitle ( webview 面板的标题)、 showOption (要关注的列)、 options (很重要,因为它处理脚本编写和 面板资源的可访问性)并返回 vscode.WebviewPanel
  3. 重要步骤: 如果您注册了新命令,请将其添加到contributes.commands下的package.json
json 复制代码
{
...,
"contributes": {
    "commands": [
      {
        "command": "helloworld.webview",
        "title": "Web View"
      }
    ]
  },
}

然后,使用 F5 运行扩展,这最终会打开另一个 vscode 窗口Extension Development。 然后按 Ctrl + Shift + P,在命令面板中输入 Web View(或您在 package.json 中提到的命令标题)。

出现的窗口必须如下所示


设计用户界面

样式与通常使用 css 的网页相同,但有一个问题,如果您在外部编写 css,则需要首先允许该资源。 默认情况下,扩展位置和工作区中的所有本地资源都是可访问的。 要控制它们,只需通过提供第四个参数 localResourceRoots 来更改 createWebviewPanel 的代码。

php 复制代码
// while creating panel allow the path you want to add
// in my case adding media as rootDir to localResources
let panel = vscode.window.createWebviewPanel("webview", "Web View", {  
       viewColumn: vscode.ViewColumn.One
},{    localResourceRoots: [vscode.Uri.joinPath(context.extensionUri, "media")]
     })

下一步是在扩展文件夹内的根目录中创建一个名为 media 的文件夹。

在该文件夹中,您可以放置所有样式文件,例如图像、svg、css 文件等。

media 文件夹中创建一个文件 vscode.css (您可以命名任何名称)并添加以下内容

css 复制代码
:root {
  --container-paddding: 20px;
  --input-padding-vertical: 6px;
  --input-padding-horizontal: 4px;
  --input-margin-vertical: 4px;
  --input-margin-horizontal: 0;
}

html {
  box-sizing: border-box;
  font-size: 13px;
}

*,
*:before,
*:after {
  box-sizing: inherit;
}

body,
h1,
h2,
h3,
h4,
h5,
h6,
p,
ol,
ul {
  margin: 0;
  padding: 0;
  font-weight: normal;
}

img {
  max-width: 100%;
  height: auto;
}

body {
  padding: 0 var(--container-paddding);
  color: var(--vscode-foreground);
  font-size: var(--vscode-font-size);
  font-weight: var(--vscode-font-weight);
  font-family: var(--vscode-font-family);
  background-color: var(--vscode-editor-background);
}

ol,
ul {
  padding-left: var(--container-paddding);
}

body > *,
form > * {
  margin-block-start: var(--input-margin-vertical);
  margin-block-end: var(--input-margin-vertical);
}

*:focus {
  outline-color: var(--vscode-focusBorder) !important;
}

a {
  color: var(--vscode-textLink-foreground);
}

a:hover,
a:active {
  color: var(--vscode-textLink-activeForeground);
}

code {
  font-size: var(--vscode-editor-font-size);
  font-family: var(--vscode-editor-font-family);
}

button {
  border: none;
  padding: var(--input-padding-vertical) var(--input-padding-horizontal);
  width: 100%;
  text-align: center;
  outline: 1px solid transparent;
  outline-offset: 2px !important;
  color: var(--vscode-button-foreground);
  background: var(--vscode-button-background);
}

button:hover {
  cursor: pointer;
  background: var(--vscode-button-hoverBackground);
}

button:focus {
  outline-color: var(--vscode-focusBorder);
}

button.secondary {
  color: var(--vscode-button-secondaryForeground);
  background: var(--vscode-button-secondaryBackground);
}

button.secondary:hover {
  background: var(--vscode-button-secondaryHoverBackground);
}

input:not([type="checkbox"]),
textarea {
  display: block;
  width: 100%;
  border: none;
  font-family: var(--vscode-font-family);
  padding: var(--input-padding-vertical) var(--input-padding-horizontal);
  color: var(--vscode-input-foreground);
  outline-color: var(--vscode-input-border);
  background-color: var(--vscode-input-background);
}

input::placeholder,
textarea::placeholder {
  color: var(--vscode-input-placeholderForeground);
}

.container {
  display: flex;
}

.form {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: 10px;
  gap: 10px;
}

上面的样式将帮助您将 html 元素的默认样式属性重置为看起来像 vscode 的本机样式。 上面提到的变量是由vscode直接提供的。

您还可以添加您选择的任何图像,只需将图像文件放入媒体文件夹中即可。

要应用 css 样式表和图像,只需添加此行并应用于 html

xml 复制代码
const cssStyle = panel.webview.asWebviewUri(vscode.Uri.joinPath(context.extensionUri, "media", "vscode.css"))

const imgSrc = panel.webview.asWebviewUri(vscode.Uri.joinPath(context.extensionUri, "media", "vim.svg"))

panel.webview.html = `<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" type="text/css" href="${cssStyle}" />
    </head>
    <body>
    <div class="container">
        <img src="${imgSrc}" width="200" />
        <div class="form">
            <code>Title</code>
            <input />
            <code>Code</code>
            <textarea></textarea>
            <button>Submit</button>
        </div>
    </div>
    </body>
    </html>`

提示: 要查看 html 的变化,您需要重新加载整个扩展,Ctrl + R 快速重新加载,无需每次使用 Ctrl + F5 重新启动

预期输出:


脚本编写

您还可以使用 javascript 更新扩展内的 DOM,但需要先启用它。

xml 复制代码
let panel = vscode.window.createWebviewPanel("webview", "Web View", {
            viewColumn: vscode.ViewColumn.One
        },{
        enableScripts: true
    })

const scriptPath= panel.webview.asWebviewUri(vscode.Uri.joinPath(context.extensionUri, "media", "script.js"))

panel.webview.html = `<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <script src="${scripts}"></script>
    </head>
    <body>
    <h1>Count:</h1>
        <p id="count">0</p>
    <button onclick="changeHeading()">Add</button>
    </body>
    </html>`

现在,在 media 文件夹中创建文件 script.js,并添加以下行。

javascript 复制代码
//script.js
function changeHeading() {
    document.getElementById("count").textContent = +document.getElementById("count").textContent + 1
} 

运行扩展后的预期输出

提示: 您无需重新加载即可查看脚本部分的更改,只需关闭并重新打开 Web 视图即可。


实施 React、TypeScript、Tailwind

在了解了有关扩展和 webview 的大量知识之后,是时候了解框架了,因为显而易见的原因是它们在使用不同的库时使事情变得更容易。

从 React 开始,您可以选择您选择的任何框架。

步骤 1 使用代码初始化扩展yo code

vbnet 复制代码
yo code

? What type of extension do you want to create? New Extension (TypeScript)
? Whats the name of your extension? react-ext
? Whats the identifier of your extension? react-ext
? Whats the description of your extension? LEAVE BLANK
? Initialize a git repository? Yes
? Bundle the source code with webpack? No
? Which package manager to use? npm

? Do you want to open the new folder with Visual Studio Code? Open with `code`

步骤 2在根目录中使用typescript创建一个 React应用程序。****

lua 复制代码
npx create-react-app web --template typescript
cd web

步骤 3在react app目录web中,设置tailwindcss

csharp 复制代码
npm i -D tailwindcss postcss
npx tailwindcss init

编辑tailwind.config.js

css 复制代码
//tailwind.config.js
module.exports = {
  content: ['./src/**/*.{js,jsx,ts,tsx}'],
  theme: {
    extend: {},
  },
  plugins: [],
}

编辑web/src/index.css

less 复制代码
@tailwind base;
@tailwind components;
@tailwind utilities;

body {
  @apply p-0;
}

步骤 4在 React 目录中,创建名为 .postcssrc 的文件

css 复制代码
//.postcssrc
{
  plugins: {
    tailwindcss: { },
  },
}

步骤 5编辑react appweb/src/App.tsx

javascript 复制代码
function App() {
  return (
    <div className="bg-gradient-to-r from-blue-600 to-purple-500 p-10">
      <p className="text-white/80 text-xl font-semibold">
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Ea, explicabo
        doloremque deserunt, voluptates, fugiat dolorem consectetur odio autem
        quas ipsa veniam ducimus necessitatibus exercitationem numquam assumenda
        natus beatae sed velit!
      </p>
    </div>
  );
}

export default App;

步骤 6安装 Parcel,最轻量级的打包器

ParcelReact 根目录 web 中安装 Parcel 作为开发依赖项

css 复制代码
npm i -D parcel

在 React 应用程序内部,编辑package.json

json 复制代码
//web/package.json
{
...,
"source": "src/index.tsx",
"scripts": {
    "start": "parcel", //overwrite 
    "build": "parcel build", //overwrite
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
}

运行Parcel

shell 复制代码
npm start

#> web@0.1.0 start
#> parcel

#Server running at http://localhost:1234

每次您更改 src 内的内容或与 src/index.tsx 相关的内容(例如 index.css)时,它都会重新运行快速构建并将其存储在 React 应用程序目录内的 dist 文件夹中,作为 index.jsindex.css

步骤 7现在进入扩展集成部分,编辑src/extension.ts

bash 复制代码
import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {

    let webview = vscode.commands.registerCommand('react-ext.namasteworld', () => {

        let panel = vscode.window.createWebviewPanel("webview", "React", vscode.ViewColumn.One, {
            enableScripts: true
        })

        // web is for my react root directory, rename for yours

        let scriptSrc = panel.webview.asWebviewUri(vscode.Uri.joinPath(context.extensionUri, "web", "dist", "index.js"))

        let cssSrc = panel.webview.asWebviewUri(vscode.Uri.joinPath(context.extensionUri, "web", "dist", "index.css"))

        panel.webview.html = `<!DOCTYPE html>
        <html lang="en">
          <head>
            <link rel="stylesheet" href="${cssSrc}" />
          </head>
          <body>
            <noscript>You need to enable JavaScript to run this app.</noscript>
            <div id="root"></div>
            <script src="${scriptSrc}"></script>
          </body>
        </html>
        `
    });

    context.subscriptions.push(webview);
}

export function deactivate() { }

最重要的过程!

不要忘记在 package.json 中手动写入所有注册的命令,这将导致命令面板中缺少 UI 选项Ctrl+Shift+P

为此,请转到扩展根目录的 package.json

json 复制代码
{
...,
"contributes": {
    "commands": [
      {
        "command": "react-ext.namasteworld",
        "title": "React Web View"
      }
    ]
  },
}

现在是最后一步

  1. 只需按,就会打开Ctrl F5另一个扩展开发。
  2. 在另一个测试 vscode 编辑器Extension Development 上,按Ctrl+Shift+P打开命令面板
  3. 搜索您注册的命令,您在 package.json 中给出的名称,在我的例子中是React Web View

并且必须弹出类似的窗口,如下所示

预期步骤:

最后的结果: 在 React 应用程序或 App.tsx 中进行更改后,无需重新运行,重新打开窗口,如下所示

相关推荐
移民找老国1 天前
加拿大移民新风向
java-ee·maven·phpstorm·visual studio code·nio
闪亮Girl3 天前
vs2015安装插件QtPackage.vsix等vsix文件类型
visual studio code
SuperYing4 天前
💯What?维护新老项目频繁切换node版本太恼火?开发一个vscode插件自动切换版本,从此告别烦恼
前端·visual studio code
羊小猪~~5 天前
数据结构C语言描述1(图文结合)--顺序表讲解,实现,表达式求值应用,考研可看
java·c语言·数据结构·c++·链表·visual studio code·visual studio
羊小猪~~5 天前
C/C++语言基础--C++模板与元编程系列三(变量模板、constexpr、萃取等…………)
java·c语言·开发语言·c++·visual studio code·visual studio
羊小猪~~8 天前
C/C++语言基础--C++模板与元编程系列二类模板、全特化、偏特化、编译模型简介、实现简单Vetctor等…………)
java·c语言·开发语言·c++·visual studio code·visual studio
编程老船长14 天前
用PlantUML让状态图“动”起来 —— 快速绘制老师申报课程流程
uml·visual studio code
风雪中的兔子17 天前
vscode插件开发入门:小试牛刀
前端·visual studio code
musiclvme17 天前
ubuntu22.04下GStreamer源码编译单步调试
ubuntu·音视频·visual studio code
Luncert19 天前
Vscode 插件开发 - TreeView
visual studio code