【中高級先端必須】手触りで足場を教えてくれます


あしばvue-clicreate-react-appreact-native-cliなどは非常に優秀な足場であり、足場を通じて、私たちは迅速にプロジェクトを初期化することができ、自分でゼロから一歩一歩配置する必要がなく、開発体験を効果的に向上させることができます.これらの足場は非常に優れていますが、実際の応用に合っているとは限りません.独自の足場(または会社共通の足場)をカスタマイズして、開発効率を向上させることができます.
より多くの良質な文章をスタンプすることができます.https://github.com/YvetteLau/...
足場の役割
  • は、他のプロジェクトをコピーして関連コードを削除したり、ゼロからプロジェクトとファイルを作成したりする必要がなく、重複性を低減します.
  • は、インタラクションに基づいてプロジェクト構造およびプロファイルを動的に生成することができる.
  • 多くの人が協力するのが便利で、書類を伝える必要はありません.

  • 実装された機能
    始める前に、自分の足場に必要な機能を明確にする必要があります.vue init template-name project-namecreate-react-app project-name .私たちが今回作成した足場(eos-cli)には、以下の能力があります(足場の名前は何と呼ばれていますか.私はEos黎明の女神を選びました).
  • eos init template-name project-nameリモートテンプレートに従って、1つのプロジェクト(リモートテンプレートは構成可能)
  • を初期化する.
  • eos config set 構成情報
  • を変更する.
  • eos config get []構成情報
  • を表示する.
  • eos --version現在のバージョン番号
  • を表示
  • eos -h

  • 他のcommanderを自分で拡張することができます.この文章は、足場を実現する方法を教えることを目的としています.
    効果の表示
    プロジェクトを初期化
    修正eosrcファイル、vuejs-templateからテンプレートをダウンロード
    使用するサードパーティ製ライブラリ
  • babel-cli/babel-env:構文変換
  • commander:コマンドラインツール
  • download-git-repo:リモートテンプレート
  • をダウンロードするための
  • ini:フォーマット変換
  • inquirer:インタラクティブコマンドラインツール
  • ora:loadingアニメーション
  • を表示
  • chalk:コンソール出力コンテンツスタイル
  • を変更する
  • log-symbols:表示√または× 等のアイコン
  • これらのサードパーティ製ライブラリの説明については、npmで直接説明を表示できますが、ここでは展開しません.
    プロジェクトの初期化npm initを使用して初期化する空のプロジェクト(eos-cli)を作成します.
    インストール依存
    npm install babel-cli babel-env chalk commander download-git-repo ini inquirer log-symbols ora

    ディレクトリ構造
    ├── bin
    │   └── www             //     
    ├── dist
        ├── ...             //    
    └── src
        ├── config.js       //  eos    
        ├── index.js        //       
        ├── init.js         //init command
        ├── main.js         //    
        └── utils
            ├── constants.js //    
            ├── get.js       //    
            └── rc.js        //    
    ├── .babelrc             //babel    
    ├── package.json
    ├── README.md
    

    babel構成
    ES 6構文を用いた開発,babelを用いたエスケープ,.bablerc
    {
        "presets": [
            [
                "env",
                {
                    "targets": {
                        "node": "current"
                    }
                }
            ]
        ]
    }
    eosコマンド
    node.jsにはコマンドライン操作のサポートが内蔵されており、package.jsonbinフィールドでは、コマンド名と関連する実行ファイルを定義できます.package.jsonbinフィールドを追加
    package.json
    {
        "name": "eos-cli",
        "version": "1.0.0",
        "description": "   ",
        "main": "index.js",
        "bin": {
            "eos": "./bin/www"
        },
        "scripts": {
            "compile": "babel src -d dist",
            "watch": "npm run compile -- --watch"
        }
    }

    wwwファイル
    行ヘッダ#!/usr/bin/env nodeは、現在のスクリプトがnodeであることを指定する.jsによる解析
    #! /usr/bin/env node
    require('../dist/main.js');

    グローバル環境へのリンク
    開発中にデバッグを容易にするために、現在のeos-cliディレクトリの下でnpm linkを実行し、eosコマンドをグローバル環境にリンクします.
    プロジェクトの開始
    npm run watch

    コマンドラインの操作commanderを使用してコマンドラインを処理します.
    main
    import program from 'commander';
    import { VERSION } from './utils/constants';
    import apply from './index';
    import chalk from 'chalk';
    
    /**
     * eos commands
     *    - config
     *    - init 
     */
    
    let actionMap = {
        init: {
            description: 'generate a new project from a template',
            usages: [
                'eos init templateName projectName'
            ]
        },
        config: {
            alias: 'cfg',
            description: 'config .eosrc',
            usages: [
                'eos config set  ',
                'eos config get ',
                'eos config remove '
            ]
            
        },
        //other commands
    }
    
    //    init / config   
    Object.keys(actionMap).forEach((action) => {
        program.command(action)
        .description(actionMap[action].description)
        .alias(actionMap[action].alias) //  
        .action(() => {
            switch (action) {
                case 'config': 
                    //  
                    apply(action, ...process.argv.slice(3));
                    break;
                case 'init':
                    apply(action, ...process.argv.slice(3));
                    break;
                default:
                    break;
            }
        });
    });
    
    function help() {
        console.log('\r
    Usage:'); Object.keys(actionMap).forEach((action) => { actionMap[action].usages.forEach(usage => { console.log(' - ' + usage); }); }); console.log('\r'); } program.usage(' [options]'); // eos -h program.on('-h', help); program.on('--help', help); // eos -V VERSION package.json program.version(VERSION, '-V --version').parse(process.argv); // eos if (!process.argv.slice(2).length) { program.outputHelp(make_green); } function make_green(txt) { return chalk.green(txt); }

    テンプレートのダウンロードdownload-git-repoは、Github、Gitlabからリモートウェアハウスをローカルにダウンロードすることをサポートします.
    get.js
    import { getAll } from './rc';
    import downloadGit from 'download-git-repo';
    
    export const downloadLocal = async (templateName, projectName) => {
        let config = await getAll();
        let api = `${config.registry}/${templateName}`;
        return new Promise((resolve, reject) => {
            //projectName          
            downloadGit(api, projectName, (err) => {
                if (err) {
                    reject(err);
                }
                resolve();
            });
        });
    }
    initコマンド
    コマンドラインインタラクション
    ユーザがinitコマンドを実行した後,ユーザに問題を提起し,ユーザの入力を受信し,対応する処理を行う.コマンドラインインタラクションは、inquirerによって実現される.
    inquirer.prompt([
        {
            name: 'description',
            message: 'Please enter the project description: '
        },
        {
            name: 'author',
            message: 'Please enter the author name: '
        }
    ]).then((answer) => {
        //...
    });

    ビジュアル美化
    ユーザが入力した後、テンプレートのダウンロードを開始すると、oraを使用してテンプレートのダウンロード中であることをユーザに提示し、ダウンロードが終了した後も提示する.
    import ora from 'ora';
    let loading = ora('downloading template ...');
    loading.start();
    //download
    loading.succeed(); //  loading.fail();

    index.js
    import { downloadLocal } from './utils/get';
    import ora from 'ora';
    import inquirer from 'inquirer';
    import fs from 'fs';
    import chalk from 'chalk';
    import symbol from 'log-symbols';
    
    let init = async (templateName, projectName) => {
        //     
        if (!fs.existsSync(projectName)) {
            //     
            inquirer.prompt([
                {
                    name: 'description',
                    message: 'Please enter the project description: '
                },
                {
                    name: 'author',
                    message: 'Please enter the author name: '
                }
            ]).then(async (answer) => {
                //         
                //      ,      
                let loading = ora('downloading template ...');
                loading.start();
                downloadLocal(templateName, projectName).then(() => {
                    loading.succeed();
                    const fileName = `${projectName}/package.json`;
                    if(fs.existsSync(fileName)){
                        const data = fs.readFileSync(fileName).toString();
                        let json = JSON.parse(data);
                        json.name = projectName;
                        json.author = answer.author;
                        json.description = answer.description;
                        //         package.json   
                        fs.writeFileSync(fileName, JSON.stringify(json, null, '\t'), 'utf-8');
                        console.log(symbol.success, chalk.green('Project initialization finished!'));
                    }
                }, () => {
                    loading.fail();
                });
            });
        }else {
            //      
            console.log(symbol.error, chalk.red('The project already exists'));
        }
    }
    module.exports = init;
    config構成
    eos config set registry vuejs-templates

    config構成では、他の倉庫を使用するテンプレートをサポートします.たとえば、vuejs-templatesの倉庫をテンプレートとして使用できます.これには、テンプレートの更新に足場を再パブリッシュする必要がなく、ユーザーが再インストールする必要がなく、ダウンロードターゲットを自由に選択できるというメリットがあります.
    config.js
    //    .eosrc    (       )
    import { get, set, getAll, remove } from './utils/rc';
    
    let config = async (action, key, value) => {
        switch (action) {
            case 'get':
                if (key) {
                    let result = await get(key);
                    console.log(result);
                } else {
                    let obj = await getAll();
                    Object.keys(obj).forEach(key => {
                        console.log(`${key}=${obj[key]}`);
                    })
                }
                break;
            case 'set':
                set(key, value);
                break;
            case 'remove':
                remove(key);
                break;
            default:
                break;
        }
    }
    
    module.exports = config;

    rc.js
    .eosrcファイルの削除
    import { RC, DEFAULTS } from './constants';
    import { decode, encode } from 'ini';
    import { promisify } from 'util';
    import chalk from 'chalk';
    import fs from 'fs';
    
    const exits = promisify(fs.exists);
    const readFile = promisify(fs.readFile);
    const writeFile = promisify(fs.writeFile);
    
    //RC      
    //DEFAULTS       
    export const get = async (key) => {
        const exit = await exits(RC);
        let opts;
        if (exit) {
            opts = await readFile(RC, 'utf8');
            opts = decode(opts);
            return opts[key];
        }
        return '';
    }
    
    export const getAll = async () => {
        const exit = await exits(RC);
        let opts;
        if (exit) {
            opts = await readFile(RC, 'utf8');
            opts = decode(opts);
            return opts;
        }
        return {};
    }
    
    export const set = async (key, value) => {
        const exit = await exits(RC);
        let opts;
        if (exit) {
            opts = await readFile(RC, 'utf8');
            opts = decode(opts);
            if(!key) {
                console.log(chalk.red(chalk.bold('Error:')), chalk.red('key is required'));
                return;
            }
            if(!value) {
                console.log(chalk.red(chalk.bold('Error:')), chalk.red('value is required'));
                return;
            }
            Object.assign(opts, { [key]: value });
        } else {
            opts = Object.assign(DEFAULTS, { [key]: value });
        }
        await writeFile(RC, encode(opts), 'utf8');
    }
    
    export const remove = async (key) => {
        const exit = await exits(RC);
        let opts;
        if (exit) {
            opts = await readFile(RC, 'utf8');
            opts = decode(opts);
            delete opts[key];
            await writeFile(RC, encode(opts), 'utf8');
        }
    }

    パブリッシュnpm publishは、本足場をnpmにパブリッシュする.他のユーザーは、npm install eos-cli -gを介してグローバルにインストールできます.eosコマンドを使用できます.
    プロジェクトアドレス
    本プロジェクトの完全なコードはスタンプしてください:https://github.com/YvetteLau/...
    本文を編纂して、一定の時間を費やしましたが、この過程で、私も多くの知識を学びました.皆さん、貴重な時間を費やして本文を読んでくれてありがとう.もし本文があなたに少し助けたり啓発したりしたら、あなたの称賛とスターをけちけちしないでください.あなたのは私の前進の最大の原動力に違いありません.https://github.com/YvetteLau/...
    参考記事:
    [1]npm依存文書(https://www.npmjs.com/package...
    ご指摘ありがとうございます.
    参考記事を追加:[フロントエンド足場を簡単に構築ICE](https://link.juejin.im/?targe...
    本人の公衆番号に注目することを推薦します