Построить универсальные леса

внешний интерфейс GitHub Командная строка Yeoman

Оригинальный адрес:GitHub.com/jiang Tao/Первоначально…, Пожалуйста, укажите источник.

В конце 2016 года мои коллеги говорили о строительных лесах. В связи с деятельностью компании多样性, передняя часть灵活性, поэтому мы должны думать о более общих лесах. Вместо того, чтобы постоянно тратить время на разработку передовых технологий配置начальство. тогдаchef-cliродившийся. В начале 2018 года я разобрал и подытожил дела прошедшего года, и заново усилил исходные лесаproject-next-cli, не только для удовлетворения потребностей нашей команды, но и потребностей других.

project-next-cli

Целевые пользователи:

  • Бизнес компании сложен, но есть определенное накопление
  • Подбрасывание одноклассников и команды
  • Разрабатывайте с большим количеством шаблонов разработки на github

image

развитие

С тех пор, как я начинал как фронтенд (13 лет), фронтенд в последние годы стремительно развивается.Основные показатели:

Примечания: происходит следующий процесс разработки, пожалуйста, не путайте порядок появления [закрой лицо]

  • Библиотеки/фреймворки: jQuery, backbone, angular, react, vue
  • Модульный: commonjs, AMD(CMD), UMD, модуль es
  • Диспетчер задач: скрипты npm, grunt, gulp
  • Сборщики модулей: r.js, webpack, rollup, browserify
  • Препроцессоры CSS: Sass, Less, Stylus, Postcss
  • Статическая проверка: поток/машинопись
  • Тестовые инструменты: мокко, жасмин, джест, ава
  • Инструменты обнаружения кода: eslint, jslint

развивать

Когда мы на самом деле разрабатываем, мы сталкиваемся с различными бизнес-требованиями (сценариями) и выбираем различные технологические стеки в соответствии с требованиями и сценариями.Из-за технического прогресса и ограничений различных сред выполнения браузера нам необходимо настроить соответствующую среду и т. д., ведет нас к удовлетворению потребностей бизнеса.

Нарисуйте картинку, чтобы представить взаимосвязь между бизнесом, конфигурацией (окружающей средой) и технологией.

image

Front-end инженер по настройке

Таким образом, Минцзянь начал новую карьеру, инженер по настройке внешнего интерфейса O (∩_∩) O~

Статус сообщества

специальные леса

В сообществе есть большое количество специализированных фреймворков, которые в основном заточены под целевую задачу. такие как следующие леса

  1. vue-cli

vue-cliОбеспечьте разработку с помощью vuewebpack, pwaВ ожидании шаблона, эта статья относится к лесамvue-cliреализация.

  1. dva-cli

dva-cliВ основном дляdvaЛеса для развития

  1. labrador

labradorэто微信小程序Компонентная среда разработки, хотя апплет уже поддерживает компоненты, другие функции скаффолда также очень хороши. Кому интересно, могут узнать.

В сообществе есть много отличных специфических лесов, которые здесь не перечислены. Популярность фронтенд-сообщества позволила мне использовать суть фронтенда и продолжать двигаться вперед.

Универсальные леса

  1. yeoman

yeomanЭто надежный и универсальный каркас с набором инструментов, но yeoman выпускает указанное имя пакета и использует его инструменты разработки. может быть конкретнымНажмите здесь, чтобы увидеть правила добавления генератора yoman

Намерение и цели развития

Из-за определенной формы финансовых компаний, различных типов бизнеса и итераций развития передовых технологий он родился, чтобы следить за развитием сообщества и лучше достигать следующих целей.

  • Займитесь делом: сосредоточенно, стабильно, быстро
  • Спецификация команды: спецификация кода, процесс выпуска, непрерывная интеграция/доставка/развертывание
  • Осадки: постоянное и стабильное внедрение новых технологий
  • Преимущество: меньше сверхурочной работы, меньше времени на сборку колес, полные ключевые показатели эффективности и более значимые вещи.

готовность к реализации

Опираясь на Github, согласноGithub APIдобиться следующим образом:

  1. получить предмет
