vscodeのvueコンポーネントコード補完プラグインの構築とアップロード

15679 ワード

1.インストールツール
vscode Generatorのインストール
npm install -g yo generator-code
2.初期プロジェクトの構築
yo code
  • New Code Snippets
  • を選択
  • ヒントに従って後続の構成記入
  • を完了する.
  • が完了すると自動的にsnippets初期プロジェクトが生成され、プロジェクトの内容は以下の
  • である.
  • snippetsプラグインは他のプラグインとは異なり、このプラグインのキーコンテンツはjsonファイルであり、コンテンツフォーマットは以下の
  • である.
  • ひょうたんに従って瓢箪を描けばいいです.
  • 
    "Affix": {
    
            "prefix": "Affix",
    
            "body": [", ":offsetTop =\"offsetTop\"", ":offsetBottom =\"offsetBottom\"", ">"],
    
            "description": "affix      :"
    
        }
    
    
  • 効果:
  • 車に戻った後自動充填コード断片
  • 3.snippet.json自動生成
    拡張requireメソッド
    各コンポーネントの情報を取り出し、snippetのフォーマットでsnippetに入力する必要があります.jsonファイルでは、コンポーネントライブラリから各コンポーネントに対応するpropsをどのように抽出するかは、もちろん手作業で収集するという愚かな方法ではなく、プログラマーの方法はもちろんコードツールで重複労働を避けることです.私の考えは、コンポーネントからpropsを取得し、node環境で実行し、最終的なsnippetを生成するツールメソッドを書くことです.jsonファイル.requireのモジュールを知っていると、exportのオブジェクトに戻り、propsを手に入れることができます.
    
    const component = require("./src/components/alert/index.js");
    
    console.log(component);
    
    
  • node snippetDemoを実行する.js,最初の問題は
  • であった
     nodeはES 6に対して部分的にサポートされており、node環境ではES 6モジュールはサポートされていません.これは簡単に解決策を見つけることができます.こちらではbabel-registerを使用しており、インストール後は直接require(「babel-register」)を使用しています.再度実行すると、今回のエラーは異なります.コンポーネントはvue単一ファイルコンポーネントの形式であるため、node環境ではコンパイルできません.そのため、template部分でエラーが発生しました.
      普段web開発をするときはvue-loaderを先に使います.vueをjsにコンパイルするには、requireのときに動的にコンパイルする方法がありますか.vueはjsにコンパイルされていますね.もちろんありますが、まずrequireの原理を深く理解します.
    requireモジュールのプロセス:Module.load("a.js") --> var module = new Module(); --> module.load("a.js") --> module._compile()
    Module.prototype.require = function(path) {
      return Module._load(path, this);
    };
    Module._load = function(request, parent, isMain) {
    
      var filename = Module._resolveFilename(request, parent);
      
      //          
      if (NativeModule.exists(filename)) {
        return NativeModule.require(filename);
      }
    
      //          
      var module = new Module(filename, parent);
      Module._cache[filename] = module;
    
      //     
      try {
        module.load(filename);
      }
    
      //      exports  
      return module.exports;
    };
    
  • module.loadメソッドは、モジュールをロードする際にモジュールの接尾辞名を決定し、その後、対応するファイルのロードメソッド
  • を実行する.
    Module.prototype.load = function(filename) {
      var extension = path.extname(filename) || '.js';
      if (!Module._extensions[extension]) extension = '.js';
      Module._extensions[extension](this, filename);
      this.loaded = true;
    };
    
  • jsファイルのextensionメソッド定義
  • Module._extensions['.js'] = function(module, filename) {
      var content = fs.readFileSync(filename, 'utf8');
      module._compile(stripBOM(content), filename);
    };
    

    上のコードからrequireのjsファイルがわかる場合、実際にioがファイルを読み込んだ後moudleを通過する.loadのメソッドはファイルをロードし、順次実行します.extensionにマウントする方法は、ファイル文字列を読み出して実行します.compile.module.compileの前にもっとやってください.vueファイルをjsファイルに解析すると、requireのときにvueファイルを動的にコンパイルし、必要な機能を実現することができます.
  • でツールモジュールを書き、registerメソッド
  • を定義しました.
    
    function register(options) {
    
      require.extensions[VUE_EXT] = (module, file) => {
    
        let fileString = fs.readFileSync(file, 'utf8');
    
        let script = compile(fileString, file);
    
        console.log(script);
    
        return module._compile(script, file);
    
      };
    
      return true;
    
    }
    
    
  • compile部分コードは以下の
  • である.
    
    function compile(content, file) {
    
      let vue = {};
    
      let selections = ['script', 'template', 'style'];
    
      var parts = vueCompiler.parseComponent(content, {
    
        pad: "space"
    
      });
    
      for (let section of selections) {
    
        let tempPart = parts[section];
    
        let content = getContent(tempPart, path.dirname(file));
    
        vue[section] = content;
    
      }
    
      let result = require('babel-core').transform(vue.script, {
    
        plugins: ['transform-es2015-modules-commonjs']
    
      });
    
      vue.script = result.code + injectTemplate(vue.template);
    
      return vue.script;
    
    }
    
    function getContent(part, filePath) {
    
      if(!part){
    
        return "";
    
      }
    
      return part.src ?
    
        loadSrc(part.src, filePath) :
    
        part.content
    
    }
    
    
    
    function loadSrc(src, filePath) {
    
      var dir = path.dirname(filePath)
    
      var srcPath = path.resolve(dir, src);
    
      try {
    
        return fs.readFileSync(srcPath, 'utf-8')
    
      } catch (e) {
    
        console.log("fail to load");
    
      }
    
    }
    
    

      は主にvue-template-compilerというモジュールを使用しており、vue単一ファイルのtemplate、script、style部分をそれぞれ抽出することができます.
  • template部分を
  • に注入する
    
    function injectTemplate(template) {
    
      let js = [
    
        '',
    
        'var __vue__options__ = (module.exports.__esModule) ?',
    
        'module.exports.default : module.exports;',
    
        '__vue__options__.template = ' + JSON.stringify(template) + ';',
    
        '',
    
      ];
    
      return js.join(os.EOL);
    
    }
    
    
  • importの問題を解決するために、babelのtransform-es 2015-modules-commonjsプラグインを使用してes 6モジュールをcommonjsモジュール
  • に変換します.
    
    let result = require('babel-core').transform(vue.script, {
    
        plugins: ['transform-es2015-modules-commonjs']
    
      });
    
    
  • 最後のscriptコードをmodule._に配置します.compileで実行します.
  • 書きたてのこのモジュールを導入して
  • を試してみましょう.
    
    require("babel-register");
    
    require("vue-register").register();
    
    const component = require("./src/components/affix/index.js");
    
    console.log(component);
    
    
  • は、vueコンポーネントのexportセクションを取得することができ、そこからpropsセクションを抽出することができる.

  • これでrequireにフックを追加してvueファイルを動的にコンパイルする機能が完了し、babel-registerもrequireファイルを動的にbabelでコンパイルするようにしました.
    文字列読み込みの使用
    私が書いたツールを使ってrequireのすべてのコンポーネントに行ったとき、また別の問題が発生しました.
    我々のフロントエンドコンポーネントライブラリの一部のコンポーネントはいくつかの補助ツール関数に依存し、一部のツール関数はwindowオブジェクトを使用しているが、node環境にはwindowオブジェクトはない.ここまで、この道は通れなくなり、props属性ごとのコメントも得られず、道を変えるしかありません.
    私が考えたのはfsを使うことです.readFileSyncは、コンポーネントコード文字列を取得し、propsに一致して完全なprops文字列を取得し、props文字列コードを実行してpropsオブジェクトを取得します.長い間困っていた問題は「props:{」から、どうやって終わりの「}」にマッチするのか、このような正則をどう書くのか、私は最終的に最もlow的な方法を使って、「props:{」から遍歴して、「{」と「}」の個数を記録しました.最初の「{」と一致する「}」に遭遇するまで、このprops文字列のすべてのコメントをsnippetsのdescriptionとして取得しました.
    
    //   string   props
    
    let getProps = (str) => {
    
            var lIndex = 0,
    
                RIndex = 0,
    
                sp = str.split(/props\s*:\s*{/)[1],
    
                i = 0;
    
            if (!sp) {
    
                return {}
    
            }
    
            while (lIndex >= RIndex) {
    
                lIndex += sp[i] === "{" ? 1 : 0;
    
                RIndex += sp[i] === "}" ? 1 : 0;
    
                i++;
    
            }
    
            var propString = '{' + sp.substring(0, i - 1) + '}';
    
            return {
    
                propsData: eval('(' + propString + ')'),
    
                description: propString.match(/(?:^|
    |\r)\s*\/\/.*(?:\r|
    |$)/g) || [] } }

    注意:eval('('+propString+'))を使用すると、文としてではなくカッコ内の式を強制的にオブジェクトに変換できます.
  • propsを取得した後、snippetsを押す.jsonのフォーマット出力
  • 
        //         props,  snippets  
    
    let readProps = (componentMap) => {
    
        let snippets = {};
    
        var ComponentNames = Object.keys(componentMap);
    
        ComponentNames.forEach(name => {
    
            var fileString = fs.readFileSync(componentMap[name], {
    
                encoding: 'utf8'
    
            });
    
            var parts = vueCompiler.parseComponent(fileString, {
    
                pad: "space"
    
            });
    
            var tempContent = fileString;
    
            if (parts && parts.script) {
    
                tempContent = parts.script.content;
    
            }
    
            let props = {};
    
            try {
    
                props = getProps(tempContent);
    
            } catch (err) {
    
                // console.error(name,err);       
    
            }
    
            let propsDescription = props.description ? props.description.join(",").replace(/\/\//g, "") : "";
    
            let a = [];
    
            for (let key in props.propsData) {
    
                if (props.propsData[key].type !== Boolean) {
    
                    a.push(`:${key} ="${key}"`);
    
                }
    
            }
    
            const kebabName = hyphenate(name);
    
            snippets[name] = {
    
                prefix: name,
    
                body: [
    
                    `<${kebabName}`,
    
                    ...a,
    
                    `>${kebabName}>`
    
                ],
    
                description: `${kebabName}${propsDescription}`,
    
            }
    
        });
    
        return snippets;
    
    }
    
    
  • は、生成するコンテンツをsnippetsプラグインプロジェクトのsnippetsに書き込む.json中
  • 
    //    ,            
    
    let writeFile = (file) => {
    
            return new Promise((res, rej) => {
    
                (async function () {
    
                    await fs.writeFile("plugin/spui-snippets-master/snippets/snippets.json", JSON.stringify(file), (err) => {
    
                        if (err) rej(err)
    
                    })
    
                    res('success');
    
                })()
    
            })
    
        }
    
    

    4.プラグインの発行
      最後にプラグインのアップロード、登録について、tokenの申請など公式ドキュメントを直接参照https://code.visualstudio.com/docs/extensions/publish-extension.vsceをグローバルにインストールし、プラグインディレクトリの下でvsce publishを実行するとプラグインをアップロードできます.プラグインのアップロードをプラグインsnippetsに追加することを考えています.jsonの構築プロセスにおいて、最終的に実現する効果は、node a.jsを実行してprops読み取りをワンタッチで完了することである、snippets.jsonの構築、snippetプラグインのアップロード.
      ここではnodeのchild_を使用していますプロセスモジュールはサブプロセスを誘導し,exec法を用いてpublishというサブプロセス操作を完了する.execは3つのパラメータを受信:(command[,options][callback])、commandはshellコマンドであり、ここでパブリッシュコマンド'vsce publish minor-p'を実行し、optionsパラメータのcwdによってサブプロセスの現在の作業ディレクトリを設定し、process.cwd()は親プロセスの現在のディレクトリであり、サブプロセスの作業ディレクトリをsnippetプラグインディレクトリの下にスペルで設定します.
    
    //    
    
    let publishExtensions = () => {
    
        return new Promise((res, rej) => {
    
            var cmdStr = 'vsce publish minor -p ';
    
            var cmdOption = {
    
                cwd: process.cwd() + "/plugin/spui-snippets-master"
    
            }
    
            exec(cmdStr, cmdOption, function (err, stdout, stderr) {
    
                if (err) {
    
                    console.log(err);
    
                } else {
    
                    res('success');
    
                }
    
            });
    
        })
    
    }
    
    

    ジルコニウム最終呼び出しシリーズメソッド
    
    async function creatSnippets() {
    
        try {
    
            let componentsMap = Object.assign(fileDisplay('./src/components'), fileDisplay('./src/b-component'));
    
            await writeFile(readProps(componentsMap));
    
            console.log(`Successfully created snippets`);
    
            await publishExtensions();
    
            return console.log(`Successfully publish snippets`);
    
        } catch (err) {
    
            console.error(err);
    
        }
    
    }
    
    creatSnippets();
    
    

    vue-registerソースコード