本文指标:手摸手教你打造一个反对内嵌网页的VS Code插件,实现Vue我的项目前端表单代码的主动生成,早日实现摸鱼自在。

成果展现

废话不多说,先看看最终的工作成绩:


看完动图是不是提神了那么一丢丢,让咱们开干吧~~

第一步/Step 1

首先,咱们须要一款开源拖拽式设计的可视化设计器,GitHub、码云一通搜寻,曾经有很多成品了,各种form-create、form-design、vue-form、form-generator等等;<br/>

其次,从上述设计器中筛选反对代码生成的,当然如果没有代码生成也能够本人实现,毕竟都开源了不是?

我这里抉择的是开源的VForm设计器:VForm GitHub
为啥咧?哈哈。。。看着眼生呗,性能上多那么一丢丢~~

第二步/Step 2

装置VS Code插件开发套件:

npm install -g yo generator-code

装置胜利后,运行yo code生成新的插件我的项目:

起个简略又好听的名字——quick-coder(撸码达人),加个简略的阐明,其余选项按需抉择即可。

来来来,看一下生成的插件我的项目:

这里只须要重点关注两个文件:extension.jspackage.json

extension.js,插件扩大点形容文件
package.json,我的项目属性、依赖包及插件配置文件

第二步工作告一段落,接下来开始第三步插件的编码实现工作。

第三步/Step 3

批改package.json,以减少插件的启动命令,能够从命令面板和左侧资源管理器启动。

"contributes": {    "commands": [{        "command": "extension.openVFormMaker",        "title": "关上VForm设计器"    }],    "menus": {        "explorer/context": [{            "command": "extension.openVFormMaker",            "group": "navigation"        }]    }},

批改extension.js的插件启用办法,仅一行:

function activate(context) {    require('./src/vform-loader')(context)}

截止到此时,咱们尚未解释整个代码生成器插件是如何工作的,但当初到了不得不说的时候了。
咱们心愿,当插件启动的时候关上一个WebView面板,WebView面板通过URL配置参数加载VForm网页,当VForm生成代码时与VS Code通过postMessage通信,VS Code负责将生成代码保留为本地文件。
实现上述需要的要害代码都在vform-loader.js文件中

这里还有两个小问题须要解答:

  1. WebView能间接加载近程网页吗?
    答案是不能,只能加载本地HTML文件。

  2. 那么问题来了?WebView怎么加载远端网页的HTML呢?
    答案也很简略,就是在本地HTML文件内嵌入iframe,iframe万能——YYDS!

解决了上述几个小case,咱们来看看整个插件的灵魂代码。

src\view\index.html

<!DOCTYPE html><html lang="zh-CN">  <head>    <meta charset="UTF-8" />    <meta      name="viewport"      content="width=device-width,initial-scale=0,maximum-scale=0,user-scalable=yes,shrink-to-fit=no"    />    <title>Quick Coder</title>  </head>  <body>    <iframe id="frame" width="100%" height="100%" frameborder="0"></iframe>    <script>      window.onload = function () {        const vscode = acquireVsCodeApi();        const cmds = {          setSrc: function (message) {            var frame = document.getElementById("frame");            frame.src = message.data.src;          },          writeFile: function (message) {            vscode.postMessage(message);          },          openUrl: function (message) {            vscode.postMessage(message);          },          setStorageItem: function (message) {            vscode.postMessage(message);          },        };        window.addEventListener("message", (event) => {          const message = event.data;          if (message && message.cmd) cmds[message.cmd](message);        });      };    </script>  </body></html>

src\vform-loader.js