curl -i https://api.github.com/orgs/project-scaffold/repos
  1. получить версию
curl -i https://api.github.com/repos/project-scaffold/cli/tags

реализовать логику

в соответствии сgithub apiПолучив список проектов и номер версии, вы можете сделать общие леса.Следующий код является основным кодом для легкого понимания.

общий дизайн

  1. Спецификация
  • Разработка скаффолдинга с помощью Node, выбор версии>=6.0.0
  • Используйте асинхронную/ожидающую разработку для решения проблемы асинхронного обратного вызова
  • Компилировать с помощью Babel
  • Канонический код с использованием ESLint
  1. Функции

подчиниться单一职责原则, каждый файл представляет собой отдельный модуль, решающий независимые задачи. Можно свободно комбинировать для достижения повторного использования. Вот окончательная структура каталогов:

├── LICENSE
├── README.md
├── bin
│   └── project
├── package.json
├── src
│   ├── clear.js
│   ├── config.js
│   ├── helper
│   │   ├── metalAsk.js
│   │   ├── metalsimth.js
│   │   └── render.js
│   ├── index.js
│   ├── init.js
│   ├── install.js
│   ├── list.js
│   ├── project.js
│   ├── search.js
│   ├── uninstall.js
│   ├── update.js
│   └── utils
│       ├── betterRequire.js
│       ├── check.js
│       ├── copy.js
│       ├── defs.js
│       ├── git.js
│       ├── loading.js
│       └── rc.js
└── yarn.lock

Поговорим о логике реализации каждой команды.

скачать

  1. использовать
project i
  1. логика
Github API ===> 获取项目列表 ===> 选择一个项目 ===> 获取项目版本号 ===> 选择一个版本号 ===> 下载到本地仓库

Если данные на каждом шаге пусты/файл не существует, будет выдано приглашение

  1. основной код

  // 获取github项目列表
  const repos = await repoList();

  choices = repos.map(({ name }) => name);
  answers = await inquirer.prompt([
    {
      type   : 'list',
      name   : 'repo',
      message: 'which repo do you want to install?',
      choices
    }
  ]);
  // 选择的项目
  const repo = answers.repo;

  // 项目的版本号劣币爱哦
  const tags = await tagList(repo);

  if (tags.length === 0) {
    version = '';
  } else {
    choices = tags.map(({ name }) => name);

    answers = await inquirer.prompt([
      {
        type   : 'list',
        name   : 'version',
        message: 'which version do you want to install?',
        choices
      }
    ]);
    version = answers.version;
  }
  // 下载
  await download([repo, version].join('@'));

построить проект

  1. использовать
project init
  1. логика
获取本地仓库列表 ===> 选择一个本地项目 ===> 输入基本信息 ===> 编译生成到临时文件 ===> 复制并重名到目标目录

Если данные на каждом шаге пусты/файл не существует/сгенерированный каталог был продублирован, будет выдано подсказка

  1. основной код

  // 获取本地仓库项目
  const list = await readdir(dirs.download);

  // 基本信息
  const answers = await inquirer.prompt([
    {
      type   : 'list',
      name   : 'scaffold',
      message: 'which scaffold do you want to init?',
      choices: list
    }, {
      type   : 'input',
      name   : 'dir',
      message: 'project name',
      // 必要的验证
      async validate(input) {
        const done = this.async();

        if (input.length === 0) {
          done('You must input project name');
          return;
        }

        const dir = resolve(process.cwd(), input);

        if (await exists(dir)) {
          done('The project name is already existed. Please change another name');
        }

        done(null, true);
      }
    }
  ]);
  const metalsmith = await rc('metalsmith');
  if (metalsmith) {
    const tmp = `${dirs.tmp}/${answers.scaffold}`;
    // 复制一份到临时目录,在临时目录编译生成
    await copy(`${dirs.download}/${answers.scaffold}`, tmp);
    await metal(answers.scaffold);
    await copy(`${tmp}/${dirs.metalsmith}`, answers.dir);
    // 删除临时目录
    await rmfr(tmp);
  } else {
    await copy(`${dirs.download}/${answers.scaffold}`, answers.dir);
  }

