VSCode插件Path-Autocomplete高级技巧

曾经介绍过Path Autocomplete是一款非常不错的VSCode插件。当然出了最基本的路径补全提示,还有些高级技巧和使用中可能遇到的小问题,在此和大家分享下。 映射目录当你项目中的Webpack使用了resolve.alias,webpack.config.js配置如下: module.exports = { //... resolve: { alias: { Utilities: path.resolve(__dirname, 'src/utilities/'), Templates: path.resolve(__dirname, 'src/templates/') } }};那么项目之前引入的一个文件的方法假设是: import Utility from '../../utilities/utility';现在就可以写成: import Utility from 'Utilities/utility';问题来了,当你输入Utilities/的时候,编辑器根本不知道这里面有什么文件,无法实现补全提示。 这时候,只需要在这个项目添加一个插件的配置就可以了,配置如下: { "path-autocomplete.pathMappings": { "Utilities": "${folder}/src/utilities/", }}${folder}表示项目根目录,如果你的项目和示例略有不同,请根据具体情况修改。这样是不是很方便啊,同理很多脚手架或框架(比如Nuxt.js)自带了这种类似的依赖关系,都是可以通过插件的pathMappings设置来更好的写代码的。 该功能示例在官方文档Options - pathMappings,也有,可以参考。出现重复文件和目录补全提示比如,你可能会遇到路径补全提示中出现重复的目录名称或者是文件,如下图: 那我也是尝试关闭VSCode自带的补全功能结果没找到。后来仔细阅读了插件文档,google相关信息,总结了下: 设置插件选项该插件提供了一个选项path-autocomplete.ignoredFilesPatter,你可以通过添加一行设置如下: "path-autocomplete.ignoredFilesPattern": "**/*.{js,ts,scss,css}"参阅:Path Autocomplete Tips 意思是匹配到所有的js、scss、css、ts文件时,path-autocomplete将被忽略。 设置VSCode内置选项在现有版本的VSCode上,是有两个选项关闭js、ts的路径提示的,我们可以通过关闭它们,达到目的: "javascript.suggest.paths": false,"typescript.suggest.paths": false,这样的话也能解决重复提示的问题,当然缺点是,其他文件类型就无法解决了。 相关阅读: Folders are duplicated on sass import statementmultiple suggesion in js files失效总的来说,推荐使用第一种设置插件选项来解决这个问题。 快速跟踪文件抱歉,理论上来说这个是VSCode内置的取代该插件的方案,但是我总是发现不太好用。 理论上,进行了jsconfig.json配置,详细可阅读官方说明,也可以达到映射目录的能力,并且,根据插件内的这段Configure VSCode to recognize path aliases描述来看,他是可以解决文件关联打开的,但是我反复测试了好久,都无法正常实现。原因不明,有兴趣的朋友也可以试试这个哦~ ...

October 17, 2019 · 1 min · jiezi

我已经离不开idea了

为什么选择ideaidea是jetbrain公司开发的一款付费的java编辑器,我之前是用eclipse开发的,自从用了idea后,就完全离不开它了。主要原因是除了idea自身强大的功能以外,还有许多的插件。接下来我主要介绍几款我觉得好用的插件。 外观power-model II写起代码火焰沸腾的感觉,一个字:爽。不过貌似会造成idea卡顿。需要设置idea的内存 backgroundImagePlus可以设置idea的背景图片,这个插件用来装逼还可以。 nyan progress bar装逼神器,进度条变成ketty 规范sonarlint根据sonarqube的要求来编写干净的代码。 pmd同样是一款规范代码的插件,使用效果一般,公司要求用这个插件,不通过就不能合代码。图片暂无 findbugs神器不解释,帮我解决了一些明显的bug,比如空指针风险。。 checkstyle也是一款代码规范的插件,唯一的特点是可以上传自定义的代码规范。 Alibaba Java Coding Guidelines按照阿里的规约来约束代码风格。 效率lombok有了这个插件,就再也不用显式地声明不限于setter和getter方法了。 generateallsetter一键调用类的全部setter方法,写单元测试造数据神器,不过我觉得lombok的建造者模式也很好用。 Free Mybatis plugin从mapper接口的方法直接跳转到对应的xml文件中的方法 MyBatisCodeHelperPro有点mybatis generator的味道,但是使用更简单,图形化界面操作 CodeGlance当你的类上千行的时候,在你往下拖拽找对象的时候,是不是感觉挺累的,有个这个插件,可以查看缩略图一样,快速切换到自己需要去的地方,飞翔的感觉。 restfultoolkitJava WEB开发必备,再也不用全局搜索RequestMapping了。 GenerateSerialVersionUID自动生成序列化ID。 translation翻译插件,选中然后ctrl+shift+y,最新版本还有单词本功能,可以把翻译的单词标记到单词本中。 智能编程aixcoder根据你的编码,不断学习的插件,代码写的越多,他越懂你,没网就gg。https://www.aixcoder.com/#/

October 6, 2019 · 1 min · jiezi

IDEA-常用插件

帮助 JAVA 开发者提升开发效率的插件工具插件名称功能描述备注lombok注解方式实现 Setter 和 Getter 等方法可以大量减少模板代码的编写工作,代码更整洁backgroundimage plus设置IDEA 的背景图片 CodeGlance相当于当前代码文件的缩略图,可以快速移动到代码块IDEA 代码界面右侧的缩略预览Idea restartIDEA 的重启功能因 IDEA 默认未自带重启功能,使用该插件可实现mybatis log pluginMybatis 的日志插件,可在 IDEA 控制台看到完整可执行的 Sql 语句 translation翻译插件 markdown supportmarkdown 文件支持可以打开 markdown 文件并以 markdown 的语法渲览文档free mybatis pluginMybatis 的插件,可以在interface 和 sql 的 xml 文件间跳转 maven helpermaven 依赖包的可视化展示对于 maven 项目的依赖包的处理很有帮助gson format将 JSON 转为 java 类可以直接根据 JSON 数据定义出 java 类及其 fieldgrep console控制台日志展示不同级别的日志可以以不同的颜色展示Material ThemeIDEA 的主题插件,可更换 IDEA 的展示风格可选主题比较多,个人比较喜欢

May 22, 2019 · 1 min · jiezi

Vuejs-构建你的第一个包并在NPM上发布

本文我们将学习如何制作一个vue插件,并将其分发到npm上,能够让其他人安装使用.插件大大地提高了开发者的开发效率。我们的大多数项目都依赖于它们,因为它们能够以极快的速度发布新功能。 正如官方Vue.js文档中所述,插件的范围没有限制。通常我们想实现的功能有下面5种: 添加全局方法或者属性 (如: vue-custom-element)添加全局资源:指令/过滤器/过渡等 (如:vue-touch)通过全局 mixin 方法添加一些组件选项 (如:vue-router)添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现 (如:vue-axios)一个库,提供自己的 API,同时提供上面提到的一个或多个功能(如:vue-router)OK,现在你了解了vue插件是什么了,以及它可以满足哪些需求! 如何在vue项目中使用插件通过npm install或yarn add安装插件后,你需要在main.js文件中导入它并调用Vue.use()全局方法。 注意:在new Vue() 前,必须先实例化所有插件.import Vue from "vue";import MyPlugin from "myplugin";Vue.use(MyPlugin);new Vue({// [...]})如果插件包支持cdn方式引用的话,也可以通过以下方式引用: <script src="https://cdn.xxx.cn/npm/myplugin@latest/dist/myplugin.min.js"></script>另外,在你调用Vue.use()时,想对插件做一些自定义配置,你可以这么做: Vue.use(MyPlugin, { option1: false, option2: true})举个例子,比如在引入热门的Element UI库时,它支持传入一个全局配置对象 import Element from 'element-ui';import 'element-ui/lib/theme-chalk/index.css';Vue.use(Element, { // size 用于改变组件的默认尺寸,zIndex 设置弹框的初始 z-index(默认值:2000) size: 'small', zIndex: 3000});现在让我们进入正题!开始构建你的第一个vue插件???? 来制作一个酷炫的按钮组件作为一个有追求的前端,相信你们在公司开发项目时,肯定会想过,"要是公司有属于自己的一套UI组件库,那肯定很棒!"。如果你有这个想法,那你认真看完这篇文章后,将会给你带来很多灵感和启发。 步骤 1:初始化插件目录结构先创建一个空的项目文件夹,名字随意取,然后初始化生成package.json文件(文件的内容后面会介绍) $ mkdir ku-button && cd ku-button$ npm init# 上面这个命令会提示一些问题,一直回车就行,然后最后会创建一个package.json文件然后在项目根目录中创建一个src文件夹,里面新建一个KuButton.vue组件,这里你甚至可以通过vue的vue serve和vue build命令行来对单个*.vue文件进行快速原型开发,不过前提需要先额外安装一个全局的扩展 ...

April 30, 2019 · 3 min · jiezi

手写一个webpack插件

本文示例源代码请戳github博客,建议大家动手敲敲代码。webpack本质上是一种事件流的机制,它的工作流程就是将各个插件串联起来,而实现这一切的核心就是Tapable,webpack中最核心的负责编译的Compiler和负责创建bundles的Compilation都是Tapable的实例。Tapable暴露出挂载plugin的方法,使我们能 将plugin控制在webapack事件流上运行(如下图)。 Tabable是什么?tapable库暴露了很多Hook(钩子)类,为插件提供挂载的钩子。 const { SyncHook, SyncBailHook, SyncWaterfallHook, SyncLoopHook, AsyncParallelHook, AsyncParallelBailHook, AsyncSeriesHook, AsyncSeriesBailHook, AsyncSeriesWaterfallHook } = require("tapable"); Tabable 用法 1.new Hook 新建钩子 tapable 暴露出来的都是类方法,new 一个类方法获得我们需要的钩子。class 接受数组参数options,非必传。类方法会根据传参,接受同样数量的参数。const hook1 = new SyncHook(["arg1", "arg2", "arg3"]);2.使用 tap/tapAsync/tapPromise 绑定钩子tapable提供了同步&异步绑定钩子的方法,并且他们都有绑定事件和执行事件对应的方法。 -Async*Sync*绑定tapAsync/tapPromise/taptap执行callAsync/promisecall3.call/callAsync 执行绑定事件 const hook1 = new SyncHook(["arg1", "arg2", "arg3"]);//绑定事件到webapck事件流hook1.tap('hook1', (arg1, arg2, arg3) => console.log(arg1, arg2, arg3)) //1,2,3//执行绑定的事件hook1.call(1,2,3)举个例子 定义一个Car方法,在内部hooks上新建钩子。分别是同步钩子 accelerate(accelerate接受一个参数)、break、异步钩子calculateRoutes使用钩子对应的绑定和执行方法calculateRoutes使用tapPromise可以返回一个promise对象。//引入tapableconst { SyncHook, AsyncParallelHook } = require('tapable');//创建类class Car { constructor() { this.hooks = { accelerate: new SyncHook(["newSpeed"]), break: new SyncHook(), calculateRoutes: new AsyncParallelHook(["source", "target", "routesList"]) }; }}const myCar = new Car();//绑定同步钩子myCar.hooks.break.tap("WarningLampPlugin", () => console.log('WarningLampPlugin'));//绑定同步钩子 并传参myCar.hooks.accelerate.tap("LoggerPlugin", newSpeed => console.log(`Accelerating to ${newSpeed}`));//绑定一个异步Promise钩子myCar.hooks.calculateRoutes.tapPromise("calculateRoutes tapPromise", (source, target, routesList, callback) => { // return a promise return new Promise((resolve,reject)=>{ setTimeout(()=>{ console.log(`tapPromise to ${source} ${target} ${routesList}`) resolve(); },1000) })});//执行同步钩子myCar.hooks.break.call();myCar.hooks.accelerate.call('hello');console.time('cost');//执行异步钩子myCar.hooks.calculateRoutes.promise('i', 'love', 'tapable').then(() => { console.timeEnd('cost');}, err => { console.error(err); console.timeEnd('cost');})运行结果 ...

April 28, 2019 · 4 min · jiezi

webpack插件 - css主题颜色提取-主题切换

css-color-extract-pluginInstallnpm install css-color-extract-pluginyarn add css-color-extract-plugin该插件主要用于提取主题颜色提取到的css数据会挂载到window下通过颜色替换再插入到<style>,可达到动态修改主题的目的Usage// webpack.config.jsconst CssColorExtractPlugin = require(‘css-color-extract-plugin’).default;const PRIMARY_COLOR = ‘#1890ff’;module.exports = { … module: { rules: [ { test: /.css$/, exclude: ‘/.module.css$/’, use: [ “style-loader”, “css-loader”, { loader: CssColorExtractPlugin.loader, options: { colors: [ PRIMARY_COLOR ] } }, ] }, { test: /.module.css$/, use: [ “style-loader”, { loader: “css-loader”, options: { modules: true, localIdentName: ‘[path][name][local]’, } }, { loader: CssColorExtractPlugin.loader, options: { colors: [ PRIMARY_COLOR ], modules: true, localIdentName: ‘[path][name][local]’, } }, ] } ] } … plugins: [ … new CssColorExtractPlugin({ fileName: ’theme’ }), ]};编译后会在html中插入theme.js,其内容类似以下window.CSS_EXTRACT_COLOR_PLUGIN = [ {“source”:".src-App-module__example { background: #1890ff;}",“fileName”:“App.module.scss”,“matchColors”:["#1890ff"]}, {“source”:".src-Header-module__example { color: #1890ff;}",“fileName”:“Header.module.scss”,“matchColors”:["#1890ff"]}];var styles = document.createElement(‘style’);styles.innerHTML = window.CSS_EXTRACT_COLOR_PLUGIN.map((item) => item.source).join(’’);document.body.appendChild(styles);接着只要使用简单的正则即可替换主题色import React, { Component } from ‘react’;import styles from ‘./App.module.scss’;import { SketchPicker } from ‘react-color’;function replaceColor(source, color, replaceColor) { return source.replace(new RegExp((:.*?\\s*)(${color})(\\b.*?)(?=}), ‘mig’), (group) => { return group.replace(new RegExp(${color}, ‘mig’), replaceColor); });}const PRIMARY_COLOR = ‘#1890ff’;class App extends Component { async setColor(color) { const styleData = window.CSS_EXTRACT_COLOR_PLUGIN || []; const cssText = styleData.map((item) => item.source).join(’’); const styleText = replaceColor(cssText, PRIMARY_COLOR, color); const style = document.createElement(‘style’); style.innerHTML = styleText; document.body.appendChild(style); } render() { return ( <div className={styles[’example’]}> <SketchPicker onChangeComplete={(colorResult) => this.setColor(colorResult.hex)} /> </div> ); }}export default App;loader Options { colors: string[]; // 匹配的颜色数组,如果出现颜色层次错误覆盖的情况,需要选上被覆盖的颜色,可通过该选项在不同的文件提取不同的颜色 only?: boolean = true; // 仅提取选中颜色规则,否则会将整个文件提取进去 modules?: boolean = false; localIdentName?: string = ‘’; }plugin Options { fileName?: string; // 提取颜色的文件名,不提供则直接嵌在 script标签中 variableName?: string = ‘CSS_EXTRACT_COLOR_PLUGIN’; // 挂载到window的变量名, 默认 CSS_EXTRACT_COLOR_PLUGIN }example一个更复杂的例子-RyanCMS内容管理系统 ...

April 5, 2019 · 2 min · jiezi

开发一个psotcss插件

git地址:开发一个psotcss插件节点类型postcss会将我们的css生成ast,然后会去遍历它,在遍历的过程中会传给我们一些不同类型的节点对象,我们主要需要了解的几个类型:css ast主要有3种父类型AtRule: @xxx的这种类型,如@screenComment: 注释Rule: 普通的css规则还有几个个比较重要的子类型:decl: 指的是每条具体的css规则rule:作用于某个选择器上的css规则集合这是test的地方的,不熟悉ast的可以先了解一下:css ast结构postCss操作方法postCss为我们提供了一些方便的操作方法遍历walk: 遍历所有节点信息,无论是atRule、rule、comment的父类型,还是rule、 decl的子类型walkAtRules:遍历所有的atRulewalkComments:遍历所有的注释节点walkDecls:遍历所以的属性walkRules:遍历所有的css代码块root.walkDecls(decl => { decl.prop = decl.prop.split(’’).reverse().join(’’);});postcss在遍历的过程中,会将当前遍历的对象的cell传给回调函数,该参数是对应的rule,decl或者comment等Constructor等构造函数的实例,根据遍历的节点不同,该实例可能会有如下属性:nodes: css规则的节点信息集合decl: 每条css规则的节点信息prop: 样式名,如widthvalue: 样式值, 如10pxtype: 类型source: 包括start和end的位置信息,start和end里都有line和* column表示行和列selector: type为rule时的选择器name: type为atRule时@紧接rule名,譬如@import ‘xxx.css’中的importparams: type为atRule时@紧接rule名后的值,譬如@import ‘xxx.css’中的xxx.csstext: type为comment时的注释内容同样还有继承的一些方法,给我操作css的, 比如操作每条具体css属性的declaration:afterbeforecleanRawsclonecloneAftercloneBeforeerrornextprevrawremovereplaceWithroottoStringwarnpostcss pluginpostcss插件如同babel插件一样,有固定的格式export default postcss.plugin(‘postcss-plugin-name’, function (opts) { opts = opts || {}; return function (root, result) { // 处理逻辑 };});注册个插件名,并获取插件配置参数opts返回值是个函数,这个函数主体是你的处理逻辑,有2个参数,一个是root,css ast的根节点。另一个是result,返回结果对象,譬如result.css,获得处理结果的css字符串,result.message包含组件里创建的warnings和自定义信息,result.warn()创造一个warning实例并将其加入到result.message中,result.warnings()获得所有创建过的warning。注意组件的异常信息处理,不要直接console,因为一些 postcss 处理器会过滤掉console的输出导致异常信息丢失,用node.warn或者node.error创造CssSyntaxError 实例,会自动带上源码中的位置信息帮助debug,加到异常信息队列里。直接调用postcss下的方法可以用postcss.parse来处理一段css文本,拿到css ast,然后进行处理,再通过调用toResult().css拿到处理后的css输出,在一些简单的处理中可以用这种方法。写在最后:想写一下的可以按照这里的指引,很详细https://github.com/postcss/postcss-plugin-boilerplate这是我写的一个将px转为vw的插件vw-by-px参考:http://api.postcss.orgpostcss-pixel-to-viewport

March 18, 2019 · 1 min · jiezi

Hexo功能增强插件

序本文是hexo-enchancer插件的中文版文档.英文版:https://github.com/sisyphsu/h…博文链接: https://sulin.me/2019/Z726F8….介绍hexo-enhancer是一个Hexo功能增强插件。此插件支持的功能较多,并且未来会继续增加,可以理解为插件包。到目前为止,此插件支持的功能如下:自动生成title:根据文件名自动生成标题。自动生成date:根据文件名自动生成日期,具体策略类似Jekyll。自动生成abbrlink:根据标题进行base32和crc32生成短链接。自动生成categories:根据文件的路径解析文章所属分类。自动生成tags:根据配置在_config.yml中的可用tags和keywords自动扫描文章中出现的标签。正常情况下编写的Hexo文章需要在markdown头部手动指定许多属性,例如:—title: Titledate: 2019-03-05categories: [A, B]tags: [tag1, tag2]—# TitleThis is a markdown file, in categories [A, B], with tags [tag1, tag2]. 使用hexo-enhancer插件之后,以上Front-matter完全不需要手动指定:# TitleThis is a markdown file, in categories [A, B], with tags [tag1, tag2].消失的Front-matter完全按照约定规则由hexo-enhancer自动生成,让你可以更加惬意简单地撰写博文。安装npm install hexo-enhancer –save或yarn add hexo-enhancer用法 — date 和title我在使用Hexo之前,曾经用过一段时间Jekyll,抛开整体不谈,个人感觉Jekyll的文件名整合日期和标题的策略挺不错的,使用Hexo之后为了维护Front-matter真的很烦。因此本插件中也实现了类似的文件名策略,即直接将 date + title放在文件名里面,由插件在Hexo编译时动态解析这些属性,整个过程非常简单方便。hexo-enhancer解析文件名的正则表达式如下:/^.?(\d{4})[-]?(\d{2})[-]?(\d{2}).?[-_.@# ](.)$/如果你熟悉正则表达式的话,就知道具体格式多么灵活了,以下所有格式都可以被正确解析:20091010-Title.md2009-10-10_Title.md2009-10-10-Title.md2009/10/10#Title.md2009/10/10@Title.md[20091010]-Title.md【20091010】Title.md「20091010」-Title.mdhexo-enhancer 会将以上文件名全部解析为(最终结果不会回写入.md文件中):—title: Titledate: 2009-10-10—用法 — categorieshexo-enhancer 会将.md文件所在目录及父目录的名称添加入categories属性中,因此你应该按照文章分类放置.md文件,事实上大多数人一直都这么做的。比如 _posts/区块链/比特币/20091010-比特币简介.md 文章将自动获得下面的categories属性:—title: 比特币简介date: 2009-10-10categories: [区块链, 比特币]—用法 — tags我一直认为,文章标签不应该手动维护,因为这样做太麻烦且容易遗漏,最终导致标签非常混乱。正确的做法应该是,将常见的标签关键词全局配置好,然后根据配置好的标签关键词,自动扫描每篇文章包括哪些关键词并生成tags属性。hexo-enhancer的做法就是这样,启动后扫描_config.yml中的keywords与tags属性收集全局标签候选词,然后给每一篇文章自动扫描tags。例如,_config.yml配置的标签可以是这样的:keywords: HTML, JavaScript, Hexotags: Java, Golang, React, Vuehexo-enhancer会扫描您的.md文章,如果文章内出现以上关键词,则自动将其分配如文章的tags属性中。需要特别指出的是,keywords是标准配置,它最终会出现在网页meta中,而tags是自定义的属性,只会被本插件使用。用法 — abbrlinkhexo-enhancer使用 base32(crc32(title)) 算法为每一篇文章分配abbrlink属性,您可以在permlink中使用它们:permalink: :year/:abbrlink.html# permalink: :year/:abbrlink# permalink: posts/:abbrlink.html# permalink: :year/:month/:day/:abbrlink.html使用abbrlink之后,文章的url就会变得非常简洁,例如 https://sulin.me/2018/3055NXV.html有一些插件会根据标题的拼音、翻译生成permlink,但是我感觉这些都不是好的做法。事实上url不宜太长,将一句话放在url中并不一定增强所谓的seo优化,反倒导致其使用起来相当不便。就像许多博客平台一样,为每篇文章分配短小且唯一的url即可,无论是看起来还是用起来都很方便。LicenseMIT ...

March 6, 2019 · 1 min · jiezi

助力深度学习!阿里开源可插拔 GPU 共享调度工具

根据 Gartner 对全球 CIO 的调查结果显示,人工智能将成为 2019 年组织革命的颠覆性力量。对于人工智能来说,算力即正义,成本即能力,利用 Docker 和 Kubernetes 代表云原生技术为 AI 提供了一种新的工作模式,将 GPU 机器放到统一的资源池进行调度和管理,这避免了GPU 资源利用率低下和人工管理的成本。因此,全球主要的容器集群服务厂商 Kubernetes 都提供了 Nvidia GPU 容器集群调度能力,但是通常都是将一个 GPU 卡分配给一个容器。这虽然可以实现比较好的隔离性,确保使用 GPU 的应用不会被其他应用影响;对于深度学习模型训练的场景也非常适合,但是,针对模型开发和模型预测的场景还是会显得比较浪费。基于此,大家有了共享 GPU 的集群调度需求。Kubernetes 共享 GPU 集群调度共享 GPU 的集群调度就是能够让更多的模型开发和预测服务共享同一个 GPU 卡,进而提高集群中 Nvidia GPU 的利用率。而这就需要提供 GPU 资源的划分,而这里 GPU 资源划分的维度指的就是 GPU 显存和 Cuda Kernel 线程的划分。通常在集群级别谈支持共享 GPU 是以下两件事情:1.调度2.隔离,我们这里主要讨论的是调度,隔离的方案目前需要用户通过应用限制(比如使用 Tensorflow 的per_process_gpu_memory_fraction 来控制),未来会提供基于 Nvidia 的 MPS 的可选项, 也会考虑 GPU 的方案。而对于细粒度的 GPU 卡调度,目前 Kubernetes 社区并没有很好的方案,这是由于 Kubernetes 对于 GPU 这类扩展资源的定义仅仅支持整数粒度的加加减减,无法支持复杂资源的分配。比如用户希望使用 Pod A 占用半张 GPU卡,这在目前 Kubernetes 的架构设计中无法实现资源分配的记录和调用。这里挑战是多卡 GPU 共享是实际矢量资源问题,而 Extened Resource 是标量资源的描述。针对此问题,我们设计了一个 Out Of Tree 的共享 GPU 调度方案,该方案依赖于 Kubernetes 的现有的工作机制:Extended Resource 定义Scheduler Extender 机制Device Plugin 机制Kubectl 的扩展机制这个 GPU 共享调度扩展的好处是:利用 Kubernetes 的扩展和插件机制实现,对于 API Server,Scheduler,Controller Manager 以及 Kubelet 等核心组件没有侵入性。这就方便了使用者可以在不同 Kubernetes 版本上应用这个方案,无需 rebase 代码和重新构建 Kubernetes 二进制包。用户场景集群管理员:“我想提高集群的 GPU 使用率;在开发过程中,多个用户共享模型开发环境。”应用开发人员:“我希望能够同时在 Volta GPU 上运行多个推理任务。”目标能够让使用者通过 API 描述对于一个可共享资源的申请, 并能实现该种资源的调度非目标不支持该共享资源的隔离不支持超卖设计原则明确问题简化设计,第一步只负责调度和部署,后续再实现运行时显存管控。有很多的客户明确的诉求是首先可以支持多AI应用可以调度到同一个 GPU 上,他们可以接受从应用级别控制显存的大小,利用类似gpu_options.per_process_gpu_memory_fraction控制应用的显存使用量。那我们要解决的问题就先简化到以显存为调度标尺,并且把显存使用的大小以参数的方式传递给容器内部。不做侵入式修改本设计中不会修改 Kubernetes 核心的 Extended Resource 的设计, Scheduler 的实现,Device Plugin 的机制以及 Kubelet 的相关设计。重用 Extended Resource 描述共享资源的申请 API。这样的好处在于提供一个可以移植的方案,用户可以在原生 Kubernetes 上使用这个方案。按显存和按卡调度的方式可以在集群内并存,但是同一个节点内是互斥的,不支持二者并存;要么是按卡数目,要么是按显存分配。详细设计前提:依旧延用 Kubernetes Extended Resource 定义,但是衡量维度最小单位从 1 个 GPU 卡变为 GPU 显存的 MiB。如果所节点使用的 GPU 为单卡 16GiB 显存,它对应的资源就是 16276MiB;由于用户对于共享GPU的诉求在于模型开发和模型预测场景,在此场景下,用户申请的GPU资源上限不会超过一张卡,也就是申请的资源上限为单卡。而我们的工作首先是定义了两个新的 Extended Resource: 第一个是 gpu-mem, 对应的是 GPU 显存;第二个是 gpu-count,对应的是 GPU 卡数。 通过两个标量资源描述矢量资源, 并且结合这一资源,提供支持共享 GPU 的工作机制。下面是基本的架构图:核心功能模块:GPU Share Scheduler Extender: 利用 Kubernetes 的调度器扩展机制,负责在全局调度器 Filter 和 Bind 的时候判断节点上单个 GPU 卡是否能够提供足够的 GPU Mem,并且在 Bind 的时刻将 GPU 的分配结果通过 annotation 记录到 Pod Spec 以供后续 Filter 检查分配结果。GPU Share Device Plugin: 利用 Device Plugin 机制,在节点上被 Kubelet 调用负责 GPU 卡的分配,依赖 scheduler Extender 分配结果执行。具体流程:1. 资源上报GPU Share Device Plugin 利用 nvml 库查询到 GPU 卡的数量和每张 GPU 卡的显存, 通过ListAndWatch()将节点的 GPU 总显存(数量 显存)作为另外 Extended Resource 汇报给 Kubelet; Kubelet 进一步汇报给 Kubernetes API Server。 举例说明,如果节点含有两块 GPU 卡,并且每块卡包含 16276MiB,从用户的角度来看:该节点的 GPU 资源为 16276 2 = 32552; 同时也会将节点上的 GPU 卡数量 2 作为另外一个 Extended Resource 上报。2. 扩展调度GPU Share Scheduler Extender 可以在分配 gpu-mem 给 Pod 的同时将分配信息以 annotation 的形式保留在 Pod spec 中,并且在过滤时刻根据此信息判断每张卡是否包含足够可用的 gpu-mem 分配。2.1 Kubernetes 默认调度器在进行完所有过滤(filter)行为后会通过 http 方式调用 GPU Share Scheduler Extender的filter 方法, 这是由于默认调度器计算 Extended Resource 时,只能判断资源总量是否有满足需求的空闲资源,无法具体判断单张卡上是否满足需求;所以就需要由 GPU Share Scheduler Extender 检查单张卡上是否含有可用资源。以下图为例, 在由 3 个包含两块 GPU 卡的节点组成的 Kubernetes 集群中,当用户申请gpu-mem=8138时,默认调度器会扫描所有节点,发现 N1 所剩的资源为 (16276 * 2 - 16276 -12207 = 4069 )不满足资源需求,N1 节点被过滤掉。而 N2 和 N3 节点所剩资源都为 8138MiB,从整体调度的角度看,都符合默认调度器的条件;此时默认调度器会委托 GPU Share Scheduler Extender 进行二次过滤,在二次过滤中,GPU Share Scheduler Extender 需要判断单张卡是否满足调度需求,在查看 N2 节点时发现该节点虽然有 8138MiB 可用资源,但是落到每张卡上看,GPU0 和分别 GPU1 只有 4069MiB 的可用资源,无法满足单卡 8138MiB 的诉求。而 N3 节点虽然也是总共有 8138MiB 可用资源,但是这些可用资源都属于 GPU0,满足单卡可调度的需求。由此,通过 GPU Share Scheduler Extender 的筛选就可以实现精准的条件筛选。2.2 当调度器找到满足条件的节点,就会委托 GPU Share Scheduler Extender 的 bind 方法进行节点和 Pod 的绑定,这里 Extender 需要做的是两件事情以 binpack 的规则找到节点中最优选择的 GPU 卡 id,此处的最优含义是对于同一个节点不同的 GPU 卡,以 binpack 的原则作为判断条件,优先选择空闲资源满足条件但同时又是所剩资源最少的 GPU 卡,并且将其作为ALIYUN_COM_GPU_MEM_IDX保存到 Pod 的 annotation 中;同时也保存该 Pod 申请的 GPU Memory 作为ALIYUN_COM_GPU_MEM_POD和ALIYUN_COM_GPU_MEM_ASSUME_TIME保存至 Pod 的 annotation 中,并且在此时进行 Pod 和所选节点的绑定。注意:这时还会保存ALIYUN_COM_GPU_MEM_ASSIGNED的 Pod annotation,它被初始化为“false”。它表示该 Pod 在调度时刻被指定到了某块 GPU 卡,但是并没有真正在节点上创建该 Pod。ALIYUN_COM_GPU_MEM_ASSUME_TIME代表了指定时间。如果此时发现分配节点上没有 GPU 资源符合条件,此时不进行绑定,直接不报错退出,默认调度器会在 assume 超时后重新调度。调用 Kubernetes API 执行节点和 Pod 的绑定以下图为例,当 GPU Share Scheduler Extender 要把 gpu-mem:8138 的 Pod 和经过筛选出来的节点 N1 绑定,首先会比较不同 GPU 的可用资源,分别为 GPU0(12207),GPU1(8138),GPU2(4069),GPU3(16276),其中 GPU2 所剩资源不满足需求,被舍弃掉;而另外三个满足条件的 GPU 中, GPU1 恰恰是符合空闲资源满足条件但同时又是所剩资源最少的 GPU 卡,因此 GPU1 被选出。3. 节点上运行当 Pod 和节点绑定的事件被 Kubelet 接收到后,Kubelet 就会在节点上创建真正的 Pod 实体,在这个过程中, Kubelet 会调用 GPU Share Device Plugin 的Allocate方法, Allocate方法的参数是 Pod 申请的 gpu-mem。而在Allocate方法中,会根据 GPU Share Scheduler Extender 的调度决策运行对应的 Pod会列出该节点中所有状态为 Pending 并且ALIYUN_COM_GPU_MEM_ASSIGNED为false的 GPU Share Pod选择出其中 Pod Annotation 的ALIYUN_COM_GPU_MEM_POD的数量与 Allocate 申请数量一致的 Pod。如果有多个符合这种条件的 Pod,就会选择其中ALIYUN_COM_GPU_MEM_ASSUME_TIME最早的 Pod。将该 Pod 的 annotation ALIYUN_COM_GPU_MEM_ASSIGNED设置为true,并且将 Pod annotation 中的 GPU 信息转化为环境变量返回给 Kubelet 用以真正的创建 Pod。相关项目目前项目已经开源到 github.com 上gpushare-scheduler-extendergpushare-device-plugin部署请参照部署文档测试样例首先创建一个使用aliyun.com/gpu-mem的应用apiVersion: apps/v1kind: Deploymentmetadata: name: binpack-1 labels: app: binpack-1spec: replicas: 1 selector: # define how the deployment finds the pods it manages matchLabels: app: binpack-1 template: # define the pods specifications metadata: labels: app: binpack-1 spec: containers: - name: binpack-1 image: cheyang/gpu-player:v2 resources: limits: # MiB aliyun.com/gpu-mem: 1024使用请参照使用文档构建请参照如何构建视频 Demo1: 部署多个 GPU Share 的 Pod,发现他们以 binpack 的方式被放置到同一个 GPU 卡上视频地址:https://cloud.video.taobao.com//play/u/2987821887/p/2/e/6/t/1/214292079721.mp42: 避免错误调度申请资源超过单个 GPU 可用资源的 Pod视频地址:https://cloud.video.taobao.com//play/u/2987821887/p/2/e/6/t/1/214235285109.mp4Roadmap在 Device Plugin 中提供 Nvidia MPS 的可选支持;支持该方案可以在由 kubeadm 初始化的 Kubernetes 集群自动化部署;提升 Scheduler Extener 的高可用性;为 GPU, RDMA 和弹性网卡提供通用方案。本文作者:jessie筱姜阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

March 4, 2019 · 3 min · jiezi

IDEA 插件开发入门教程

IntelliJ IDEA 是目前最好用的 JAVA 开发 IDE,它本身的功能已经非常强大了,但是每个人的需求不一样,有些需求 IDEA 本身无法满足,于是我们就需要自己开发插件来解决。工欲善其事,必先利其器,想要提高开发效率,我们可以借助 IDEA 提供的插件功能来满足我们的需求。如果没有我需要的功能怎么办?很简单,我们自己造一个!插件能做什么?IDEA 的插件几乎可以做任何事情,因为它把 IDE 本身的能力都封装好开放出来了。主要的插件功能包含以下四种:自定义语言支持:如果有 IDEA 暂时不支持的语言,你可以自己写一个插件来支持,例如 Go 语言原来的支持就是通过插件做的,后来单独做了一个 Goland。官方有自定义语言插件支持的教程。框架支持:例如Struts 2 的框架支持工具集成:可以给 IDEA 的自带功能进行增强,例如对 Git 的操作增加 CodeReview 的功能。参考Gerrit用户界面:自定义的插件改变用户界面。参考BackgroundImage我为了减少重复代码的编写,写了一个代码生成的插件IDEA代码生成插件CodeMaker,支持自定义代码生成的模板。Hello world 插件依照惯例,我们从 Hello world 开始。新建一个 Gradle 的插件工程有些教程推荐用 IDEA 默认的插件工程来开始,但是我比较推荐用 Gradle 来管理整个插件工程,后面的依赖管理会很方便,否则都得靠手动管理。点击新建工程,选择 Gradle接下来填写项目属性配置 Gradle,用默认配置就行新建完工程之后,IDEA 会自动开始解析项目依赖,因为它要下载一个几百兆的 SDK 依赖包,所以会比较久,打开科学上网能快一点。Gradle 依赖解析完成之后,项目结构如下图,其中 plugin.xml 是插件的配置,build.gradle 是项目依赖的配置(类比 pom.xml)。下面就是默认生成的 plugin.xml<idea-plugin> <!–插件id–> <id>com.xiaokai.test.demo</id> <!–插件名称–> <name>Demo</name> <!–开发者信息–> <vendor email=“support@yourcompany.com” url=“http://www.yourcompany.com”>YourCompany</vendor> <!–插件说明–> <description><![CDATA[ Enter short description for your plugin here.<br> <em>most HTML tags may be used</em> ]]></description> <!– please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/plugin_compatibility.html on how to target different products –> <!– uncomment to enable plugin in all products <depends>com.intellij.modules.lang</depends> –> <!–依赖的其他插件能力–> <extensions defaultExtensionNs=“com.intellij”> <!– Add your extensions here –> </extensions> <!–插件动作–> <actions> <!– Add your actions here –> </actions></idea-plugin>创建一个 ActionAction 是 IDEA 中对事件响应的处理器,它的 actionPerformed 就像是 JS 中的 onClick 方法。可以看出来,插件的开发本质上跟 web、Android 的开发没有什么不同,因为都是事件驱动的编程。我们可以直接使用 IDEA 提供的 Action 生成器点击 OK 之后会在 src 生成类文件:package com.xiaokai.test;import com.intellij.openapi.actionSystem.AnAction;import com.intellij.openapi.actionSystem.AnActionEvent;public class HelloWorldAction extends AnAction { @Override public void actionPerformed(AnActionEvent e) { // TODO: insert action logic here }}同时,动作的信息也会注册到 plugin.xml 中 <!–插件动作–> <actions> <!– Add your actions here –> <action id=“demo.hello.world” class=“com.xiaokai.test.HelloWorldAction” text=“HelloWorld” description=“Say Hello World”> <add-to-group group-id=“GenerateGroup” anchor=“last”/> </action> </actions>弹出对话框创建完 Action 之后我们就要开始往里面写逻辑了,既然是 Hello World 教学,那我们就来试一下最简单的弹出对话框。 @Override public void actionPerformed(AnActionEvent e) { //获取当前在操作的工程上下文 Project project = e.getData(PlatformDataKeys.PROJECT); //获取当前操作的类文件 PsiFile psiFile = e.getData(CommonDataKeys.PSI_FILE); //获取当前类文件的路径 String classPath = psiFile.getVirtualFile().getPath(); String title = “Hello World!”; //显示对话框 Messages.showMessageDialog(project, classPath, title, Messages.getInformationIcon()); }代码写完之后,打开 Gradle 的界面,点击 runIde 就会启动一个安装了插件的 IDEA,然后就可以进行测试。你还可以右键启动 Debug 模式,这样还能进行断点。运行的效果如下图:可以看到,我们右键打开 Generate 菜单之后,里面最后一项就是我们添加的 Action,进阶的教程如果想学习更多的原理和设计理念可以看IntelliJ Platform SDK的官方文档。不过老实说,它的文档写的挺差的,基本上就是简单讲了一下概念和原理,没有深入的分析。所以如果要深入研究还得靠自己。最靠谱的学习方式就是看别人写的插件,举个例子,你想知道怎么样实现自动生成代码,你就去找支持这个功能的插件,看他的源码是怎么写的。我当时写CodeMaker的时候也是靠自己啃源码之后写出来的。下面我简单介绍一下我用过的一些 API,这些 API 基本都没有文档说明,全靠代码相传。判断当前光标选择的元素是什么 //获取当前事件触发时,光标所在的元素 PsiElement psiElement = anActionEvent.getData(LangDataKeys.PSI_ELEMENT); //如果光标选择的不是类,弹出对话框提醒 if (psiElement == null || !(psiElement instanceof PsiClass)) { Messages.showMessageDialog(project, “Please focus on a class”, “Generate Failed”, null); return; }获取当前类文件的所有类对象一个类文件中可能会有内部类,所以读取的时候返回的是一个列表 public static List<PsiClass> getClasses(PsiElement element) { List<PsiClass> elements = Lists.newArrayList(); List<PsiClass> classElements = PsiTreeUtil.getChildrenOfTypeAsList(element, PsiClass.class); elements.addAll(classElements); for (PsiClass classElement : classElements) { //这里用了递归的方式获取内部类 elements.addAll(getClasses(classElement)); } return elements; }格式化代码 public static void reformatJavaFile(PsiElement theElement) { CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(theElement.getProject()); try { codeStyleManager.reformat(theElement); } catch (Exception e) { LOGGER.error(“reformat code failed”, e); } }使用粘贴板 CopyPasteManager.getInstance() .setContents(new SimpleTransferable(table.toString(), DataFlavor.allHtmlFlavor));更多更多的技巧可以参考我的项目CodeMaker,以及其他的开源插件。本文作者:风马萧萧 阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

February 25, 2019 · 2 min · jiezi

Idea插件使用

Ideaactivate-power-modeactivate-power-mode for IDEA.根据Atom的插件activate-power-mode的效果移植到IDEA上设置窗口在这里:我喜欢打开colorful关闭combo,你们呢?DownloadAtom Material IconsReplace Jetbrains’ icons with Atom File Icons and Material Design Icons! This is a both a port of the Atom File Icons (https://github.com/file-icons… and the Material Theme Icons (https://github.com/ChrisRM/ma… for Jetbrains products.它好像会随着Material Theme UI一起安装。DownloadMaterial Theme UIThis will add the Material Theme look to your IDE.很棒的一个主题设置在这里:DownloadRainbow BracketsRainbow Brackets / Rainbow Parentheses for IntelliJ based IDEs Supported languages:Java, Scala, Clojure, Kotlin, Python, Haskell, Agda, Rust, JavaScript, TypeScript, Erlang, Go, Groovy, Ruby, Elixir, ObjectiveC, PHP, HTML, XML, SQL, Apex language, C#, Dart …JavaWith Material Theme UIScalaKotlinClojureHtmlGifDownloadWakaTimeMetrics, insights, and time tracking automatically generated from your programming activity.InstallationInside your IDE, select Preferences -> Plugins -> Browse Repositories….Search for wakatime.Click the green Install Plugin button and confirm the installation.Re-launch your IDE.Enter your api key, then click Save.Use your IDE like you normally do and your time will be tracked for you automatically.Visit https://wakatime.com to see your logged time.Source Code: https://github.com/wakatime/j...chrome也有哦,附一张我的统计图:设置在这里:DownloadAndroid StudioAndroid WiFi ADBProvides an action which allow you quickly connect your Android device over WiFi to install, run and debug your applications without a USB connected by pressing one button. Connect your device using a USB cable and press the Android WiFi ADB button. Once the device be connected over WiFi you’ll see an IntelliJ/Android Studio notification. Now you can disconnect your USB cable and enjoy deploying, running and debugging your applications over WiFi. The version 2.0 enables a window to check which of your devices are connected or not and connect/disconnect it manually if needed.有了它就不用数据先连接调试了,需要在同一个局域网下哦。DownloadDatabase NavigatorDatabase development, scripting and navigation toolThis product adds extensive database development and maintenance capabilities to the IntelliJ IDEA development environment and related products. Along with a qualified and IDE-compliant SQL and PL/SQL editor, it provides advanced database connection management, script execution support, database objects browsing, data and code editor, support for database compiler operations, method execution and debugging, database objects factory, as well as various navigation capabilities between all its components.See features overview on the support page.Supported Databases:OracleMySQLSQLitePostgreSQLThis tool is free for personal and commercial usage. Donations are very welcome though.调试数据库有奇效。DownloadJSON To Kotlin Class (JsonToKotlinClass)Plugin for Kotlin to convert Json String into Kotlin data class code quicklyFast use it with short cut key ALT + K on Windows or Option + K on MacFeatures:Generating Kotlin data class from any legal JSON string or any URLs that returns a JSON string as response Generating Kotlin data class from any legal JSON text when right click on directory and select New -> Kotlin data class File from JSONSupporting (almostly) all kinds of JSON libs’ annotation(Gson, Jackson, Fastjson, MoShi and LoganSquare, kotlinx.serialization(default custom value))Customizing your own annotationsInitializing properties with default valuesAllowing properties to be nullable(?)Determining property nullability automaticallyRenaming property names to be camelCase style when selecting a target JSON lib annotation.Generating Kotlin data class as individual classesGenerating Kotlin data class as inner classesFormatting any legal JSON stringGenerating Map Type when json key is primitive typeOnly create annotation when neededCustom define data class parent classSort property order by AlphabeticalMake keyword property validSupport Loading JSON From Paster/Local File/Http URLSupport customize your own plugin by Extension ModuleFull Usage DocumentationDownload未完待续 ...

February 4, 2019 · 3 min · jiezi

Visual Studio Code使用中CPU占用率异常暴增过高原因

今天要说的是一个困扰我好几个月的问题,Visual Studio Code(下文简称VSCode)在使用中突然增高,风扇开始狂转,温度骤增,影响心情的故障原因。其实,无论是Windows还是OSX,很多人可能或多或少都遇到过VSCode突然就不好使了,我就遇到过好多次疑难杂症,折腾很久才弄出来,比如下面三点:tab键突然就不好使了,卡顿很久或者压根无法缩进,并且sidebar的git那块功能彻底失效!写Markdown文档的时候,tab键的缩进只能向右,不能收回。。。这真是奇葩。使用中莫名其妙的风扇就响了起来,看看进程和温度,CPU满载执行,完全不知道怎么回事,这也是本次要专门提到的问题。系统使用环境及VSCode状态检测我使用的是黑苹果,当然这个与CPU占用率增高并无关系,通过code –status查看一些基本信息如下:P750TM:~ whidy$ code –statusVersion: Code 1.30.2 (61122f88f0bf01e2ac16bdb9e1bc4571755f5bd8, 2019-01-07T22:48:31.260Z)OS Version: Darwin x64 17.7.0CPUs: Intel(R) Core(TM) i5-8600K CPU @ 3.60GHz (6 x 3600)Memory (System): 16.00GB (5.22GB free)Load (avg): 2, 2, 2VM: 0%Screen Reader: noProcess Argv: –inspect-extensions=9993GPU Status: 2d_canvas: enabled checker_imaging: disabled_off flash_3d: enabled flash_stage3d: enabled flash_stage3d_baseline: enabled gpu_compositing: enabled multiple_raster_threads: enabled_on native_gpu_memory_buffers: enabled rasterization: unavailable_software video_decode: enabled video_encode: enabled webgl: enabled webgl2: enabledCPU % Mem MB PID Process 0 98 1775 code main 0 49 1776 gpu-process 0 229 1777 window (settings.json — mpa-stat-sdk) 0 0 1780 /bin/bash -l 0 115 1783 extensionHost 0 82 1787 /Applications/Visual Studio Code.app/Contents/Frameworks/Code Helper.app/Contents/MacOS/Code Helper –nolazy –inspect=10785 /Applications/Visual Studio Code.app/Contents/Resources/app/extensions/json-language-features/server/dist/jsonServerMain –node-ipc –clientProcessId=1783 0 49 1784 watcherService 0 49 1789 searchService 0 33 1785 utility 0 82 1817 shared-process 0 311 1830 window (ald-stat.js — one-plus-sport) 0 49 1831 watcherService 0 98 1832 extensionHost 4 66 1870 electron_node eslintServer.js 0 131 1871 electron_node tsserver.js 0 66 1879 electron_node typingsInstaller.js typesMap.js 0 49 1835 searchServiceWorkspace Stats: | Window (ald-stat.js — one-plus-sport)| Window (settings.json — mpa-stat-sdk)| Folder (one-plus-sport): 273 files| File types: js(75) json(58) wxss(57) wxml(56) png(21) md(2)| gitignore(1) xlsx(1) jpg(1) zip(1)| Conf files:| Folder (mpa-stat-sdk): 21 files| File types: js(13) md(3) json(2) zip(2) gitignore(1)| Conf files: gulp.js(1) package.json(1)故障现象先来看看正常情况下和非正常情况的运行情况对比图:上图为正常情况下的截图上图为异常情况下的截图这个问题真的令我很苦恼,我这两张截图期间绝对没有做任何可能会产生高计算需求的工作,但是正常的操作怎么会出现这种情况呢。故障分析及解决于是进行了大量的搜索,百度就不用看了,屎一样的结果:前5篇内容完全一致,结论:“search.followSymlinks”:true,在我这一点用也没用。顺便吐槽,我完全不理解,在中国尤其是CSDN,为什么一个简单的小问题,一大堆人转载,完全一样的内容,如果真的是神一般的技巧,敢不敢多写一点,为什么这样能解决问题,出现故障的原因呢,无脑抄袭就算了,做笔记请使用自己的笔记本,比如有道云笔记,印象笔记不好吗,难道没人知道你是抄的?简直浪费搜索时间!垃圾!吐槽完毕,该用google了,实际上,我一开始就没用百度,只是写这篇文章,担心有人遇到过这样的问题,写过相同的解决方案,说我是抄来的。就索性百度搜一下。用谷歌自然用英文,虽然我英语很渣,但是谷歌懂我。只需要几个关键词:无论是微软官方的issue查,还是stackoverflow查,总能有很大的收获,但是,我这个问题比较特殊,我尝试过最基本的两种处理办法:屏蔽所有插件测试重置自定义的settings.json文件然而都不好使。可怜我英文也不是特别好,有可能有些有用的信息被我忽略掉了。这里补充一下,其实大部分原因,可以通过官方提供的自排除方案来检查Performance Issues,我很推荐遇到CPU占用率过高的情况下先看看这篇文章。不过也不是全无收获,至少开头提到的三个问题,前两个查出来了。第一个问题是插件Auto Rename Tag造成的,这个至少在一年前是非常流行的,我自己也觉得很好用,就一直装了,完全想不到这个简单的功能居然会造成VSCode某些功能异常,去插件主页看看,作者也不更新维护了,插件评价页面全是一星,可见目前已经是垃圾插件了查看评论,不过过年很多无脑转载的还在推荐这个插件,所以为了避免大家入坑,建议不要使用Auto Rename Tag。第二个问题也是插件问题,就是Markdown All in One这个插件导致缩进功能不好使,原因我也不知道,其实这个问题并不严重,有强烈依赖改插件的朋友还是可以继续使用,我也很推荐这个插件写markdow,有些还是挺便捷的,不过我是删了哈哈哈,看个人意愿了~好了第三个问题才是最重要的,我反复观察了很久,做了大量测试和查阅文档,终于得出结论:当且仅当VSCode的窗口大于1个的时候,才会出现该现象出现异常经常出现在切换不同窗口之后发生我发现切换窗口后出现异常就搜索关键词two/multi vscode switch cause a high cpu useage终于找到了一丝丝线索,仔细阅读了下面几篇:Switching between VSCode windows with any custom app switcher causes high CPU usageapplication processes consume 200% CPU combinedExtreme CPU usage when multiple windows are openRenderer high CPU on OSX with custom window switchers我终于,发现了一个问题,我切换VSCode的窗口的方式有问题!!!我是用了罗技鼠标的快捷键功能导致,如图:啊,我的天啊!我反复尝试,在多个窗口,直接用键盘的Cmd + 来切换内部应用窗口,妥妥的一点毛病都没有。结论很多情况下VSCode功能异常都是插件引起的,尝试关闭所有插件来检查,建议阅读Performance Issues。其次是**第三方Switcher应用切换VSCode窗口会造成异常!比如常用的鼠标功能键!啊,坑了我好多个月,反复重装VSCode和系统都没法解决的毛病终于解决了。。。以后只能用Cmd + 来切换了 ...

January 28, 2019 · 2 min · jiezi

VS Code插件开发介绍(二)

一、前言在上一篇文章里,我简要介绍了 VSCode 插件开发的基本流程,同时讲解了如何获取文件夹绝对路径和用户输入的方法。最近又开发了一个新的插件,主要用途是替换当前编辑文件的内容。google 了一圈,发现介绍这方面的文章很少,特此记录一下,希望对有类似需求的人有一些帮助。二、需求需求很简单,我需要将下面文件的内容:export default { add_member# manage_member_card# member_setting# search_member# edit_member# delete_member# assign_consultant# add_member_tag# import_member# modify_member_point#};替换为:export default { add_member: ‘ce0’, manage_member_card: ‘ce1’, member_setting: ‘ce2’, search_member: ‘ce3’, edit_member: ‘ce4’, delete_member: ‘ce5’, assign_consultant: ‘ce6’, add_member_tag: ‘ce7’, import_member: ‘ce8’, modify_member_point: ‘ce9’,};可以理解为一个简单的自动化编号工具。其中要解决的问题主要有下面三个:获取当前文件路径读取文件内容写文件内容下面介绍如何实现。三、实现开始以为 VSCode 有现成的 API 可以取到当前文件内容,但找了一圈搜不到,只能通过迂回的方式实现。第一步,获取当前文件的路径:const currentlyOpenTabfilePath = vscode.window.activeTextEditor.document.fileName;第二步,读取文件内容,并拆分为数组const fs = require(‘fs’);const fileContentArr = fs.readFileSync(currentlyOpenTabfilePath, ‘utf8’).split(/\r?\n/);第三步,写文件。由于没法逐行替换文件内容,只能现将原来的文件清空,再一行一行添加回去。fs.truncateSync(currentlyOpenTabfilePath);fileContentArr.forEach( (line, index) => { let content = line; if (line.slice(-1) == ‘#’) { content = xxxxx; } fs.appendFileSync(currentlyOpenTabfilePath, content + ((index == contentLength - 1) ? ’’ : ‘\n’));})四、总结其实这个需求实现起来还是蛮简单的,主要是要根据 VSCode 的特点将思路理顺,再一步步实现。如果有更好的实现方式,请务必留言给我 ...

December 27, 2018 · 1 min · jiezi

chrome插件编写

chrome浏览器Chrome 浏览器追求的是全方位的快速体验。它不仅能飞快地从桌面上启动,而且能瞬间完成网页加载,还能以闪电般的速度运行网络应用。 Chrome 浏览器整洁且直观。您可在同一位置进行搜索和导航,可随意排列标签页,既快捷又轻松。您不必成为安全专家即可放心地浏览网络。Chrome 默认会为用户提供安全保护,并可供所有人轻松且安全地使用。内置地址所有内置地址列表:chrome://chrome-urls/开发者常使用列表:开发者高级选项:chrome://flags/dns缓存清除: chrome://net-internals/#dns扩展应用程序:chrome://extensions/侦测页面[包括外接安卓设备]:chrome://inspect/#devices比较全的的列表:(1)chrome://accessibility/可达性分析,默认是关闭的,点击accessibility off后变成accessibility on|show accessibility tree,点击show accessibility tree显示分析树(2)chrome://appcache-internals/应用程序缓存,显示所有的应用程序缓存路径列表(3)chrome://apps/当前chrome安装的应用列表(4)chrome://blob-internals/当前内部的blob文件列表(5)chrome://bookmarks/ 书签管理器(6)chrome://cache/当前缓存文件的url列表,点击url可以看到对应的缓存文件内容,包括类型 编码 过期时间等概要信息,以及文件内容等具体信息,以二进制方式显示(7)chrome://chrome/chrome关于页面,显示当前chrome的版本信息。(8)chrome://chrome-urls/显示chrome可用的伪url列表(9)chrome://components/显示chrome的组件列表,可以点击"检测是否有更新"来检测当前组件是否有新版本,如果有,可以直接下载更新。(10)chrome://conflicts/模块冲突检测,会列出当前已加载到主进程中的所有模块,包括模块的数量、签名方,版本以及模块所在的位置(11)chrome://copresence/Google共存信息列表,显示共存信息,包括有效指令、传输的令牌、收到的令牌(12)chrome://crashes/显示当前chrome的崩溃报告,需要启用崩溃报告后才会显示。https://support.google.com/chrome/answer/96817中说明了如何启用崩溃报告。设置后需要重启chrome才能生效(13)chrome://credits/类似于演职员列表,是一份chrome使用的一些开源组件或工具的列表,包括各种工具的主页和授权文件。但第一行的“Accessibility Audit library, from Accessibility Developer Tools”的主页居然链接的是一份未压缩的js源码,不知道是啥情况(14)chrome://device-log/设备日志,chrome://device-log/?refresh=秒数 可以自动刷新(15)chrome://devices/显示当前在网络中注册的设备,可以添加打印机到云打印(16)chrome://discards/丢弃的标签页面,标签页面按照感兴趣的程度由高到低排序。如果当前的物理内存超出运行内存后,最不感兴趣的tab页面可能被丢弃掉。(17)chrome://dns/如果当前显示DNS pre-resolution and TCP pre-connection is disabled.则打开设置,勾选“预提取资源,以便更快速地加载网页”然后刷新当前页面就可以看到相关页面预加载的分析数据列表了(18)chrome://downloads/下载内容页面(19)chrome://extensions/扩展程序列表(20)chrome://flags/实验性功能列表,可以在这里启用这些实验性的功能(21)chrome://flash/显示flash插件的版本信息,安装位置及显卡的一些具体信息,包括显卡版本号,GPU(22)chrome://gcm-internals/GCM(Google Cloud Messaging )内部构建信息,包括签到、连接、注册、发送、接收相关的日志信息。(23)chrome://gpu/显示当前的GPU信息,包括图像功能的状态(各种功能的硬件加速)、Gpu内存buffer的状态(24)chrome://help/chrome关于页面,与chrome://chrome/是同样的效果(25)chrome://histograms/直方图,柱状图,显示了浏览器启动到上一个页面加载的状态统计数据,重新加载可以获取到当前页面加载数据。(26)chrome://history/历史记录页面,显示所有的浏览记录(27)chrome://indexeddb-internals/显示chrome的内部数据库的实例列表,包括所有的内部数据所在的路径,最后修改时间及数据库大小(28)chrome://inspect/检测设备,页面,扩展插件,应用程序等,在Pages标签中显示当前打开的所有tab页面,点击inspect直接跳转到该页面,并调起开发者工具。(29)chrome://invalidations/失效的调试信息,失效调试服务状态,注册的失效服务处理器等信息(30)chrome://local-state/本地状态,显示的是一个json格式的文件,包括了浏览器的很多状态信息,插件的详细信息(31)chrome://media-internals/当前的多媒体内部构建信息,如果当前使用的是浏览器内部的播放器而不是flash播放器的话,会在Players、Audio、Video Capture显示播放文件的详细信息,在Player中可以显示当前播放的适配的详细信息,包括音频、视频及播放器的内部状态信息。(32)chrome://memory会自动跳转到chrome://memory-redirect/,显示浏览器占用的总内存以及各个内部进程占用的内存,包括各个Tab页面占用的物理内存和虚拟内存数,包括私有内存,共享内存及总内存(33)chrome://memory-internals/内存内部详细信息,点击Update后可以获取到当前浏览内存的使用信息,包括一个json格式的数据。下发有一个列表,可以显示出所有进程所占用的内存,以及V8引擎使用的和分配的内存。(34)chrome://nacl/NaCl的版本信息,包括NaCl的插件位置,版本信息(35)chrome://net-internals网络内部构件的信息。包括代理信息、时间信息、DNS信息。其中的DNS可以显示当前浏览器中缓存的DNS信息,包括过期时间(36)chrome://newtab打开一个新的标签页(37)chrome://omnibox/omnibox 的测试工具 ,omnibox API https://developer.chrome.com/extensions/omnibox(38)chrome://password-manager-internals/显示捕获到的密码管理日志。当这个页面被关闭掉,则已有的记录会被清除,并且不再捕获。(39)chrome://plugins/显示当前chrome中所使用的插件及版本信息,可以在该页面点击 停用 来停用某个插件(40)chrome://policy/显示已设置的政策,默认是没有的(41)chrome://predictors/显示预测列表,包括自动完成动作的预取列表,也就是在地址栏输入某些字母后,出现对应的完整地址的列表,还包括(42)chrome://print/浏览器打印页面(43)chrome://profiler/分析器,可以按照不同的条件分组及排序,主要应该是用于分析chrome的各种进程的内部信息(44)chrome://quota-internals/存储空间的配额信息,包括了三个tab页面,Summary、Usage&Quota、DataSummary标签页显示的是一个磁盘总的空闲空间大小以及混合统计的一些数值Usage&Quota 标签页显示的是临时的、持久化的和同步的数据库中的具体数据项Data标签中点击Dump按钮可以生成一个json格式的文件,包含了前面两个tab中的统计信息和分类信息。(45)chrome://serviceworker-internals/serviceworker的内部组件,可以勾选选择框,进行调试ServiceWorker的项目主页: https://www.chromium.org/blink/serviceworker介绍视频:https://youtu.be/4uQMl7mFB6g视频中介绍者的的代码:https://github.com/jakearchibald/simple-serviceworker-tutorialw3c ServiceWorker的Demo:https://github.com/w3c-webmob/ServiceWorkersDemos(46)chrome://settings/chrome的设置页面(47)chrome://signin-internals/当前chrome登录者信息,包括账户状态的各种信息(48)chrome://suggestions/推荐信息,也就是打开新的tab页是默认显示的推荐网站的缩略图页面的那些网站,包含了网站的信息和过期时间。(49)chrome://sync-internals/chrome账户同步信息,包含了多个tab页面,首页显示的是同步的概要信息,包含同步相关的各种信息,包括上一次同步的时间,Token请求时间,接收时间等。后面的tab按照同步的不同类型展示了不同信息,包括了同步的分类、事件等(50)chrome://system/系统的诊断数据,包括当前Chrome的版本信息、操作系统的版本信息、同步数据信息、数据压缩代理是否启用、内存使用概况信息、usb键盘检测信息。(51)chrome://terms/chrome服务条款(52)chrome://thumbnails/顶级网站的url,分为包含缩略图的和未包含的、聚焦和未聚焦,估计也是用于在新开tab页面做推荐时使用(52)chrome://tracing/可以在该页面录制chrome的跟踪信息,也可以使用监控(53)chrome://translate-internals翻译内部组件信息,此处包含了对于chrome翻译的设置,包括用户自定义的不需要自动翻译的网站列表,可以在此处进行编辑,删除包括了当前翻译引擎的设置,以及翻译组件的日志信息,日志包括了检测日志、事件日志和错误日志,其中检测日志可以dump为json格式的文件。追踪日志会将打开该页面后的浏览器访问的网页内容抓取出来,包括要翻译的文字内容列表(54)chrome://user-actions/用户操作列表,包括操作类型和发生时间。(55)chrome://version/显示当前chrome的版本信息,包括版本号、JavaScript 引擎版本号,Flash插件版本号,用户代理信息等(56)chrome://view-http-cache/显示当前http缓存的url列表,点击对应的url,可以打开缓存的文件,包含了文件的具体信息和二进制内容信息(57)chrome://webrtc-internals/webrtc内部组件信息。点击Create Dump按钮,可以下载当前的webrtc连接的数据信息和状态信息快照数据(58)chrome://webrtc-logs/webrtc日志信息应用商店扩展应用商店包含了很多实用的扩展应用,adblock,广告过滤开发人员小心你的本地调试代码也被拦截了Momentum 新开页面的美化Proxy SwitchyOmega 浏览器代理设置二维码小助手 当前页面的二维码生成器捕捉网页截图 - FireShot 滚动全局页面截图插件编写参考chrome扩展入门编一个入门的插件;扩展由不同但关联的组件构成。组件可以包括后台脚本,内容脚本,选项页面,UI元素和各种逻辑文件,根据扩展的具体功能加入需要的功能组件模块,其中使用的技术栈就是HTML、JS、CSS,而最后的扩展文件就是压缩的HTML,CSS,JavaScript,图像和Web平台中使用的其他文件得出的包,扩展具有广泛的功能。他们不仅可以修改用户查看、交互的Web页面内容,甚至可以扩展和更改浏览器本身的行为【所以每个浏览器的扩展可能有点不一样】,一个常见的chrome扩展会包含一下的一些内容:manifest.json清单文件【类似配置文件,表明权限、版本、名称、介绍、配置入口等信息】ico 【应用扩展商店和chrome浏览器上的工具栏展示的图标】Background Script 【后台脚本是扩展的事件处理程序;它包含对扩展重要的浏览器事件的侦听器。它处于休眠状态,直到事件被触发然后执行脚本逻辑。有效的后台脚本仅在需要时加载,在空闲时卸载】UI Elements 【UI界面就是正常的html页面,主要是交互中的弹窗等】Content Script 【这个就是操作用户打开的页面】Options Page 【扩展可供用户配置的页面,用于修改扩展中的一些默认配置参数】一个改变当前查看页面的背景色的扩展插件实现想要实现这个功能,很简单就知道需要一下模块:manifest.json 【配置】ico 【图标】Background Script 【图标按钮点击交互】UI Elements 【点击图标是展示的弹窗页面】Options Page 【可供用户选择修改默认的背景色的页面】Content Script 【修改用户查看的页面的背景色】manifest.json配置文件,权限、弹窗页面、ico位置等信息。{ “name”: “Getting Started Example”, “version”: “1.0”, “description”: “Build an Extension!222”, “permissions”: [“activeTab”, “declarativeContent”, “storage”], “background”: { “scripts”: [“background.js”], “persistent”: false }, “options_page”: “options.html”, “page_action”: { “default_popup”: “popup.html”, “default_icon”: { “16”: “fh-icon.png”, “32”: “fh-icon.png”, “48”: “fh-icon.png”, “128”: “fh-icon.png” } }, “icons”: { “16”: “fh-icon.png”, “32”: “fh-icon.png”, “48”: “fh-icon.png”, “128”: “fh-icon.png” }, “manifest_version”: 2}background.js后台脚本,chrome.runtime.onInstalled.addListener(function() { chrome.storage.sync.set({color: ‘#f00’}, function() { console.log(“The color is green.”); }); chrome.declarativeContent.onPageChanged.removeRules(undefined, function() { chrome.declarativeContent.onPageChanged.addRules([{ conditions: [new chrome.declarativeContent.PageStateMatcher({ pageUrl: {}, }) ], actions: [new chrome.declarativeContent.ShowPageAction()] }]); });});popup.html点击ico的时候弹出的页面,只有一个可被点击的色块按钮。<!DOCTYPE html> <html> <head> <style> button { height: 30px; width: 30px; outline: none; } </style> </head> <body> <button id=“changeColor”></button> <script src=“popup.js”></script> </body> </html>popup.js弹出页面的交互,点击弹窗页面中的按钮时,需要设置当前展示页面的背景色为chrome.storage存储的默认色值,let changeColor = document.getElementById(‘changeColor’);chrome.storage.sync.get(‘color’, function(data) { changeColor.style.backgroundColor = data.color; changeColor.setAttribute(‘value’, data.color);});changeColor.onclick = function(element) { let color = element.target.value; chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { chrome.tabs.executeScript( tabs[0].id, {code: ‘document.body.style.backgroundColor = “’ + color + ‘”;’}); });};options.html扩展应用页面可以查看每个扩展的详细介绍,这个页面就是扩展程序的扩展程序选项页面,用户可以自由配置扩展程序需要的参数【前提是扩展应用开发把配置参数放在这个页面供使用者修改了】。本案例是可供选择的背景色值。<!DOCTYPE html><html> <head> <style> button { height: 30px; width: 30px; outline: none; margin: 10px; } </style> </head> <body> <div id=“buttonDiv”> </div> <div> <p>Choose a different background color!</p> </div> </body> <script src=“options.js”></script></html>options.js扩展程序选项页面的交互脚本,在用户选择 options.html页面中的颜色块的时候,处理设置chrome.storage存储的默认色值,let page = document.getElementById(‘buttonDiv’); const kButtonColors = [’#3aa757’, ‘#e8453c’, ‘#f9bb2d’, ‘#4688f1’]; function constructOptions(kButtonColors) { for (let item of kButtonColors) { let button = document.createElement(‘button’); button.style.backgroundColor = item; button.addEventListener(‘click’, function() { chrome.storage.sync.set({color: item}, function() { console.log(‘color is ’ + item); }) }); page.appendChild(button); } } constructOptions(kButtonColors);上面实例是chrome官方提供的基础实例,还有很多API需要在使用的时候查看。不能科学上网的话,只能参考一下国内的其他浏览器的扩展开发,其实是类似的,基本都是借鉴的Chrome的方式。参考:chrome扩展入门chrome扩展综述 ...

December 26, 2018 · 2 min · jiezi

VS Code插件开发介绍

前言前段时间做了一个基于命令行的效率工具,可以自动生成组件的模板代码。自己用起来还觉得挺好,但在组内案例几次后大家都不愿意用,究其原因还是命令行工具使用起来门槛有点高,不方便。由于组内已经统一使用VS Code进行开发了,于是决定研究下VS Code的插件开发,让效率工具更方便的用起来。准备工作为了降低开发门槛,微软做了一个Yeoman代码生成命令,可以很方便的生成插件开发需要的模板代码,可以通过以下命令安装:// 安装npm install -g yo generator-code// 使用yo code运行完以上命令后会出现下面的操作界面,填入需要的信息即可。运行示例代码代码生成后,可以按F5开始调试插件,此时VS Code会新建一个实例并进入插件开发模式,开发中的插件可以在这个新的实例中使用。模版代码会生成一个名为Hello World的命令,按下⇧⌘P调出命令输入窗口,然后输入’Hello World’运行命令。如果找不到命令,重启下VS Code再重新运行。修改代码插件的入口代码在extension.js这个文件中,主要是修改avtivate函数:export function activate(context) { // 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 “my-first-extension” 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(’extension.sayHello’, () => { // 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!’); }); context.subscriptions.push(disposable);}我插件的功能是用户通过右键点击导航栏,获取选中文件夹的绝对路径,然后提示用户输入新组件的名字,然后自动帮用户生成组件的模板代码。开发的关键点是如何获取文件夹绝对路径和获取用户输入的组件名。尤其是获取路径,找了很久才找到,官网的文档只字未提。先看代码:function activate(context) { console.log(‘Congratulations, your extension “react-template” is now active!’); // 注册一个名为createFunctionalComponent的命令 const fc = vscode.commands.registerCommand(’extension.createFunctionalComponent’, function (param) { // 文件夹绝对路径 const folderPath = param.fsPath; const options = { prompt: “请输入组件名: “, placeHolder: “组件名” } // 调出系统输入框获取组件名 vscode.window.showInputBox(options).then(value => { if (!value) return; const componentName = value; const fullPath = ${folderPath}/${componentName}; // 生成模板代码,不是本文的重点,先忽略 generateComponent(componentName, fullPath, ComponentType.FUNCTIONAL_COMP); }); }); context.subscriptions.push(pc);}代码很简单,就不做讲解了。为了显示Create Functional Component这个菜单项,我们需要修改package.json文件的contributes字段。activationEvents字段也要相应的改下。同时为了给插件配一个图标,要加一个icon字段: “icon”: “images/icon.png”, “activationEvents”: [ “onCommand:extension.createFunctionalComponent” ], “contributes”: { “commands”: [ { “command”: “extension.createFunctionalComponent”, “title”: “Create Functional Component” } ], “menus”: { “explorer/context”: [ { “command”: “extension.createFunctionalComponent”, “group”: “1_modification” } ] } },详细的contributes配置可以看这里。配置好menus之后,registerCommand的第二个函数参数就能取到文件或文件夹的绝对路径了。发布插件插件开发完后就可以发布了,需要安装vsce npm install -g vsce安装完后,需要去Azure DevOps注册并生成一个access token。详细的流程可以看这里。生成toke的时候有两个地方需要注意下:token生成后就可以登录和发布了。如果有任何的修改,要注意修改package.json里面版本号才能发布成功。发布成功后,很快就能在VS Code的插件市场搜到了。总结本文介绍了VS Code插件开发的基本流程,实现了一个简单的插件。本文只涉及到VS Code插件系统的冰山一角,更多的高级功能以后接触到的时候再作介绍。如果想再作进一步的了解,可以从这里开始。 ...

October 11, 2018 · 2 min · jiezi