const vscode = require('vscode')const fs = require('fs')const path = require('path')const open = require('open')const DB_PATH = path.join(__dirname,'./data/db.json')function getExtensionFileAbsolutePath(context, relativePath) {    return path.join(context.extensionPath, relativePath)}/** * 从某个HTML文件读取能被Webview加载的HTML内容 * @param {*} context 上下文 * @param {*} templatePath 绝对于插件根目录的html文件相对路径 */function getWebViewContent(context, templatePath) {    const resourcePath = getExtensionFileAbsolutePath(context, templatePath)    const dirPath = path.dirname(resourcePath)    let html = fs.readFileSync(resourcePath, 'utf-8')    // vscode不反对间接加载本地资源,须要替换成其专有门路格局,这里只是简略的将款式和JS的门路替换    html = html.replace(/(<link.+?href="|<script.+?src="|<img.+?src=")(.+?)"/g, (m, $1, $2) => {        return $1 + vscode.Uri.file(path.resolve(dirPath, $2)).with({ scheme: 'vscode-resource' }).toString() + '"'    })    return html}const methods = {    writeFile: function (message, vscode, dirPath) {        let { fileName, code } = message.data        let filePath = path.join(dirPath, fileName)        fs.writeFileSync(filePath, code)        vscode.window.showInformationMessage(`文件${fileName}创立胜利`)    },    openUrl: function (message, vscode, dirPath) {        open(message.data.url)    },    setStorageItem: function(message, vscode, dirPath) {        const { key, val } = message.data        const str = fs.readFileSync(DB_PATH).toString()        let json = {}        if (str) {            json = JSON.parse(str)        }        json[key] = val        fs.writeFileSync(DB_PATH, JSON.stringify(json))    },}module.exports = function (context) {    context.subscriptions.push(vscode.commands.registerCommand('extension.openVFormMaker', (uri) => {        if (uri) {            let dirPath = uri.fsPath,                stat = fs.lstatSync(dirPath)            if (stat.isFile()) dirPath = path.dirname(dirPath)            let pclintBar = vscode.window.createStatusBarItem()            pclintBar.text = `指标文件夹:${dirPath}`            pclintBar.show()            const panel = vscode.window.createWebviewPanel(                'vFormMaker',                "VForm表单设计器",                vscode.ViewColumn.One,                {                    enableScripts: true, // 启用JS,默认禁用                    retainContextWhenHidden: true, // webview被暗藏时放弃状态,防止被重置                }            )            panel.onDidChangeViewState(e => {                if (panel.visible) {                    pclintBar.show()                } else {                    pclintBar.hide()                }            })            panel.webview.html = getWebViewContent(context, 'src/view/index.html')            panel.webview.postMessage({                cmd: 'setSrc',                data: {                    src: vscode.workspace.getConfiguration().get('VFormMaker.url') + '&t=' + new Date(),                    db: JSON.parse(fs.readFileSync(DB_PATH).toString() || '{}')                }            })            panel.webview.onDidReceiveMessage(message => {                if (message.cmd && message.data) {                    let method = methods[message.cmd]                    if (method) method(message, vscode, dirPath)                } else {                    vscode.window.showInformationMessage(`没有与音讯对应的办法`)                }            }, undefined, context.subscriptions)            panel.onDidDispose(e => {                pclintBar.dispose()            })        } else {            vscode.window.showInformationMessage(`无奈获取文件夹门路`)        }    }))}

OK~灰常好,给看到这里的大佬们鼓掌,行将看到插件运行成果!!

最初批改package.json文件的contributes属性,减少一个URL参数配置,竣工!!

"contributes": {    "configuration": {        "type": "object",        "title": "VForm设计器配置",        "properties": {            "VFormMaker.url": {                "type": "string",                "default": "http://120.92.142.115/?vscode=1",                "description": "VForm设计器近程URL"            }        }    },    

连忙在VS Code中按下F5键调试插件,观赏下本人的工作成绩~~~

第四步/打包公布

装置打包工具vsce

npm install -g vsce

在插件我的项目运行vsce package命令,即可生成.vsix文件(会提醒批改README.md文件,减少插件的简介及应用阐明)

vsce package

注册VS marketplace账号,上传.vsix文件,凋谢给所有VS Code用户应用:
VS marketplace

后话/Finally

简略回顾一下,咱们通过WebView嵌入VForm的远端网页,实现了常见的Vue表单前端代码生成(反对Vue2也反对Vue3哦)的预期需要,因为VForm自身是一个开源我的项目,且有良好的扩展性,有心的大佬们能够自在扩大VForm的性能,进一步实现el-table等更多组件的前端代码主动生成,早日实现摸鱼自在

最初的最初

感觉本人写插件有点小累的大佬们,能够间接在VS Code扩大中搜寻vform-makervformAdmin

最初,再附上寰球最大同性交友网的VForm链接:GitHub
国内同步码云:Gitee