Механизм шаблонов компилирует и реализует основной код следующим образом:

// metalsmith逻辑
function metal(answers, tmpBuildDir) {
    return new Promise((resolve, reject) => {
    metalsmith
	  .metadata(answers)
      .source('./')
      .destination(tmpBuildDir)
      .clean(false)
      .use(render())
      .build((err) => {
        if (err) {
          reject(err);
          return;
        }
        resolve(true);
      });
  });
}
// metalsmith render中间件实现
function render() {
    return function _render(files, metalsmith, next) {
    const meta = metalsmith.metadata();

    /* eslint-disable */
    
    Object.keys(files).forEach(function(file){
      const str = files[file].contents.toString();

      consolidate.swig.render(str, meta, (err, res) => {
        if (err) {
          return next(err);
        }

        files[file].contents = new Buffer(res);
        next();
      });
    })
    
  }
}

обновить/понизить версию

  1. использовать
project update
  1. логика
获取本地仓库列表 ===> 选择一个本地项目 ===> 获取版本信息列表 ===> 选择一个版本 ===> 覆盖原有的版本文件

Если данные на каждом шаге пусты/файл не существует, будет выдано приглашение

  1. основной код
  // 获取本地仓库列表
  const list = await readdir(dirs.download);

  // 选择一个要升级的项目
  answers = await inquirer.prompt([
    {
      type   : 'list',
      name   : 'scaffold',
      message: 'which scaffold do you want to update?',
      choices: list,
      async validate(input) {
        const done = this.async();

        if (input.length === 0) {
          done('You must choice one scaffold to update the version. If not update, Ctrl+C');
          return;
        }

        done(null, true);
      }
    }
  ]);

  const repo = answers.scaffold;

  // 获取该项目的版本信息
  const tags = await tagList(repo);

  if (tags.length === 0) {
    version = '';
  } else {
    choices = tags.map(({ name }) => name);

    answers = await inquirer.prompt([
      {
        type   : 'list',
        name   : 'version',
        message: 'which version do you want to install?',
        choices
      }
    ]);
    version = answers.version;
  }
  // 下载覆盖文件
  await download([repo, version].join('@'))

настроить

Конфигурация используется для получения основных настроек скаффолда, таких как реестр, тип и другая основная информация.

  1. использовать
project config set registry koajs # 设置本地仓库下载源

project config get registry # 获取本地仓库设置的属性

project config delete registry # 删除本地设置的属性
  1. логика
判定本地设置文件存在 ===> 读/写

Если данные на каждом шаге пусты/файл не существует, будет выдано приглашение

  1. основной код
switch (action) {
    case 'get':
      console.log(await rc(k));
      console.log('');
      return true;

    case 'set':
      await rc(k, v);
      return true;

    case 'remove':
      await rc(k, v, true);
      return true;

    default:
      console.log(await rc());

поиск

Найдите список проектов в удаленном репозитории github.

  1. использовать

project search

  1. логика
获取github项目列表 ===> 输入搜索的内容 ===> 返回匹配的列表

Если данные на каждом шаге пусты, будет выдано приглашение

  1. основной код
 const answers = await inquirer.prompt([
    {
      type   : 'input',
      name   : 'search',
      message: 'search repo'
    }
  ]);

  if (answers.search) {
    let list = await searchList();

    list = list
      .filter(item => item.name.indexOf(answers.search) > -1)
      .map(({ name }) => name);

    console.log('');
	  if (list.length === 0) {
		  console.log(`${answers.search} is not found`);
	  }
	  console.log(list.join('\n'));
	  console.log('');
  }

Суммировать

Вышеупомянутое является предысторией этой общей структуры леса.Для пользователей и конкретных реализаций леса в настоящее время имеют некоторые области, которые можно оптимизировать:

  1. Разные источники, храните разные файлы
  2. Поддержка автономной функции

Жесткий широкий: если вы чувствуетеproject-next-cliПростота в использовании, добро пожаловать в звезду и добро пожаловать в форк для обслуживания.