VSCode 微信小程序扩展开发
写在前面
为什么要开发这个扩展呢,是因为微信开发者工具自身不支持页面引入组件的跳转,人工根据引入组件路径查看对应代码的方式,效率偏低。就形如这样的json文件,引入了多个组件,比如要查看
先看看效果,功能展示如下:按下ctrl+鼠标左键,就能实现下面5种跳转功能。
1. app.json中的分包页面跳转
2. js文件中的wx.navigateTo,wx.redirectTo,wx.reLaunch跳转
3. wxml文件中微信标签bindTap属性绑定的方法跳转
4. wxml文件中微信wxs标签src路径跳转
5. js文件中的ajax url跳转
这个插件不仅可以在VSCode编辑器中使用,也可以在微信开发者工具中使用,效果一模一样。在微信开发者工具中的使用方法如下:
1. 微信开发者工具工具栏--编辑-->打开编辑器扩展目录-将VSCode的扩展复制进去,假如你已经安装了某个扩展,这个扩展一般在C:\Users\xxx用户名\.vscode\extensions路径下。
2. 微信开发者工具工具栏--编辑-->管理编辑器扩展, 将VSCode扩展ID添加到扩展列表。扩展ID的查找方式见下图。
3. 重启微信开发者工具。
如何开发出这样的VSCode 微信小程序扩展?
step1 安装vscode扩展开发脚手架yo,generator-code和vsce
- npm install -g cnpm --registry=https://registry.npm.taobao.org
- cnpm install -g yo generator-code vsce
step2 用yo初始化扩展项目
- yo code
- ? ==========================================================================
- We're constantly looking for ways to make yo better!
- May we anonymously report usage statistics to improve the tool over time?
- More info: https://github.com/yeoman/insight & http://yeoman.io
- ========================================================================== No
- _-----_ ╭──────────────────────────╮
- | | │ Welcome to the Visual │
- |--(o)--| │ Studio Code Extension │
- `---------´ │ generator! │
- ( _´U`_ ) ╰──────────────────────────╯
- /___A___\ /
- | ~ |
- __'.___.'__
- ´ ` |° ´ Y `
- ? What type of extension do you want to create? New Extension (JavaScript)
- ? What's the name of your extension? wx-minipro-helper
- ? What's the identifier of your extension? wx-minipro-helper
- ? What's the description of your extension? 微信小程序开发助手,目前只实现了定义跳转功能
- ? Enable JavaScript type checking in 'jsconfig.json'? Yes
- ? Initialize a git repository? Yes
- ? Which package manager to use? yarn
step3 修改package.json文件
- {
- "name": "wx-minipro-helper",
- "displayName": "wx-minipro-helper",
- "description": "第一版本只实现了微信开发者工具不支持的 1.app.json内的页面路径跳转; 2. 页面下的json文件中引入的组件路径跳转; 3.页面文件下的js文件中的引入外部工具库跳转; 4.wx.navigateTo,wx.redirectTo,wx.reLaunch跳转; 5.wxml标签中绑定的方法跳转; 后续会添加自动补全,悬浮提示功能",
- "version": "0.0.3",
- "keywords": [ // 添加搜索关键字
- "wx",
- "minipro",
- "helper"
- ],
- "publisher": "wph", // 添加发布者
- "icon": "src/images/icon.png", // 添加图标至少是128*128
- "main": "src/extension", // 修改入口文件
- "engines": {
- "vscode": "^1.5.0" // 依赖的vscode版本
- },
- "categories": [
- "Other"
- ],
- "activationEvents": [ //启动时触发的命令
- "*"
- ],
- "contributes": {
- "commands": [
- {
- "command": "extension.wx-minipro-helper",
- "title": "wx-minipro-helper"
- }
- ]
- },
- "scripts": {
- "lint": "eslint .",
- "pretest": "yarn run lint",
- "test": "node ./test/runTest.js"
- },
- "devDependencies": {
- "@types/glob": "^7.1.3",
- "@types/mocha": "^8.0.0",
- "@types/node": "^12.11.7",
- "@types/vscode": "^1.5.0",
- "eslint": "^7.9.0",
- "fs": "^0.0.1-security",
- "glob": "^7.1.6",
- "mocha": "^8.1.3",
- "os": "^0.1.1",
- "path": "^0.12.7",
- "typescript": "^4.0.2",
- "vscode": "^1.1.37",
- "vscode-test": "^1.4.0"
- },
- "bugs": {
- "url": "https://github.com/wph/wx-minipro-helper/issues"
- },
- "repository": {
- "type": "gitee",
- "url": "https://gitee.com/getbetter/wx-minipro-helper.git"
- },
- "homepage": "https://gitee.com/getbetter/wx-minipro-helper/blob/master/README.md"
- }
step4 写扩展的功能,扩展入口extension.js内容如下
- const vscode = require('vscode');
- /**
- * 插件被激活时触发,所有代码总入口
- * @param {*} context 插件上下文
- */
- exports.activate = function (context) {
- console.log('扩展“wx-minipro-helper”已被激活!');
- require('./jump-to-definition')(context); // 跳转到定义
- };
- /**
- * 插件被释放时触发
- */
- exports.deactivate = function () {
- console.log('扩展“wx-minipro-helper”已被释放!');
- };
extension.js引入的jump-to-definition文件,是跳转功能的具体实现,我为这部分代码写了详尽的注释, 基本原理就是VSCode提供了光标点击事件的一些属性,如点击了什么文件,点击了那一行,点击了文件中的什么文本,根据这些信息可以拿到跳转路径,然后调用vscode提供的跳转api,就能实现定义跳转功能
- const vscode = require('vscode');
- const path = require('path');
- const fs = require('fs');
- const util = require('./utils');
- /**
- * 查找文件定义的provider,匹配到了就return一个location,否则不做处理
- * @param {*} document
- * @param {*} position
- * @param {*} token
- */
- function provideDefinition(document, position, token) {
- // 获取工作目录
- const projectPath = util.getProjectPath(document);
- // 获取光标所在行的文档路径
- const { fileName } = document;
- // 获取光标所在行的文档夹路径
- const workDir = path.dirname(fileName);
- // 获取光标所在位置的双引号范围内的文本路径,并去除空格,引号,逗号
- let textPath = document.getText(document.getWordRangeAtPosition(position, /[\'\"](.*?)[\'\"]/g));
- textPath = textPath.replace(/,|\s|\'|\"/gi, '');
- // 获取光标所在行的信息
- const line = document.lineAt(position);
- // 如果跳转行存在import字样,屏蔽掉这个工具的跳转功能,因为会与开发编辑工具的跳转功能冲突
- if (line.text.includes('import')) return null;
- // wxml文件中微信标签上bindTap绑定方法跳转, 因为在wxml文件中,获取到的光标所在处的文本是整个文档,所以要修改
- // 光标所在行截取出来的字符串,没有.或/等路径符
- if (/\.wxml$/.test(fileName) && !/[\/\.]/.test(textPath)) {
- // const textLine = document.lineAt(position);
- const wordRange = document.getWordRangeAtPosition(position, /[\w|\-]+\b/);
- // const tag = (textLine.text.match(/(?<=<\/?)[\w|\-]+\b/) || [])[0];
- const word = document.getText(wordRange);
- // console.log(wordRange, word, tag, textPath);
- // 在wxml文件对应的js文件中,查找方法名所在的行号和列数
- const filePath = fileName.replace(/\.wxml$/, '.js');
- const pos = util.findStrInFile({ filePath, str: word});
- const { row, col } = pos;
- // 判断是否找到
- if (row != 0 && col != 0) {
- return new vscode.Location(vscode.Uri.file(filePath), new vscode.Position(row, col));
- }
- return [];
- }
- // 项目定制需求--ajax url跳转,不通用
- // 检测光标所在行的字符串中是否有ajax('')字样
- const ajaxReg1 = new RegExp(`ajax\\(\\s*.*('|")${textPath}('|"),?`, 'gm');
- // 检测光标所在行的字符串中是否有yield call(ajax字样
- const ajaxReg2 = new RegExp(`yield call\\(ajax\\, ?('|")${textPath}('|"), ?`, 'gm');
- const json = document.getText();
- if (ajaxReg1.test(json) || ajaxReg2.test(json)) {
- // webapp项目
- const destPath1 = `${projectPath}/src/config/api.js`;
- // 小程序项目
- const destPath2 = `${projectPath}/config/api-config.js`;
- let destPath = '';
- if (fs.existsSync(destPath1)) {
- destPath = destPath1;
- } else if (fs.existsSync(destPath2)) {
- destPath = destPath2;
- }
- // 文件存在
- if (fs.existsSync(destPath)) {
- try {
- // 查找关键字在文件中的行号和列号
- const pos = util.findStrInFile({ filePath:destPath, str: textPath });
- const { row, col } = pos;
- return new vscode.Location(vscode.Uri.file(destPath), new vscode.Position(row, col));
- } catch (error) {
- vscode.window.showErrorMessage('%c error:', 'color: #0e93e0;background: #aaefe5;', JSON.stringify(error));
- return [];
- }
- }
- return []
- }
- // 微信小程序app.json跳转逻辑比较特殊,存在分包路径,如果是分包路径,要拼接子包root路径部分
- if (fileName.includes('app.json')) {
- const json = JSON.parse(document.getText());
- // 分包路径判断
- let isSubPath = json.subpackages.some((item) => {
- if (item.pages.includes(textPath)) {
- // 如果是分包路径,则要拼接分包的root路径部分
- textPath = `/${item.root}/${textPath}`;
- return true;
- }
- return false;
- });
- // 如果是正常页面路径,要在页面路径前面加绝对路径符号/
- if (!isSubPath) {
- textPath = `/${textPath}`;
- }
- }
- // 如果没有文件后缀,说明是json,或者js,jsx文件中的navigateTo跳转,默认跳转到对应页面的wxml文件
- const reg = /\.\w+$/;
- let isNoSuffix = !reg.exec(textPath);
- // 没有文件后缀,添加默认的跳转文件类型
- if (isNoSuffix) {
- textPath = `${textPath}.wxml`;
- }
- let jumpPath;
- if (textPath.startsWith('/')) {
- // 为绝对路径时-直接拼接工程路径+截取的路径字符串
- jumpPath = path.join(projectPath, textPath);
- } else {
- // 为相对路径时-转换成绝对路径
- jumpPath = path.resolve(workDir, textPath);
- }
- console.log('====== 进入 provideDefinition 方法 ======');
- console.log('projectPath=%s ', projectPath); // 当前工程目录
- console.log('document:', document); // 文档对象
- console.log('position:', position); // 位置
- // console.log('token=%o', token); // 分词
- console.log('line:', line); // 当前光标所在行
- console.log('fileName=%s ', fileName); // 当前文件名
- console.log('workDir=%s', workDir); // 当前文件所在目录
- console.log('textPath=%s', textPath); // 跳转短路径
- console.log('jumpPath=%s ', jumpPath); // 跳转路径
- // 路径不存在则不跳转
- if (!jumpPath || !fs.existsSync(jumpPath)) {
- return null;
- } else {
- return new vscode.Location(vscode.Uri.file(jumpPath), new vscode.Position(0, 0));
- }
- }
- module.exports = function (context) {
- // 注册如何实现跳转到定义,第一个参数表示仅对js,jsx,ts,tsx,json,wxml文件生效
- context.subscriptions.push(
- vscode.languages.registerDefinitionProvider(
- { pattern: '**/*.{ts,js,jsx,tsx,json,wxml}' },
- {
- provideDefinition,
- }
- )
- );
- };
step5 调试VSCode 扩展,按下F5, VSCode会启动一个新的窗口,在新窗口调试功能,在旧窗口看调试日志,下图的第一张图是旧窗口,第二张图是新窗口
step6 扩展开发完成后,就可以准备发布了。首先你需要注册一个发布账号 marketplace.visualstudio.com/manage/,填写各种注册信息,注册完之后,安装官方发布脚本,然后执行打包脚本命令
- E:\study\wx-minipro-helper>vsce package
- INFO Detected presense of yarn.lock. Using 'yarn' instead of 'npm' (to override this pass '--no-yarn' on the command line).
- DONE Packaged: E:\study\wx-minipro-helper\wx-minipro-helper-0.0.3.vsix (10 files, 23.06KB)
step7 在vscode应用市场发布扩展 ,刚才生成的扩展wx-minipro-helper-0.0.3.vsix
扩展的更新方法
避坑指南
1. VSCode 扩展 的js文件,只要有一处报错,调试控制台就没有任何日志输出,不好排查错误。新手这个时候很茫然,惊慌失措。不知道哪里出了问题。看了这篇文章之后,你要淡定一些。
2. package.json中的vscode版本很重要,不能太高,我用yo code生成的初始项目,vscode的版本配置是 "vscode": "^1.51.0",结果我发现这个扩展只能在VSCode编辑器中使用,不能在微信开发者工具中使用,
我猜测可能是微信开发者工具只支持vscode工具包的低级版本。我把vscode的版本改成下面的配置后,在微信开发者工具中也可以使用了。
- "engines": {
- "vscode": "^1.5.0" // 依赖的vscode版本
- },
3.在不同的文件类型中,document.getText(document.getWordRangeAtPosition(position)获取到的光标所在处的字符串不一样,在json文件中,能拿到双引号之间的全部内容,在js,jsx,ts,tsx,wxml文件中,只能拿到光标所在处的哪个单词,所以要用正则表达式,取出跳转路径。
4.安装的同类插件太多了,插件之间会打架,出现如下这种情况,不进行跳转,处理方法就是修改下载到本地的插件源代码,屏蔽掉自己插件或别人插件的同类功能。
最后
本文实现的微信小程序扩展插件代码托管在码云, 欢迎下载
这个扩展已经发布到vscode 应用扩展市场,输入wx-minipro-helper就可以搜到
参考文章
[1] VSCode 插件开发全攻略
[2] 如何在 10 分钟内完成一款 vscode 扩展开发
VSCode 微信小程序扩展开发的更多相关文章
- VSCode 微信小程序 开发环境配置 详细教程
本博客已暂停更新,需要请转新博客http://www.whbwiki.com/231.html 配置 VsCode 微信小程序开发环境并非不用官方的 微信小程序开发者工具 ,而是两者配合适用,可以极大 ...
- 微信小程序开发(一)开发工具推荐VSCode
虽然微信小程序官方开发工具非常优秀,但用的时间久了,会发现一些问题,比如代码编辑区小,自定义能力差,不支持插件,有时还会出现莫名其妙的bug,最不能忍的是编辑器代码提示功能不健全,这对于新手来说,很不 ...
- 微信小程序开发工具测评
1月9日微信小程序正式上线.很多企业都希望能在这个.但是在技术开发的问题上,却不知道该如何下手.经过一些程序员不辞辛苦连夜测试,终于从十余款工具呕心沥血筛选出四款比较靠谱实用的微信小程序开发工具.接下 ...
- 微信小程序开发学习资料
作者:初雪链接:https://www.zhihu.com/question/50907897/answer/128494332来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明 ...
- 微信小程序开发及相关设置小结
今年过年,主要看了<奇葩说>和<电锯惊魂>,很不错,好东西的确需要留出足够的时间来看,匆匆忙忙走马观花是对作者的不尊重.除此之外,就是研究了一下微信小程序开发,先说对小程序的看 ...
- 【微信】2.微信小程序开发--官方开发工具使用说明
承接第一篇 =============================================== 关于微信小程序开发使用IDE,曾经自己动摇过. 到底是采用 微信官方小程序开发工具 WebS ...
- 微信小程序开发-入门到熟练(wepy-初级篇)
Title:最近做完了项目,review代码的同时,就想写一篇详细的小程序开发经历,记录自己的项目从0到1的过程 Desc : 小程序从0到1,从小白到完成项目,你需要这样做: step1: 基础知识 ...
- 5款微信小程序开发工具使用报告,微信官方开发工具还有待提升
微信小程序已经内测有一段时间了,笔者本着好奇加学习的心态写了几个小demo,虽然在MINA框架上并没有遇到太多的坑,但官方开发工具实在不敢恭维. api提示不全,要一个个查api啊,写代码超级慢啊 很 ...
- 微信小程序开发心得
微信小程序也已出来有一段时间了,最近写了几款微信小程序项目,今天来说说感受. 首先开发一款微信小程序,最主要的就是针对于公司来运营的,因为,在申请appid(微信小程序ID号)时候,需要填写相关的公司 ...
随机推荐
- K8S(14)监控实战-grafana出图_alert告警
k8s监控实战-grafana出图_alert告警 目录 k8s监控实战-grafana出图_alert告警 1 使用炫酷的grafana出图 1.1 部署grafana 1.1.1 准备镜像 1.1 ...
- codeforces 10C Digital Root(非原创)
Not long ago Billy came across such a problem, where there were given three natural numbers A, B and ...
- range()函数的使用、while循环、for-in循环等
一.range()函数 用于直接生成一个整数序列 创建range对象的三种方式: (1)range(stop) 创建一个(0,stop)之间的整数序列,步长为1 (2)range(start,s ...
- LeetCode 最大收益的分配工作
LeetCode 最大收益的分配工作 工作安排 现在有n位工程师和6项工作(编号为0至5),现在给出每个人能够胜任的工作序号表(用一个字符串表示,比如:045,表示某位工程师能够胜任0号,4号,5号工 ...
- OTA development
OTA development OTA update OTA Over the Air / 无线下载 https://en.wikipedia.org/wiki/Over-the-air_progra ...
- javascript nested object merge
javascript nested object merge deep copy Object reference type function namespace(oNamespace, sPacka ...
- javascript change array length methods
javascript change array length methods Array 改变数组长度的方法 push, pop shift, unshift, splice, fill, 不改变数组 ...
- bash shell cli tools
bash shell cli tools before # create files $ mkdir app-component $ cd app-component $ touch index.ht ...
- Union international INC评德意志联邦投入十亿欧元重启文化娱乐产业
当地时间6月4日,德国联邦政府宣布了一项名为"重启文化"(Neustart Kultur)的计划,将投入总计10亿欧元,用以支持德国文化及创意产业的恢复和重建. Union int ...
- ubuntu ARM换国内源和国内源安装ROS
ubuntu arm换国内源: https://www.cnblogs.com/yongy1030/p/10315569.html 国内源安装ROS: https://blog.csdn.net/ch ...