使用 Vue.js 构建 VS Code 扩展

35 篇文章 3 订阅
订阅专栏
1 篇文章 0 订阅
订阅专栏
1 篇文章 0 订阅
订阅专栏

使用 Vue.js 构建 VS Code 扩展

在这里插入图片描述

Visual Studio (VS) Code 是开发人员在日常任务中最喜欢使用的代码编辑器之一。它的构建考虑到了可扩展性。在某种程度上,VS Code 的大部分核心功能都是作为扩展构建的。您可以查看 VS Code 扩展存储库 ( https://github.com/microsoft/vscode/tree/main/extensions ) 以了解我在说什么。

VS Code 在底层是一个电子 ( https://www.electronjs.org/ ) 跨环境应用程序,可以在 UNIX、Mac OSX 和 Windows 操作系统上运行。因为它是一个电子应用程序,你可以通过编写 JavaScript 插件来扩展它。事实上,任何可以转换为 JavaScript 的语言都可以用来构建扩展。例如,VS Code 文档网站提示使用 TypeScript ( https://www.typescriptlang.org/ ) 来编写 VS Code 扩展。VS Code 团队提供的所有代码示例 ( https://github.com/microsoft/vscode-extension-samples ) 都是使用 TypeScript 构建的。

VS Code 支持非常广泛的 API,您可以在 VS Code API ( https://code.visualstudio.com/api )上查看和阅读。

VS Code 允许您扩展它支持的几乎所有功能。您可以构建自定义命令、创建新的颜色主题、在 WebView 中嵌入自定义 HTML、通过添加新视图为活动栏做出贡献、利用树视图在侧边栏上显示分层数据以及许多其他可扩展性选项。扩展功能概述页面 ( https://code.visualstudio.com/api/extension-capabilities/overview ) 详细介绍了所有 VS Code 扩展功能。如果您想跳过概述并直接转到有关如何构建具有功能的实际扩展的详细信息,请查看扩展指南页面 ( https://code.visualstudio.com/api/extension-guides/overview )。

在 VS Code 中构建扩展是一个巨大的话题,可以在许多书籍和无数文章中详细介绍。在这篇文章中,我将重点关注:

  • 创建 VS Code 命令
  • 使用 Webview API 在 Webview 面板和视图中嵌入 Vue.js 应用程序
  • 将视图容器添加到活动栏

VS Code UI 架构

在我深入研究构建扩展之前,了解构成 VS Code UI 的部分和部分很重要。

我将从 VS Code 网站借用两张图表来帮助说明这些概念。图 1说明了 VS Code UI 的主要部分。

在这里插入图片描述

图 1: VS Code 主要部分

VS Code 有以下主要部分:

  • 活动栏:活动栏上的每个图标都代表一个视图容器。反过来,这个容器在里面承载一个或多个视图。此外,您也可以扩展现有的。例如,您可以将新视图添加到资源管理器视图中。
  • 侧边栏:侧边栏是托管视图的容器。例如,您可以向侧边栏添加树视图或 Web 视图视图。
  • 编辑器:编辑器托管 VS Code 使用的不同类型的编辑器。例如,VS Code 使用文本编辑器来允许您读/写文件。另一种编辑器允许您编辑工作区和用户设置。例如,您还可以使用 Webview 贡献您自己的编辑器。
  • 面板:面板允许您添加带有视图的视图容器。
  • 状态栏:状态栏承载可以使用文本和图标显示的状态栏项目。您还可以将它们视为单击它们时触发操作的命令。

图 2说明了 VS Code UI 的主要部分的内容。

在这里插入图片描述

图 2: VS Code 部分详细信息

  • Activity Bar 承载 View Containers,而 View Containers 又承载着 Views。
  • 视图具有视图工具栏。
  • 侧边栏有一个侧边栏工具栏。
  • 编辑器有一个编辑器工具栏。
  • 面板托管视图容器,而后者又托管视图。
  • 面板有一个面板工具栏。

VS Code 允许我们使用其 API 扩展任何主要和次要部分。

VS Code API 足够丰富,允许开发人员扩展它提供的几乎所有功能。

你的第一个 VS Code 扩展

要开始构建您自己的自定义 VS Code 扩展,请确保您的计算机上安装了Node.js ( https://nodejs.org/en/ ) 和 Git ( https://git-scm.com/ )。不用说,您的计算机上也需要安装 VS Code(https://code.visualstudio.com/download)。

我将使用 Yeoman ( https://yeoman.io/ ) CLI 生成一个新的 VS Code 扩展项目。Microsoft 提供并支持 Yo Code ( https://www.npmjs.com/package/generator-code ) Yeoman 生成器,以在 TypeScript 或 JavaScript 中构建完整的 VS Code 扩展。

开始吧!

步骤1

通过运行以下命令安装 Yeoman CLI 和 Yo 代码生成器:

npm install -g yo generator-code

第2步

运行以下命令以搭建准备开发的 TypeScript 或 JavaScript 项目。

yo code

在创建新的 VS Code 扩展项目的过程中,代码生成器会询问一些问题。我将通过它们来创建应用程序。

图 3显示了生成器的起点。

在这里插入图片描述

图 3启动扩展项目脚手架

您可以选择 TypeScript 或 JavaScript。您在网上找到的大多数示例都是用 TypeScript 编写的。在编写和创作扩展程序时,使用 TypeScript 使您的生活更轻松,这将是明智之举。

接下来,您需要提供扩展的名称,如图 4所示。

在这里插入图片描述

图 4命名 VS Code 扩展

现在,您指定扩展的标识符 (ID)。您可以保留默认设置或提供您自己的设置。我倾向于不使用空格或破折号 (-) 来分隔标识符名称。

然后,您可以提供扩展程序的描述。

接下来的三个问题如图 5所示。

  • 初始化 Git 存储库?是的
  • 使用 Webpack 捆绑扩展?是的
  • 使用哪个包管理器?新产品经理

在这里插入图片描述

图 5完成代码生成器脚手架

生成器获取您所有的答案并为您的应用程序搭建支架。完成后,进入新的扩展文件夹并通过运行以下命令打开 VS Code:

cd vscodeexample && code .

第 3 步

让我们快速探索扩展项目。

图 6列出了 Yo Code 为您生成的所有文件。

在这里插入图片描述

图 6项目文件

  • /.vscode/目录包含帮助我们轻松测试扩展的配置文件。
  • /dist/目录包含扩展的编译版本。
  • /src/目录包含您为构建扩展而编写的源代码。
  • package.json文件是默认的 NPM 配置文件。您可以使用此文件来定义您的自定义命令、视图、菜单等等。
  • vsc-extension-quickstart.md文件包含对扩展项目的介绍以及有关如何开始构建 VS Code 扩展的文档。

Microsoft 提供了 Yo Code Yeoman 生成器来帮助您快速轻松地构建 VS Code 扩展项目。

步骤4

打开package.json文件,让我们探索构建此扩展所需的重要部分。

"contributes": {
    "commands": [
        {
            "command": "vscodeexample.helloWorld",   
            "title": "Hello World"
        }
    ]
},

您可以在贡献部分中定义自定义命令。定义新命令时,您至少要提供命令和标题。该命令应唯一标识您的命令。默认情况下,使用的命令是您在搭建扩展时指定的扩展标识符与代表您提供的命令的任意字符串的串联。新命令现在会自动显示在命令面板中。

VS Code 定义了许多内置命令,您甚至可以以编程方式使用它们。例如,您可以执行workbench.action.newWindow命令来打开一个新的 VS Code 实例。

这是VS Code中内置命令的完整列表 ( https://code.visualstudio.com/api/references/commands )。

该命令暂时不执行任何操作。您仍然需要将此命令绑定到我将很快定义的命令处理程序。VS Code 提供了registerCommand()为你做关联的功能。

您应该定义一个激活事件,当用户触发命令时将激活扩展。是激活事件让 VS Code 定位命令并将其绑定到命令处理程序。请记住,默认情况下并不总是激活扩展。例如,当您打开具有特定文件扩展名的文件时,可能会激活扩展名。这就是为什么需要确保在运行任何命令之前激活扩展。

package.json文件定义了 activationEvents 部分:

"activationEvents": [ "onCommand:vscodeexample.helloWorld" ],

当用户从命令面板或通过键绑定调用命令时,扩展将被激活并且registerCommand()函数将绑定(vscodeexample.helloWorld)到正确的命令处理程序。

第 5 步

现在是探索扩展源代码并将命令与命令处理程序一起注册的时候了。扩展源代码位于/src/extension.ts文件中。我已经清理了这个文件如下:

import * as vscode from 'vscode';

export function activate(
    context: vscode.ExtensionContext) {
        context.subscriptions.push(...);
    }

export function deactivate() {}

VS Codeactivate()在想要激活扩展时调用该函数。同样,当它调用该deactivate()函数时,它想停用它。请记住,扩展仅在您声明的激活事件之一发生时激活。

如果您在命令处理程序中实例化对象并希望 VS Code 稍后为您释放它们,请将新的命令注册推送到context.subscriptions数组中。VS Code 维护这个数组并将代表你进行垃圾收集。

让我们注册Hello World命令如下:

context.subscriptions.push(
    vscode.commands.registerCommand(
       'vscodeexample.helloWorld',
       () => {
           vscode.window.showInformationMessage('...');
        }
    )
);

vscode对象是访问整个 VS Code API 的关键。注册命令处理程序的方式与在 JavaScript 中注册 DOM 事件的方式类似。该代码将相同的命令标识符(您之前在package.json文件中的 commands 和 activationEvents 部分下声明的那个标识符)绑定到命令处理程序。

当用户触发命令时,VS Code 会显示一条信息消息。

让我们通过单击 来测试扩展F5。VS Code 打开一个加载了新扩展的新实例。要触发命令,请打开命令面板并开始输入“hello”。

图 7显示了 VS Code 如何将可用命令过滤为您想要的命令。

在这里插入图片描述

图 7过滤的命令面板

现在单击该命令,图 8显示了信息消息如何出现在编辑器的右下方。

在这里插入图片描述

图 8显示信息消息

恭喜!你刚刚完成了你的第一个 VS Code 扩展!

使用 Vue CLI 使用 Vue.js 构建 VS Code 扩展

让我们用你新学到的知识来创造更有趣的东西吧!

在本节中,您将使用 Vue CLI 创建一个新的 Vue.js 应用程序并将其作为单独的编辑器托管在 Webview 中。

Webview API 允许您在 VS Code 中创建完全可自定义的视图。我喜欢将 Webview 视为 VS Code 中的 iframe。它可以在此框架内呈现任何 HTML 内容。它还支持扩展和加载的 HTML 页面之间的双向通信。视图可以向扩展发布消息,反之亦然。

Webview API 支持我将在本文中探讨的两种类型的视图:

  • WebviewPanel 是 Webview 的包装器。它用于在 VS Code 的编辑器中显示 Webview。
  • WebviewView 是 Webview 的包装器。它用于在侧边栏中显示 Web 视图。

在这两种类型中,Webview 都承载 HTML 内容!

Webview API 文档内容丰富,包含使用它所需的所有详细信息。在 Webview API ( https://code.visualstudio.com/api/extension-guides/webview ) 上查看。

让我们开始构建 Vue.js 示例应用程序并将其托管在 VS Code 的编辑器中。

Webview 允许您通过将 HTML 内容与 JavaScript 和 CSS 资源文件一起嵌入来丰富您的 VS Code 扩展。

步骤1

使用 Yeoman 生成一个新的 VS Code 扩展项目,如上所述。

第2步

添加一个新命令来打开 Vue.js 应用程序。找到该package.json文件并添加以下内容:

"contributes": { 
    "commands": [ 
        {
            "command": "vscodevuecli:openVueApp", 
            "title": "Open Vue App"
        }
    ]
},

该命令的标识符为vscodevuecli:openVueApp

然后你声明一个激活事件如下:

"activationEvents": ["onCommand:vscodevuecli:openVueApp"],

第 3 步

切换到extension.js文件并在activate()函数内部注册命令处理程序。

context.subscriptions.push(   
    vscode.commands.registerCommand(
        'vscodevuecli:openVueApp', () => 
            {
                WebAppPanel.createOrShow(context.extensionUri);
            }
    )
);

在命令处理程序中,您正在实例化一个新的WebAppPanel类实例。它只是一个 WebviewPanel 的包装器。

步骤4

在这一步中,您将使用 Vue CLI 生成一个新的 Vue.js 应用程序。按照本指南 ( https://cli.vuejs.org/guide/creating-a-project.html#vue-create )/web/在扩展项目的根目录中搭建一个新的 Vue.js 应用程序。

确保将您使用的任何图像放在/web/img/目录中。稍后,您将dist在编译应用程序时将此目录复制到该目录中。

通常,托管 Vue.js 应用程序的 HTML 页面会请求从服务器上的本地文件系统渲染图像。但是,当 Webview 加载应用程序时,它不能只是请求和访问本地文件系统。出于安全原因,Webview 应该仅限于项目本身内的几个目录。

此外,VS Code 使用特殊的 URI 来加载 Webview 中的任何资源,包括 JavaScript、CSS 和图像文件。因此,您需要一种基于所有图像的方法,因此您使用 VS Code 用于访问本地资源的 URI。正如您将在第 5 步中看到的,该扩展将 VS Code 基 URI 注入到 Webview 的 HTML 正文中,以便 Vue.js 应用程序可以使用它来构建其图像。

因此,要使用注入的基本 URI,您将添加一个 Vue.js mixin,它从 HTML DOM 读取基本 URI 的值,并使其可用于 Vue.js 应用程序。

请注意,如果您想在 Webview 之外运行 Vue.js 应用程序,则需要将以下内容放入/web/public/index.html文件中:

<body>   
    <input hidden data-uri="">
    ...
</body>

/web/src/mixins/ExtractBaseUri.js文件中,定义一个新的 Vue.js mixin。它使baseUri任何 Vue.js 组件都可以使用data 选项:

data() {
    return {
        baseUri: '',   
    };
},

然后它使用 Vue.jsmounted()生命周期钩子来提取值:

mounted() {
    const dataUri = document.querySelector('input[data-uri]'); 
    if (!dataUri) return;

    this.baseUri = dataUri.getAttribute('data-uri');
},

如果它找到具有名为 data-uri 的数据属性的输入字段,它会读取该值并将其分配给该baseUri属性。

下一步是在/web/src/main.js文件中提供mixin :

Vue.mixin(ExtractBaseUri);

切换到 App.vue 组件并将图像元素替换为以下内容:

<img alt="Vue logo" :src="`${baseUri}/img/logo.png`">

现在应用程序已准备好在本地和 Webview 内运行,让我们通过 Vue.js 配置文件自定义编译过程。

创建一个新文件。清单 1显示了该文件的完整源代码。/web/vue.config.js

清单 1: vue.config.js
const path = require('path');

module.exports = {
    filenameHashing: false,
    outputDir: path.resolve(__dirname, "../dist-web"),  
    chainWebpack: config => {   
        config.plugin('copy') 
            .tap(([pathConfigs]) => {
                const to = pathConfigs[0].to
                // so the original `/public` folder keeps priority
                pathConfigs[0].force = true

                // add other locations.
                pathConfigs.unshift({ 
                    from: 'img',  
                    to: `${to}/img`,
                })
                
                return [pathConfigs]    
            })
    },
}

基本上,您正在执行以下操作:

  • 从编译的文件名中删除哈希。编译后的 JavaScript 文件看起来像 app.js,只是文件名中没有任何哈希值。
  • 将输出目录设置为/dist-web/. Vue CLI 使用此属性来决定放置已编译应用程序文件的位置。
  • /web/img/目录及其所有内容复制到目标目录。

接下来,让我们修复 NPM 脚本,以便您可以使用单个脚本同时编译扩展文件和 Vue.js 应用程序。

首先,Concurrently通过运行以下命令安装NPM 包:

npm i --save-dev concurrently

然后,找到该package.json文件并将监视脚本替换为:

"watch": "concurrently \"npm --prefix web run serve\" \"webpack --watch\"",

现在,每次更改两个文件夹中的任何文件时,监视脚本都会编译 Vue.js 应用程序和扩展文件。

运行以下命令编译两个应用程序并生成/dist-web/目录:

npm run watch

就这样吧!Vue.js 应用程序已准备好托管在 Web 视图中。

第 5 步

/src/目录中添加一个新的 TypeScript 文件并将其命名为WebAppPanel.ts. 清单 2包含该文件的完整源代码。让我们剖析它并解释它最相关的部分。

清单 2:WebAppPanel.ts
import * as vscode from "vscode";
import { getNonce } from "./getNonce";

export class WebAppPanel {

    public static currentPanel: WebAppPanel | undefined;

    public static readonly viewType = "vscodevuecli:panel";

    private readonly _panel: vscode.WebviewPanel;  
    private readonly _extensionUri: vscode.Uri;  
    private _disposables: vscode.Disposable[] = [];

    public static createOrShow(extensionUri: vscode.Uri) { 
        const column = vscode.window.activeTextEditor
        ? vscode.window.activeTextEditor.viewColumn: undefined;

        // If we already have a panel, show it.      
        if (WebAppPanel.currentPanel) {
            WebAppPanel.currentPanel._panel.reveal(column);
            return;     
        }
        
        // Otherwise, create a new panel. 
        const panel = vscode.window.createWebviewPanel(
            WebAppPanel.viewType,
            'Web App Panel',
            column || vscode.ViewColumn.One,
            getWebviewOptions(extensionUri),
        );

        WebAppPanel.currentPanel = new WebAppPanel(panel, extensionUri);    
    }

    public static kill() { 
        WebAppPanel.currentPanel?.dispose();
        WebAppPanel.currentPanel = undefined; 
    }

    public static revive(panel: vscode.WebviewPanel,
        extensionUri: vscode.Uri) {    
        WebAppPanel.currentPanel = new WebAppPanel(panel, extensionUri);  
    }

    private constructor(panel: vscode.WebviewPanel,
        extensionUri: vscode.Uri) {    
            this._panel = panel;    
            this._extensionUri = extensionUri;

        // Set the webview's initial html content    
            this._update();

            this._panel.onDidDispose(() => this.dispose(), 
                null, this._disposables);
            
        // Update the content based on view changes 
            this._panel.onDidChangeViewState(  
                e => {
                    if (this._panel.visible) {  
                        this._update();
                    }
                },
                null,
                this._disposables
            );

            // Handle messages from the webview  
            this._panel.webview.onDidReceiveMessage(    
                message => {
                    switch (message.command) {
                        case 'alert': vscode.window.showErrorMessage(message.text); 
                        return;
                    }
                },
                null,
                this._disposables 
            );
        }

        public dispose() {    
            WebAppPanel.currentPanel = undefined;  

            // Clean up our resources  
            this._panel.dispose();

            while (this._disposables.length) {
                const x = this._disposables.pop(); 
                    if (x) {
                    x.dispose();
                    }
            }
        }

        private async _update() {
            const webview = this._panel.webview;    
            this._panel.webview.html = this._getHtmlForWebview(webview);  
        }
        
        private _getHtmlForWebview(webview: vscode.Webview) {    
            const styleResetUri = webview.asWebviewUri(      
                vscode.Uri.joinPath(this._extensionUri, "media", "reset.css")   
            );

            const styleVSCodeUri = webview.asWebviewUri(    
                vscode.Uri.joinPath(this._extensionUri, "media", "vscode.css")
            );
            const scriptUri = webview.asWebviewUri( 
                vscode.Uri.joinPath(this._extensionUri, "dist-web", "js/app.js")
            );
            
            const scriptVendorUri = webview.asWebviewUri(
                vscode.Uri.joinPath(this._extensionUri, "dist-web", 
                    "js/chunk-vendors.js")
            );

            const nonce = getNonce();  
            const baseUri = webview.asWebviewUri(vscode.Uri.joinPath(
                this._extensionUri, 'dist-web')
                ).toString().replace('%22', '');

            return `      
                <!DOCTYPE html>
                <html lang="en">
                <head>
                    <meta charset="utf-8" />
                    <meta name="viewport" content="width=device-width, 
                        initial-scale=1" />
                    <link href="${styleResetUri}" rel="stylesheet">
                    <link href="${styleVSCodeUri}" rel="stylesheet">
                    <title>Web App Panel</title>
                </head>
                <body>
                <input hidden data-uri="${baseUri}">
                    <div id="app"></div>  
                    <script type="text/javascript"
                        src="${scriptVendorUri}" nonce="${nonce}"></script>  
                    <script type="text/javascript"
                        src="${scriptUri}" nonce="${nonce}"></script>
                </body>
                </html> 
            `;  
        }
}
function getWebviewOptions(extensionUri: vscode.Uri): 
vscode.WebviewOptions {    
    return {
        // Enable javascript in the webview
        enableScripts: true,

        localResourceRoots: [  
            vscode.Uri.joinPath(extensionUri, 'media'),  
            vscode.Uri.joinPath(extensionUri, 'dist-web'),
        ]
    };
}

您将WebAppPanel类定义为单例以确保它始终只有一个实例。这是通过添加以下内容来完成的:

public static currentPanel: WebAppPanel | undefined;

它包装了 WebviewPanel 的一个实例并通过定义以下内容来跟踪它:

private readonly _panel: vscode.WebviewPanel;

createOrShow()功能的核心WebAppPanel类。它检查是否currentPanel已经实例化,并立即显示WebviewPanel

if (WebAppPanel.currentPanel) {   
    WebAppPanel.currentPanel._panel.reveal(column);
    return;
}

否则,它WebviewPanel使用该createWebviewPanel()函数实例化一个新的,如下所示:

const panel = vscode.window.createWebviewPanel(   
    WebAppPanel.viewType,
    'Web App Panel',    
    column || vscode.ViewColumn.One,    
    getWebviewOptions(extensionUri),
);

该函数接受以下参数:

  • viewType:指定视图类型的唯一标识符WebviewPanel
  • 标题:标题WebviewPanel
  • showOptions:在Webview编辑器中的显示位置
  • 选项:新的设置Panel

选项是在getWebviewOptions()函数内部准备好的。

function getWebviewOptions(   
    extensionUri: vscode.Uri
): vscode.WebviewOptions {
    return {    
        enableScripts: true,
        localResourceRoots: [
            vscode.Uri.joinPath(extensionUri, 'media'),
            vscode.Uri.joinPath(extensionUri, 'dist-web'),
        ]
    };
}

它返回一个具有两个属性的对象:

  • enableScripts:控制是否在 Webview 内容中启用脚本
  • localResourceRoots:指定 Webview 可以使用 URI(表示磁盘上的文件或任何其他资源的通用资源标识符)加载本地资源的根路径。这保证了扩展不能访问您指定的路径之外的文件。

WebviewPanel 包装了一个 Webview 以在 VS 代码编辑器中呈现。

createOrShow()函数通过调用其私有构造函数将 的值设置currentPanel为 的新实例而结束WebAppPanel

构造函数最重要的部分是设置Webview的HTML内容如下:

this._panel.webview.html = this._getHtmlForWebview(webview);

_getHtmlForWebview()函数准备并返回 HTML 内容。

您将在几乎每个创建的 Web 视图中嵌入两个 CSS 文件。该reset.css文件会重置 Web 视图中的一些 CSS 属性。尽管该vscode.css文件包含 VS Code 的默认主题颜色和 CSS 属性。这对于使您的 Webview 具有与 VS Code 中的任何其他编辑器相同的外观和感觉至关重要。

const styleResetUri = webview.asWebviewUri(   
    vscode.Uri.joinPath(this._extensionUri, "media", "reset.css"));

const styleVSCodeUri = webview.asWebviewUri(   
    vscode.Uri.joinPath(this._extensionUri, "media", "vscode.css"));

_extensionUri属性表示包含当前扩展的目录的 URI。WebviewasWebviewUri()函数将本地文件系统的 URI 转换为可在 Webviews 中使用的 URI。它们不能使用file: URI从工作区或本地文件系统直接加载资源。该asWebviewUri()函数采用本地文件:URI 并将其转换为可在 Webview 中使用以加载相同资源的 URI。

然后,该函数为其他资源准备 URI,包括在步骤 5 中由 Vue CLI 编译的js/app.jsjs/chunk-vendors.js文件。

记住在步骤 4 中,Vue CLI 复制/dist-web/img/目录中的所有图像。Vue.js 应用程序中的所有图像路径都使用一个基本 URI,该 URI 在 Webview 中运行时指向 VS Code URI,或者在独立模式下运行时指向 file: URI。

在此阶段,您需要生成一个 VS Code 基础 URI 并将其注入到 Vue.js 通过 Vue.js mixin 加载和读取的隐藏输入字段中。

WebAppPanel 使用以下代码生成扩展的 VS Code 基 URI:

const baseUri = 
    webview.asWebviewUri(
        vscode.Uri.joinPath(
            this._extensionUri, 'dist-web'
        )
    ).toString().replace('%22', '');

它通过在同时加载 Vue.js 应用程序的 HTML 页面内的隐藏输入字段上设置 data-uri 数据属性值,将此 URI 传达给 Vue.js 应用程序。

最后,该函数将所有 CSS 和 JavaScript URI 嵌入 HTML 页面内容并返回它。

而已!

让我们通过单击F5键来运行扩展,并开始在刚刚打开的 VS Code 实例的命令面板中键入“Open Vue App”,如图 9所示。

在这里插入图片描述

图 9打开 Vue App 命令

单击该命令以在新编辑器窗口的 Web 视图中加载 Vue.js 应用程序,如图 10所示。

在这里插入图片描述

图 10:在 VS Code 扩展中加载 Vue 应用程序

这就是在 VS Code 扩展中加载由 Vue CLI 生成的 Vue.js 应用程序所需的全部内容。

使用 Rollup.js 使用 Vue.js 构建 VS Code 扩展

在本节中,我将扩展您迄今为止所构建的内容,并介绍一个新场景,其中 Vue CLI 可能不是该工作的正确工具。

如您所知,Vue CLI 将整个 Vue.js 应用程序编译为一个app.js文件。让我们暂时搁置 CLI 提供的分块功能。

在构建 VS Code 扩展时,有时您需要在编辑器的 WebviewPanel 中加载一个 HTML 页面。同时,您可能需要WebviewView在侧边栏中的a 内加载另一个 HTML 页面。当然,您可以使用纯 HTML 和 JavaScript 来构建您的 HTML,但是因为您想使用 Vue.js 来构建您的 HTML 页面,所以在这种情况下 Vue CLI 不是一个选项。

您需要创建一个 Vue.js 应用程序,其中包含多个独立的小型 Vue.js 组件,这些组件被单独编译成单独的 JavaScript 文件,而不仅仅是合并到一个app.js文件中。

我想出了一个解决方案,该解决方案涉及使用至少两个文件创建微型 Vue.js 应用程序。一个 JavaScript 文件和一个或多个 Vue.js 组件(具有许多子组件的根组件)。JavaScript 文件导入 Vue.js 框架并将相应的 Vue.js 根组件挂载到 HTML 页面内的 DOM 中。

对于这个解决方案,我决定使用 Rollup.js ( https://rollupjs.org/ ) 来编译文件。

让我们通过构建一个新的 VS Code 扩展来一起探索这个解决方案,它可以做两件事:

  • 使用 WebviewPanel 将 Vue.js 应用程序(或根组件)托管到新编辑器中
  • 使用 WebviewView 将 Vue.js 应用程序(或根组件)托管到侧边栏中

步骤1

像之前一样,使用 Yeoman 生成一个新的 VS Code 扩展项目。

第2步

添加一个新命令来打开 Vue.js 应用程序。找到该package.json文件并添加以下内容:

"contributes": {
    "commands": [ 
        { 
            "command": "vscodevuerollup:openVueApp", 
            "title": "Open Vue App", 
            "category": "Vue Rollup"    
        }
    ]
},

该命令的标识符为vscodevuerollup:openVueApp

然后你声明一个激活事件:

"activationEvents": ["onCommand:vscodevuerollup:openVueApp"],

此外,定义一个新的 View Container 以在 Activity Bar 内加载。清单 3显示了您需要在package.json文件中添加的部分。

清单 3:添加一个视图容器
    "viewsContainers": {
        "activitybar": [   
            {
                "id": "vscodevuerollup-sidebar-view", 
                "title": "Vue App",     
                "icon": "$(remote-explorer)"
            }
        ]
    },
    "views": {
        "vscodevuerollup-sidebar-view": [
            {
                "type": "webview",      
                "id": "vscodevuerollup:sidebar",
                "name": "vue with rollup",
                "icon": "$(remote-explorer)",
                "contextualTitle": "vue app"  
            }
        ]
    },

活动栏条目的 ID 为vscodevuerollup-sidebar-view。此 ID 与将托管在此视图容器内且在视图部分中定义的视图集合的 ID 相匹配。

"views": {"vscodevuerollup-sidebar-view": [...]}

( vscodevuerollup-sidebar-view) 条目表示视图的集合。每个视图都有一个 ID。

{   
    "type": "webview",  
    "id": "vscodevuerollup:sidebar",   
    "name": "vue with rollup", 
    "icon": "$(remote-explorer)",  
    "contextualTitle": "vue app"
}

记下这个 ID vscodevuerollup:sidebar,向上滚动到 activatinEvents 部分,并添加以下条目:

"onView:vscodevuerollup:sidebar"

使用onView声明时,VS Code 会在具有指定 ID 的视图在侧边栏上展开时激活扩展。

第 3 步

切换到extension.js文件并在activate()函数内部注册命令处理程序。

首先,注册vscodevuerollup:openVueApp命令:

context.subscriptions.push(
    vscode.commands.registerCommand(
        'vscodevuerollup:openVueApp', async (args) => {
            WebAppPanel.createOrShow(context.extensionUri); 
        }
    )
);

然后注册vscodevuerollup:sendMessage命令:

const sidebarProvider = new SidebarProvider(context.extensionUri);

context.subscriptions.push(
    vscode.window.registerWebviewViewProvider(
        SidebarProvider.viewType,
        sidebarProvider
    )
);

您正在实例化该类的一个新实例SidebarProvider并使用该vscode.window.registerWebviewViewProvider()函数来注册此提供程序。

在这里,您正在处理我之前提到的第二种类型的 Web 视图,WebviewView. 要将 Webview 加载到侧边栏中,您需要创建一个实现该WebviewViewProvider接口的类。它只是一个WebviewView.

WebviewViewProvider 包装了一个WebviewView,而后者又包装了一个 Webview。WebviewViewVS Code 中侧边栏内的渲染。

步骤4

在这一步中,您将创建一个自定义 Vue.js 应用程序。首先在扩展的根文件夹中创建 /web/ 目录。

在此目录中,创建三个不同的子目录:

  • pages:此目录包含所有 Vue.js 页面。
  • 组件:这包含所有 Vue.js 单文件组件 (SFC)。
  • img:这包含您在 Vue.js 组件中使用的所有图像。

让我们通过创建/web/pages/App.js文件并将以下代码粘贴到其中来添加第一个 Vue.js 页面:

import Vue from "vue";
import App from "@/components/App.vue";

new Vue({render: h => h(App)}).$mount("#app");

这里没有魔法!它与 Vue CLI 在main.js文件中用于在 HTML DOM 上加载和挂载 Vue.js 应用程序的代码相同。但是,在这种情况下,我只是安装了一个 Vue.js 组件。将此组件视为可能在树层次结构中使用其他 Vue.js 组件的根组件。

请注意,我App.vueCLI您之前创建的 Vue文件中借用了相同的文件。

让我们通过创建/web/pages/Sidebar.js文件并将此代码粘贴到其中来添加另一个页面:

import Vue from "vue";
import Sidebar from "@/components/Sidebar.vue";

new Vue({render: h => h(Sidebar)}).$mount("#app");

此页面加载并挂载 Sidebar.vue 组件。

清单 4显示了 Sidebar.vue 组件的完整内容。它定义了以下 UI 部分:

  • 显示从分机收到的消息。
  • 允许用户从 Vue.js 应用程序内向扩展程序发送消息。
  • 在扩展程序上执行命令以在编辑器内的 Web 视图中加载 App.js 页面。
清单 4:Sidebar.vue 组件
<template>  
    <div> 
        <p>Message received from extension</p>  
        <span>{{ message }}</span>

        <p>Send message to extension</p>
        <input type="text" v-model="text">
        <button @click="sendMessage">Send</button>

        <p>Open Vue App</p>
        <button @click="openApp">Open</button>
    </div>
</template>

<script> export default {
    data() {
        return {     
            message: '',
            text: '',   
        };
    },
    mounted() {
        window.addEventListener('message', this.receiveMessage);
    },
    beforeDestroy() {    
        window.removeEventListener('message', this.receiveMessage); 
    },  
    methods: {     
        openApp() {     
            vscode.postMessage({
                type: 'openApp',
            });
            this.text = '';  
        },
        sendMessage() { 
            vscode.postMessage({
                type: 'message',
                value: this.text,
            }); 
            this.text = '';  
        },
        receiveMessage(event) {
            if (!event) return;    
            
            const envelope = event.data;
            switch (envelope.command) {
                case 'message': { 
                    this.message = envelope.data;  
                    break;
                }
            };
        },
    },
}
</script>

<style scoped>
    p {
        margin: 10px 0; 
        padding: 5px 0;
        font-size: 1.2rem;
    }
    span {  
        display: inline-block;
        margin-top: 5px;  
        font-size: 1rem;
        color: orange;
    }
    hr {
        display: inline-block;  
        width: 100%;  
        margin: 10px 0;
    }
</style>

导航到扩展根目录并添加一个新rollup.config.js文件。

清单 5显示了该文件的完整内容。

清单 5: rollup.config.js
import path from "path";
import fs from "fs";

import alias from '@rollup/plugin-alias';
import commonjs from 'rollup-plugin-commonjs';
import esbuild from 'rollup-plugin-esbuild';
import filesize from 'rollup-plugin-filesize';
import image from '@rollup/plugin-image';
import json from '@rollup/plugin-json';
import postcss from 'rollup-plugin-postcss';
import postcssImport from 'postcss-import';
import replace from '@rollup/plugin-replace';
import resolve from '@rollup/plugin-node-resolve';
import requireContext from 'rollup-plugin-require-context';
import { terser } from 'rollup-plugin-terser';
import vue from 'rollup-plugin-vue';

const production = !process.env.ROLLUP_WATCH;

const postCssPlugins = [  
    postcssImport(),
];

export default fs  
    .readdirSync(path.join(__dirname, "web", "pages"))  
    .map((input) => {   
        const name = input.split(".")[0].toLowerCase();  
        return {     
            input: `web/pages/${input}`,     
            output: {
                file: `dist-web/${name}.js`,
                format: 'iife',
                name: 'app',
                sourcemap: false,    
            },
            plugins: [
                commonjs(),
                json(),
                alias({
                    entries: [{ find: '@',
                    replacement: __dirname + '/web/' }],
                }),
                image(),
                postcss({ extract: `${name}.css`,
                    plugins: postCssPlugins 
                }),
                requireContext(),
                resolve({  
                    jsnext: true,  
                    main: true, 
                    browser: true,  
                    dedupe: ["vue"],
                }),
                vue({ 
                    css: false
                }),
                replace({ 
                    'process.env.NODE_ENV': production ? 
                        '"production"' : '"development"',  
                    preventAssignment: true,
                }),
                esbuild({ 
                    minify: production, 
                    target: 'es2015',
                }),
                production && terser(),
                production && filesize(),
            ],
            watch: {
                clearScreen: false,
                exclude: ['node_modules/**'],     
            },
        };
    });

该文件最重要的部分:

export default fs  
    .readdirSync(      
        path.join(__dirname, "web", "pages")   
    )
    .map((input) => {
        const name = input.split(".")[0].toLowerCase();
        
    return {     
        input: `web/pages/${input}`,
        output: {
            file: `dist-web/${name}.js`,    
            format: 'iife',
            name: 'app',
},
...

代码片段遍历/web/pages/目录中的所有 *.js 页面,并将每个页面分别编译为目录中的新 JavaScript 文件/dist-web/

让我们Concurrently通过运行以下命令来安装NPM 包:

npm i --save-dev concurrently

然后,找到该package.json文件并将监视脚本替换为:

"watch": "concurrently \"rollup -c -w\" \"webpack --watch\"",

现在,每次更改两个文件夹中的任何文件时,监视脚本都会编译 Vue.js 页面和扩展文件。

运行此命令以编译两个应用程序并生成/dist-web/目录:

npm run watch

您现在可以看到在/dist-web/目录中创建的四个新文件:

  • 应用程序.js
  • 应用程序.css
  • 侧边栏.js
  • 侧边栏.css

每个页面都会生成两个文件,特别是 JavaScript 和 CSS 文件。

就这样吧!Vue.js 页面已准备好托管在 Web 视图中。

第 5 步

我们首先WebAppPanel.ts从使用 Vue CLI 的扩展项目中复制文件。然后将资源文件更改为包含/dist-web/app.js/dist-web/app.css.

清单 6显示了更改后该文件的整个源代码。

清单 6:WebAppPanel.ts 加载单个 Vue.js 根组件
import * as vscode from "vscode";
import { getNonce } from "./getNonce";

export class WebAppPanel {
    public static currentPanel: WebAppPanel | undefined;

    public static readonly viewType = "vscodevuerollup:panel";

    private readonly _panel: vscode.WebviewPanel; 
    private readonly _extensionUri: vscode.Uri;   
    private _disposables: vscode.Disposable[] = [];

    public static createOrShow(extensionUri: vscode.Uri) {      
        const column = vscode.window.activeTextEditor?
        vscode.window.activeTextEditor.viewColumn: undefined;

        // If we already have a panel, show it.
        if (WebAppPanel.currentPanel) {
            WebAppPanel.currentPanel._panel.reveal(column);
            return;      
        }

        // Otherwise, create a new panel.  
        const panel = vscode.window.createWebviewPanel(
            WebAppPanel.viewType,
            'Web App Panel',
            column || vscode.ViewColumn.One,
            getWebviewOptions(extensionUri),      
        );

        WebAppPanel.currentPanel = new WebAppPanel(panel, extensionUri);    
    }

    public static kill() {    
        WebAppPanel.currentPanel?.dispose();
        WebAppPanel.currentPanel = undefined; 
    }

    public static revive(panel: vscode.WebviewPanel,
        extensionUri: vscode.Uri) {
            WebAppPanel.currentPanel = new WebAppPanel(panel, extensionUri);  
        }
        
    private constructor(panel: vscode.WebviewPanel,
        extensionUri: vscode.Uri) {
            this._panel = panel;
            this._extensionUri = extensionUri;

            // Set the webview's initial html content
            this._update();
            this._panel.onDidDispose(() => this.dispose(), 
                null, this._disposables);

            // Update the content based on view changes 
            this._panel.onDidChangeViewState(  
                e => {
                    if (this._panel.visible) {
                        this._update();}
                },
                null,
                this._disposables    
            );
            
            // Handle messages from the webview
            this._panel.webview.onDidReceiveMessage(    
                message => {
                    switch (message.command) {
                        case 'alert': vscode.window.showErrorMessage(message.text);  
                        return;
                    }
                },
                null,
                this._disposables
            );
        }

        public dispose() {    
            WebAppPanel.currentPanel = undefined; 
            
            // Clean up our resources 
            this._panel.dispose();

            while (this._disposables.length) {      
                const x = this._disposables.pop();
                if (x) {
                    x.dispose();    
                }
            }
        }

        private async _update() { 
            const webview = this._panel.webview;     
            this._panel.webview.html = this._getHtmlForWebview(webview);  
        }

        private _getHtmlForWebview(webview: vscode.Webview) {
            const styleResetUri = webview.asWebviewUri(
                vscode.Uri.joinPath(this._extensionUri, "media", "reset.css")
            );
            const styleVSCodeUri = webview.asWebviewUri(      
                vscode.Uri.joinPath(
                    this._extensionUri, "media", "vscode.css")
            );

            const scriptUri = webview.asWebviewUri(
                vscode.Uri.joinPath(
                    this._extensionUri, "dist-web", "app.js")
            );
            
            const styleMainUri = webview.asWebviewUri(
                vscode.Uri.joinPath(
                    this._extensionUri, "dist-web", "app.css")    
            );

            const nonce = getNonce();
            
            return `      
                <!DOCTYPE html>
                <html lang="en">     
                <head>
                    <meta charset="utf-8" />
                    <meta name="viewport" content="width=device-width, 
                                                         initial-scale=1" />
                    <link href="${styleResetUri}" rel="stylesheet">
                    <link href="${styleVSCodeUri}" rel="stylesheet">
                    <link href="${styleMainUri}" rel="stylesheet">
                    <title>Web Pages Panel</title>  
                </head> 
                <body>
                    <div id="app"></div>
                    <script src="${scriptUri}" nonce="${nonce}">
                </body>
                </html> 
            `;
        }
}

function getWebviewOptions(extensionUri: vscode.Uri): vscode.WebviewOptions {
    return {
        // Enable javascript in the webview
        enableScripts: true,

        localResourceRoots: [
            vscode.Uri.joinPath(extensionUri, 'media'), 
            vscode.Uri.joinPath(extensionUri, 'dist-web'),
        ]
    };
}

添加一个新/src/SidebarProvider.ts文件并将清单 7的内容粘贴到其中。

清单 7:SidebarProvider.ts
import * as vscode from "vscode";
import { getNonce } from "./getNonce";

export class SidebarProvider implements vscode.WebviewViewProvider {
    public static readonly viewType = 'vscodevuerollup:sidebar';

    private _view?: vscode.WebviewView;

    constructor(private readonly _extensionUri: vscode.Uri) {}

    public resolveWebviewView(    
        webviewView: vscode.WebviewView,    
        context: vscode.WebviewViewResolveContext,
            _token: vscode.CancellationToken  
    ) {
        this._view = webviewView;

    webviewView.webview.options = {      
        // Allow scripts in the webview
        enableScripts: true,
        
        localResourceRoots: [
            this._extensionUri
        ],
    };

    webviewView.webview.html = this._getHtmlForWebview(webviewView.webview);

    webviewView.webview.onDidReceiveMessage(async (data) => {     
        switch (data.type) {
            case "message": {
                if (!data.value) {
                    return;
                }
                vscode.window.showInformationMessage(data.value);  
                break;
            }
            case "openApp": {  
                await vscode.commands.executeCommand(
                    'vscodevuerollup:openVueApp', { ...data }
                );
                break;
            }
            case "onInfo": {
                if (!data.value) {
                    return; 
                }
                vscode.window.showInformationMessage(data.value);  
                break;
            }
            case "onError": {
                if (!data.value) { 
                    return; 
                } 
                vscode.window.showErrorMessage(data.value); 
                break;
            }
        }
    });
    }

    public revive(panel: vscode.WebviewView) {
        this._view = panel; 
    }

    public sendMessage() {
        return vscode.window.showInputBox({
            prompt: 'Enter your message',
            placeHolder: 'Hey Sidebar!'
        }).then(value => {      
            if (value) {
                this.postWebviewMessage({  
                    command: 'message',  
                    data: value,});      
            }
        });
    }
    private postWebviewMessage(msg: {
        command: string,
        data?: any
    }) {
    vscode.commands.executeCommand(
                    'workbench.view.extension.vscodevuerollup-sidebar-view');  
    vscode.commands.executeCommand('workbench.action.focusSideBar');
    
    this._view?.webview.postMessage(msg); 
    }  

    private _getHtmlForWebview(webview: vscode.Webview) 
    { 
        const styleResetUri = webview.asWebviewUri(
            vscode.Uri.joinPath(
                this._extensionUri, "media", "reset.css")    
        );

        const styleVSCodeUri = webview.asWebviewUri(      
            vscode.Uri.joinPath(
                this._extensionUri, "media", "vscode.css")    
        );

        const scriptUri = webview.asWebviewUri(      
            vscode.Uri.joinPath(
                this._extensionUri, "dist-web", "sidebar.js")    
        );
        
        const styleMainUri = webview.asWebviewUri( 
            vscode.Uri.joinPath(
                this._extensionUri, "dist-web", "sidebar.css")   
        );

        const nonce = getNonce();

    return `
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="utf-8" />
            <meta name="viewport" content="width=device-width, 
                                                 initial-scale=1" />  
                <link href="${styleResetUri}" rel="stylesheet">
                <link href="${styleVSCodeUri}" rel="stylesheet">
                <link href="${styleMainUri}" rel="stylesheet">  
                <title>Web Pages Panel</title>
                <script nonce="${nonce}">    
                    const vscode = acquireVsCodeApi();
                </script>
        </head>     
        <body>
            <div id="app"></div>
            <script src="${scriptUri}" nonce="${nonce}">
        </body>
        </html>   
    `;
    }
}

SidebarProvider实现了WebviewViewProvider接口。它包装了 的一个实例WebviewView,而后者又包装了一个Webview包含实际 HTML 内容的 。

resolveWebviewView()功能位于此提供程序的核心。VS Code 使用它来WebviewSidebar. 正是在此函数中,您可以设置Webviewfor VS Code的 HTML 内容以将其显示在Sidebar. 提供程序加载资源文件/dist-web/sidebar.js/dist-web/sidebar.cssHTML 内部。

现在的 HTMLWebview包含以下代码:

<script>       
    const vscode = acquireVsCodeApi();
</script>

vscode对象将成为 Vue.js 应用程序可用于向扩展程序发布消息的桥梁。

而已!让我们按F5键运行扩展程序。VS Code 的一个新实例打开。

找到并单击活动栏上添加的最后一个图标。图 11显示了 Sidebar.vue 组件是如何加载到 Sidebar 部分中的。

在这里插入图片描述

图 11: Sidebar 内的 Sidebar.vue 组件

第 6 步

当用户单击侧边栏上的打开按钮时,让我们在编辑器中加载 App.vue 组件。

转到/web/components/Sidebar.vue文件并将按钮绑定到事件处理程序:

<button @click="openApp">Open</button>

然后,定义openApp()函数如下:

openApp() {
    vscode.postMessage({
        type: 'openApp',   
    });
},

该代码使用该vscode.postMessage()函数通过传递消息有效负载将消息发布到扩展程序。在这种情况下,有效负载仅指定消息的类型。

切换到SidebarProvider.ts文件并在resolveWebviewView()函数内部监听您刚刚定义的消息类型。您可以onDidReceiveMessage()按如下方式收听函数内发布的消息:

webviewView.webview.onDidReceiveMessage(
    async (data) => {
        switch (data.type) {
            case "openApp": {
                await vscode.commands.executeCommand(
                        'vscodevuerollup:openVueApp',
                        { ...data }
                    );
                break;
            }
            // more
        }
    }
);

当用户单击侧边栏上的“打开”按钮时,提供程序会通过执行命令vscodevuerollup:openVueApp并传递有效负载(如果需要)来做出反应。

而已!让我们按F5键运行扩展程序。VS Code 的一个新实例打开。

单击活动栏上添加的最后一个图标。然后单击打开按钮。图 12显示了在编辑器的 Web 视图中加载的 App.vue 组件。Sidebar.vue 组件加载在侧边栏的 Web 视图中。

在这里插入图片描述

图 12: VS Code 扩展中的 Sidebar.vue 和 App.vue 组件

Webview API 允许扩展和 HTML 内容之间的双向通信。

第 7 步

让我们添加一个命令,允许扩展从 VS Code 中向 Sidebar.vue 组件发布消息。

首先在文件中定义vscodevuerollup:sendMessage命令package.json,如下所示:

{   
    "command": "vscodevuerollup:sendMessage",   
    "title": "Send message to sidebar panel",  
    "category": "Vue Rollup"
}

然后,在extension.ts文件中注册此命令:

context.subscriptions.push(
    vscode.commands.registerCommand(
        'vscodevuerollup:sendMessage', async () => {
            if (sidebarProvider) { 
                await sidebarProvider.sendMessage();
            }
        }
    )
);

当用户触发 sendMessage 命令时,命令处理程序调用类sendMessage()上的实例函数SidebarProvider

清单 8显示了该sendMessage()函数。它通过内置vscode.window.showInputBox()函数提示用户输入消息。然后使用Webview.postMessage()内置函数将用户输入的消息发布到 Sidebar.vue 组件。

清单 8:sendMessage() 函数
public sendMessage() { 
    return vscode.window.showInputBox({
        prompt: 'Enter your message',
        placeHolder: 'Hey Sidebar!'}
    ).then(value => {   
        if (value) {
            this._view?.webview.postMessage({  
                command: 'message', 
                data: value,
            });
        }
    });
}

Sidebar.vue 组件通过注册一个事件监听器来处理从扩展接收到的消息,如下所示:

mounted() {
    window.addEventListener(
        'message', this.receiveMessage
    );
},

receiveMessage()当用户在 VS Code 中触发命令时,该函数就会运行。

您可以receiveMessage()按如下方式定义函数:

receiveMessage(event) {
    if (!event) return;

    const envelope = event.data;
    switch (envelope.command) { 
        case 'message': {  
            this.message = envelope.data;  
            break;
        }
    };
},

它验证命令是消息类型**。**然后它提取命令的有效负载并将其分配给组件在 UI 上显示的局部变量。

让我们运行扩展程序!

找到并导航到 Sidebar 内托管的 Sidebar.vue 组件。

打开命令面板,开始输入“Send message to sidebar panel” **。**VS Code 会提示您输入消息,如图 13所示。输入您选择的任何消息,然后按 Enter。

在这里插入图片描述

图 13:促进用户输入

该消息将显示在侧栏上,如图 14所示**。**

在这里插入图片描述

图 14: Sidebar.vue 组件接收来自扩展的消息。

恭喜!到目前为止,您已经完成了第三个 VS Code 扩展。

使用vscode快速搭建Vue项目步骤_vscode创建vue项目3种方法(1)
fksdskjfzxklzk的博客
05-01 1538
1.webpack打包文件体积过大?①在代码目录下创建一个文件夹,然后用VSCode打开。①输入npm create vite@latest。②输入项目名称vue-project,选择vue。⑦进入项目,运行pnpm install。③输入pnpm create vite。④进入项目,运行npm install。②点击查看打开终端,然后切换到cmd。2.如何优化webpack构建的性能。4.Vue的SPA 如何优化加载速度。③选择JavaScript。⑤选择vue,然后回车。3.移动端的性能优化。
VS Code 开发Vue扩展
淳于晗歌的博客
07-17 1485
1、Vetur —— 语法高亮、智能感知、Emmet等 2、Vue VSCode Snippets -->Vue 语法片段扩展 3、EsLint —— 语法纠错 4、JavaScript(ES6) code snippets —— ES6语法智能提示以及快速输入,除js外还支持.ts,.jsx,.tsx,.html,.vue,省去了配置其支持各种包含js代码文件的时间 5、Path Intellisense —— 自动路径补全 6、Beautify——格式化代码,值得注.
VuePack-包含HTML Intellisense和Vue.js JavaScript库的代码段。-Vue.js开发
05-27
Vue.js Pack从VS Gallery下载此扩展或获取CI版本。 包含Vue.js JavaScript li Vue.js PackHTML Intellisense和代码段从VS Gallery下载此扩展或获取CI构建。 包含HTML Intellisense和Vue.js JavaScript库的代码段。有关更改和路线图,请参阅更改日志。 功能.vue文件被映射为在HTML编辑器中打开,用于内置指令HTML Intellisense用于自定义指令和组件HTML Intellisense .vue文件的文件图标JavaScript代码段指令Intellisense Intellisense中显示了内置指令,以使其更易于使用
安装 Vue-devtools拓展程序
无理. 的博客
11-03 2666
vue-devtools是一款用于vue应用的调试的基于chrome浏览器的插件,可极大地提高我们的调试效率。可帮助我们快速的调试开发vue应用。
vs code开发前端项目常用扩展插件
qq_45643079的博客
12-08 1484
搞开发一直用的VS code,用新电脑的时候,每次都得把一些乱七八糟的插件重新安装一遍,一直也没做个总结,每次安装都搜索很久,总有一些插件会忘记。为了以后换新电脑的时候,安装插件方便点,做一个总结: 首先是vue相关的插件 使用vue进行开发的话,这几个插件是必须安装的,自动提示啥的都包括在内了。 代码相关 Eslint,懂得都懂,检查代码,可以帮你改错,提示错误啥的。而prettier是代码风格,比如,使用单引号,不用分号等等,添加这个插件可以让代码更好看,规范。这两个插件一般是两个配合使用的。 这个
vscode扩展开发
最新发布
yydshcg的博客
03-27 1186
官方文档。
VsCode Extensio 扩展开发之命令笔记
孙亖的专栏
04-23 461
VsCode Extension 扩展开发,基本是以Command命令为核心的。开发一个命令是三个地方: 1、js代码: // Display a message box to the user vscode.window.showInformationMessage('Hello Vs Code Extension!'); }); context.subscriptions.push...
调试vue.js应用的浏览器扩展 Chrome插件
12-07
Vue.js devtools:调试vue.js应用的浏览器扩展 Chrome插件
扩展Vue.js组件
qq_43067585的博客
08-26 307
您的Vue应用程序中是否有共享类似选项的组件,甚至模板标记? 使用公共选项和标记创建基本组件,然后扩展基本组件以创建子组件,这是一个好主意。这样的体系结构将帮助您在代码中应用DRY原则(不要重复您自己),这将使您的代码更具可读性,并减少错误的可能性。 Vue提供了一些功能来帮助组件继承,但是您还必须添加一些自己的独创性。 例如:调查问题 下面是Vue.js做的一个简单的调查: 你会注意到每个问题都有不同的相关输入类型: 文本输入 选择输入 Radio input
vs code vue扩展工具
xiaoshengjinbu的博客
12-11 136
Vue VSCode Snippets -快速生成代码
VS CODEvue.js基本知识一
Woolemon的博客
07-04 376
vs code 建项目布置 切换使用语言: 搜索框直接搜索该语言的英文,点击安装即可 文件目录管理: 设置颜色主题: 一些通用操作: 推荐安装的插件 Vue.js项目技术栈 Vue.js,Vue-Router,webpack,axios,Vue-cli3,Vuex,Vue组件器(Element-UI…) 技术间的联系 vue的细节分析 前端渲染(把数据和模板填到HTML标签中): 渲染方式: 原生js拼接字符串 使用前端模板引擎 使用vue特有的模板语法 vue的基本
basys:用于构建全栈Vue.js应用程序的工具箱
02-05
是用于构建Vue.js全栈应用程序的工具箱,其重点是出色的开发人员经验。 创建基于堆栈的基于的后端和单页应用程序的简便方法 通过的简单配置和直观选项 借助 , 和 ,可以使用现代JavaScript和CSS预处理编写代码,并...
nodecg-vue-ts-template:使用Vue.js和TypeScript的NodeCG捆绑软件的模板
03-18
nodecg-vue-ts-template ...我个人使用带有一些适当扩展名的Visual Studio Code (例如 ),因此请确保它在该编辑器中能正常工作。 扩展程序/浏览器文件中散布了一些示例代码,这些示例代码应有助于如何
vue2.6.10-source-code:学习vue2.x源代码
05-14
支持Vue.js Vue.js是MIT许可的开源项目,其持续的开发完全有赖于这些出色的。 如果您想加入他们,请考虑: 。 。 Patreon和OpenCollective有什么区别? 通过Patreon捐赠的资金将直接用于支持Evan You在Vue.js上的全...
vue-source-code-analyse:Vue ES6汇总流Node.js-vue source code
03-24
支持Vue.js Vue.js是MIT许可的开放源代码项目,其持续的开发完全有赖于这些出色的。 如果您想加入他们,请考虑: 。 。 Patreon和OpenCollective有什么区别? 通过Patreon捐赠的资金将直接用于支持Evan You在...
vue.js基础__ extend 扩展选项
alanbiz1314的博客
06-28 279
extend 扩展选项需要在构造器外部进行定义,并使用updated方法; 在构造器中使用 extend 方法以对象的形式调用, 方法的执行顺序为:原生的methods方法优先执行,然后是扩展的updated方法,最后执行的是原生的updated方法 差值使用{{ }}进行插入,在构造器中设置delimiters:['${','}'],则可以使用${}进行插值 代码示例如下: ...
Vue.js 组件复用和扩展
hell0_W0rld4396的博客
08-13 179
Vue.js 组件复用和扩展 查看更多 扩展组件是否必要 扩展往往通过继承基础组件来达到功能复用的目的。要知道,所有的组件扩展方法都会增加复杂性和额外代码,有时候还会增加性能消耗。经验告诉我们,组合模式优于继承。 因此,在决定扩展组件之前,最好先看看有没有其他更简单的设计模式能完成目标。 下面几种模式通常足够替代扩展组件了: props 配合模板逻辑 slot 插槽 JavaScript 工具函数 props 配合模板逻辑 最简单的方法是通过props结合模板条件渲染,来实现组件的多功能。 比如通过 typ
vs code安装扩展
weixin_44867717的博客
02-03 474
安装扩展 Vetur ,使得vue文件内容可以有代码高亮显示 和 提示 安装Vue 2 Snippets,之后可以设置代码片段,使得组件的结构内容快速显示 之后选取 vue.json 配置文件设置代码片段即可 步骤:vscode—>设置 --> user snippets ----> vue.json 在其中配置如下内容: { // Place your snippe...
使用 Vue 开发的,这 7 个 VS Code 插件万万不可错过!
粉丝们务必加入微信粉丝群
04-22 977
作者:Ahmad shaded 译者:前端小智 来源:sitepoint 有梦想,有干货,微信搜索 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。 本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试完整考点、资料以及我的系列文章。 在 VS Code 中添加好用的插件可以提高我们的开发效率。这些可以帮助我们格式化,扩充性,执行最佳实践的代码方式,自动完成一些琐碎的事情。好了,费话不多说,那我们开始吧! Vetur Vetur 支.
vscode插件开发中,如何使用 Vue.js 构建webview 扩展,给出示例
04-26
对于使用 Vue.js 构建 webview 扩展,可以按照以下步骤进行操作: 1. 首先,需要安装 Visual Studio Code 插件:`vue-web-extension`。 2. 接下来,在插件所在的项目目录下,使用以下命令进行 Vue.js 项目的初始化...

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
写文章

热门文章

  • 什么是深浅拷贝?如何实现深浅拷贝 14872
  • vscode 格式化插件以及配置 12417
  • element-ui中form表单input、select框宽度自适应 11915
  • js 实现色色的九九乘法表 9548
  • JSX 语法详解 9418

分类专栏

  • javaScript 30篇
  • vue 35篇
  • webpack 4篇
  • react 11篇
  • vue3.0 1篇
  • vscode 1篇
  • vscode扩展 1篇
  • input 1篇
  • input 输入 1篇
  • input 可以选择不能输入 1篇

最新评论

  • 用 typescript 做一个贪吃蛇小游戏

    新时代农民工Top: src 目录下面

  • 用 typescript 做一个贪吃蛇小游戏

    more_luky: index.ts文件要放在哪里?

  • JSX 语法详解

    艾加绒: 写得简洁明了,真的好,点赞了

  • 使用 Vue.js 构建 VS Code 扩展

    小不着调_ZY: 源码在哪 老哥

  • element-ui中form表单input、select框宽度自适应

    何七七KongKwan: 屏幕大小改变的时候 好像不会变诶

大家在看

  • AI笔记——语音识别 207
  • 机器学习与大数据分析的结合:为未来的智能化提供数据支持 583
  • 深度学习PyTorch基础笔记 (6) :注意力机制、Transformer 1103
  • MATLAB基础应用精讲-【数模应用】SPSSAU数据处理 34
  • 2356. 每位教师所教授的科目种类的数量

最新文章

  • 前端将当前页面或者页面中某一部分区域保存成 pdf 文件
  • react 项目中封装 websocket
  • npm 切换国内淘宝镜像源
2024年1篇
2023年3篇
2022年17篇
2021年86篇

目录

目录

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

深圳SEO优化公司张家界百度关键词包年推广公司光明百度爱采购推荐深圳网站搜索优化报价和田网络广告推广哪家好济宁建站推荐保山网站推广工具哪家好赣州seo排名推荐绍兴企业网站改版公司莱芜百搜标王多少钱福田网站优化按天计费公司漳州网络推广推荐大丰网站设计模板多少钱陇南阿里店铺托管推荐西乡网站推广工具哪家好宜宾网站搭建哪家好大浪营销型网站建设公司鹤壁seo排名报价福田关键词按天扣费黄山企业网站建设价格长治优秀网站设计价格大庆企业网站建设报价武汉百度竞价多少钱南联外贸网站制作报价常州百度seo哪家好六安网络推广价格和田百姓网标王多少钱永州网站优化软件多少钱安顺网站推广工具公司诸城网站推广公司芜湖百度网站优化排名报价歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

深圳SEO优化公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化