------**Предисловие**--------------
Строительные леса — это рабочая платформа, созданная для обеспечения бесперебойного хода каждого строительного процесса. Мы используем скаффолдинг для быстрого создания проектов, чтобы сэкономить время и повысить эффективность разработки.Например, у egg, vue и react есть скаффолдинг, который может быстро генерировать фреймворковый проект и настраивать различные параметры.
~~~Функции, которые, как мы ожидаем, будут реализованы с помощью разрабатываемого инструмента построения лесов, могут быть следующими:
- Реализация может запускать код прямо из командной строки
- Реализация может быть установлена с помощью npm
npm install lee-cli -g - Инициализировать проект по шаблону
lee-cli create project-name - Вытягивание кода библиотеки шаблонов
- Инициализировать файл конфигурации
lee-cli config set repo repo-name
1. Необходимые знания и модули, которые необходимо использовать:
Друзья, которые использовали vue-cli или react scaffolding, мы знаем, что мы можем использовать scaffolding для быстрого создания относительного проекта vue или react.Этапы создания, например, vue:
~~~~~~ Приходите, чтобы вспомнить или просмотреть, студенты, которые не знают, могут также взглянуть, конечно, те, кто знает, могут пропустить карту памяти и перейти непосредственно к официальной части~~~~~~~ ~~~~~~~~ ~~~~~~~
Поскольку код выполняется в среде узла, узел необходимо установить заранее, поскольку мы получаем код из github, вам также необходимо знать некоторые знания git~~~
Введите в командной строке следующее: Конечно, это зависит от установленной среды узла:
# 1)全局安装 ,可以在任意目录下执行 vue 这条命令
npm install -g vue-cli
# 2)选择一个工作目录,并且用cmd进入该目录,创建你一个项目名称为 first-vue-project 的 vue 项目
vue create first-vue-project
# 运行vue项目
cd first-vue-project
npm run serve
При установке по описанному выше процессу мы видим, что в первую очередь наш скаффолдинг должен быть исполняемым в командной строке и может парсить вводимые пользователем параметры.Есть возможность парсить параметр create) и когда вы нажимаем Enter, появляется следующая картинка: Есть два варианта по умолчанию\Manually select features.После выбора нажать Enter появится эффект загрузки, маленькие значки и т.д., вы можете увидеть это после успешной установки.Содержимое файла на рис. 1-3,
(Рисунок 1-1)
(Рисунок 1-2)
(Рисунок 1-3)
----2, и реализация их скаффолдинга также официально используется для справки в этой статье, так какие модули им нужны? Пожалуйста, ознакомьтесь со следующими модулями:
- командир: анализ параметров --help фактически полагается на него~ Разобрать команды, введенные пользователем
- inquirer: интерактивный инструмент командной строки, с помощью которого вы можете реализовать функцию выбора командной строки
- download-git-repo : загружать файлы с GitHub
- мел : помогите нам нарисовать разные цвета в консоли
- ora: маленькие значки (загрузка, успешное выполнение, предупреждение и т. д.)
- metalsmith: прочитать все файлы, реализовать рендеринг шаблона
- консолидация: единый механизм шаблонов
---- 3. Сценарии применения и преимущества применения
- Он заключается в унификации технологического стека каждого бизнес-направления и формулировании спецификаций, чтобы проблемы можно было решать единым образом, а обновления и итерации можно было выполнять синхронно.
- Повышайте эффективность и предоставляйте больше инструментов для повышения эффективности на унифицированной основе.Эта эффективность — это не только эффективность разработки, но и эффективность всего процесса от разработки до запуска, например, инкапсуляция некоторых бизнес-компонентов и система выпуска. что повышает эффективность запуска.утилиты и т.д.
- Инструмент скаффолдинга удобен для нас, чтобы быстро клонировать кодовую базу на локальный, а также может иметь больше пользовательских вариантов, вводить плагины, необходимые пользователям, и иметь инженерные идеи.
- Используя инструмент скаффолдинга, нам нужна только простая команда, чтобы загрузить проект из кодовой базы на мой локальный, без необходимости каждый раз клонировать адрес ссылки git (этот адрес может быть не запомнен) или копировать каждый раз, когда проект повторно открыт в другой папке
-----**Формальная часть**--------------------------------
Давайте начнем писать код вручную и создадим собственный каркас~~ Выполните шаги: (как поверхностные, так и глубокие) создайте инструмент CLi с нуля, ~~~ Необходимые навыки для архитекторов полного стека ^_^
2. Создайте проект
1. Инициализировать проект
Инициализируем наш проект и устанавливаем нужные нам модули.Мы можем установить все упомянутые выше модули в начале, а можем установить их по одному, когда будем их использовать позже
Создайте собственную пустую папку (lee-cli) для хранения нашего проекта, сначала нужно:
Шаг за шагом введите следующие команды в командную строку текущего каталога:
npm init -y # 初始化package.json
npm install eslint husky --save-dev # eslint是负责代码校验工作,husky提供了git钩子功能
npx eslint --init # 初始化eslint配置文件
2. Структура каталогов самодельных строительных лесов:
├── bin
│ └── www // 全局命令执行的根文件
├── src
│ ├── main.js // 入口文件
│ └── utils // 存放工具方法
| |___constants.js // 存放用户所需要的常量
| |___common.js
│ ├── create.js // create 命令所有逻辑
│ ├── config.js // config 命令所有逻辑
│── .huskyrc // git hook
│── .eslintrc.json // 代码规范校
├── package.json
|__ README.md
3. Создание проекта
- 3.1, файл bin\www Корневой файл выполнения глобальной команды
#!/usr/bin/env node
// 此文件是一个可执行文件
console.log("这是我创建的一个文件,目录:/bin/www");
~~~~~~ps: объяснение кодаи сводка возможных ошибок:
1) #!/usr/bin/env node -> Я хочу выполнить этот файл в среде node этого каталога /user/bin/env в системе, и он должен быть помещен в начало файла.
- 3.2,Добавьте следующую конфигурацию в package.json:
"bin": {
"lee-cli": "./bin/www"
}
Без написания приведенного выше кода мы не можем выполнять наши собственные определенные команды в командном инструменте:
(Рисунок 2-3-1)
~~~~~~ps: объяснение кодаи сводка возможных ошибок:
1)пакет.jsonbin: путь к исполняемому файлу, соответствующему внутренней команде. Многие пакеты имеют один или несколько исполняемых файлов, в которые они хотят поместиться.PATHсередина. (На самом деле, это то, что делает npm исполняемым). Приведенный выше код указывает, что использование команды lee-cli в командном инструменте вызовет файл bin/www.
- 3.3, ссылка на глобальный пакет:
npm link
(Рисунок 2-3-1)
~~~~~~ps: Объяснение кода и сводка возможных ошибок:
1) использоватьnpm link , link связывает пакет npm в любом месте с глобальной средой выполнения, так что пакет npm можно запустить напрямую с помощью командной строки в любом месте.npm linkКоманда реализует глобальный исполняемый файл команд пакета npm, связывая каталоги и исполняемые файлы.
2) Мы можем видеть рисунок 2-3-1 выше, есть ошибка, потому что файл в bin/www:
(Рисунок 2-3-2)
(Рисунок 2-3-3)
так что будьте осторожны#!/usr/bin/env node В начале файла не должно быть пробелов.
#!/usr/bin/env node
console.log("这是我创建的一个文件,目录:/bin/www");
3) Во время выполненияnpm linkСообщается о следующей ошибке:
(Рисунок 2-3-4)
Это потому, что файлы, которые мы создаем при создании файла bin/www, имеют такие расширения, как www.js, но наш код в package.json по-прежнему:"bin": { "lee-cli": "./bin/www" } изменить на"bin": { "lee-cli": "./bin/www.js" }Оба могут.
4. Параметры командной строки, связанные со скаффолдингом
bin/www.js Main.js представлен в файле, а main используется в качестве файла записи в файле www.require('../src/main.js');
#!/usr/bin/env node
// 此文件是一个可执行文件
require('../src/main.js');
4.1 Использование командора
API:Уууу, эта лошадь plus.com/package/com…
Китайский API командира:GitHub.com/recommended/com мужские…
Использование Commander Использование Commander автоматически генерирует справку и анализирует параметры.
Например, мы используем скаффолдинг vue, vue-cli --help
1) Установите модуль
npm i commander
2) Предварительное содержимое src/main.js:
const program = require('commander');
program.version('0.0.1')
.parse(process.argv); // process.argv就是用户在命令行中传入的参数
(Рисунок 2-4-1)
Как показано на рис. 2-4-1 выше, выполнитеlee-cli --helpУже есть оперативный вывод, иlee-cli -Vто, что мы устанавливаем в коде.
3) Динамически получить номер версии
Версия второго шага — это номер версии текущего кли, который мы записали насмерть, нам нужно получить его динамически, а для удобства все константы мы поместили в файл const.js под util
const { name, version } = require('../../package.json');
module.exports = {
name,
version,
};
main.js
const program = require('commander');
const { version } = require('./utils/constants');
program.version(version)
.parse(process.argv); // process.argv就是用户在命令行中传入的参数
~~~~~~ps: Объяснение кода и сводка возможных ошибок:
1) О: process.argv: Для получения дополнительной информации см. соответствующие ссылки:узел будет .capable/api/process…
Свойство process.argv возвращает массив, содержащий аргументы командной строки для запуска процесса Node.js, в:
- Первый элемент массива process.argv[0] — возвращает абсолютный путь, по которому находится исполняемый файл, запустивший процесс Node.js.
- Второй элемент process.argv[1] — путь к исполняемому в данный момент файлу JavaScript.
- Остальные элементы являются другими аргументами командной строки.
4.1.2 Настройка параметров команды Scaffolding
В предисловии мы рассмотрели, что при создании проекта с помощью vue-cli используйте командуvue create first-vue-project
Эти параметры создания являются фиксированным представлением для создания проекта, вы также можете использовать другие команды, такие какvue config set k v
Тогда давайте реализуем командира, чтобы добиться этого!
в утилитах/common.js
// 根据我们想要实现的功能配置执行动作,遍历产生对应的命令
const mapActions = {
create: {
alias: 'c', //别名
description: '创建一个项目', // 描述
examples: [ //用法
'lee-cli create <project-name>'
]
},
config: { //配置文件
alias: 'conf', //别名
description: 'config project variable', // 描述
examples: [ //用法
'lee-cli config set <k> <v>',
'lee-cli config get <k>'
]
},
'*': {
alias: '', //别名
description: 'command not found', // 描述
examples: [] //用法
}}
module.exports = {
mapActions
};
Добавьте следующий контент в main.js:
const { mapActions } = require('./utils/common');
// Object.keys()
Reflect.ownKeys(mapActions).forEach((action)=>{
program.command(action) //配置命令的名字
.alias(mapActions[action].alias) // 命令的别名
.description(mapActions[action].description) // 命令对应的描述
.action(() => { //动作
if(action === '*'){ //访问不到对应的命令 就打印找不到命令
console.log(mapActions[action].description);
}else{
console.log(action);
// 分解命令 到文件里 有多少文件 就有多少配置 create config
// lee-cli create project-name ->[node,lee-cli,create,project-name]
console.log(process.argv);
}
})});
program.version(version)
.parse(process.argv); // process.argv就是用户在命令行中传入的参数
Вывод: lee-cli создай мой
(Рисунок 2-4-2)
мы смотрим наlee-cli --help
(Рисунок 2-4-3)
Выяснилось, что для нашей конфигурации уже есть директивы create config*.
~~~~~~ps: Объяснение кода и сводка возможных ошибок:
1)Reflect.ownKeys() аналогичен Object.keys(). статический методReflect.ownKeys()Возвращает массив собственных ключей свойств целевого объекта. Reflect.ownKeys() может возвращать собственные свойства, включая свойства Symbol. Object.keys() возвращает ключи свойств, но не включает неперечисляемые свойства. Вы можете обратиться к:cloud.Tencent.com/developer/ это…
2) Команда подкоманды, которую вы можете использовать.commandУкажите подкоманды для вашей команды верхнего уровня. В предыдущем коде мы можем упростить код создания, чтобы увидеть,
program.command('create') //配置命令的名字
.alias('c') // 命令的别名
.description('创建一个项目') // 命令对应的描述
.action(() => {
console.log('此处为create子命令');
})
(Рисунок 2-4-4)
4.1.3 слушать --help
Прослушайте команду --help и распечатайте справочную информацию. Мы можем увидеть примеры в коде предыдущей команды настройки. Это говорит нам об использовании этой подкоманды. Мы можем просмотреть случай с помощью --help.
(Рисунок 2-4-5)
Добавьте код в main.js:
// 监听用户的help事件
program.on('--help', () => {
console.log('\nExamples:');
Reflect.ownKeys(mapActions).forEach((action) => {
mapActions[action].examples.forEach((example) => {
console.log(` ${example}`);
})
})})
в исполнении lee-cli --helpПроверить)
(Рисунок 2-4-6)
4.1.4 Что делает конкретная команда create
Основная функция команды create - вытащить шаблон из репозитория git и загрузить соответствующую версию в локальный.Если есть шаблон, он отобразит шаблон в соответствии с информацией, введенной пользователем, и сгенерирует его для каталог, в котором выполняется текущая команда~
Рисунок (2-4-7)
4.1.4.1 Как реализовать основную функцию create?
Привяжите обработчик действия к команде или напишите команду как отдельный исполняемый файл.
Вышеуказанная фигура (2-4-7) является кодом инструкции конфигурации Main.js. Мы знаем, что когда мы входим в Lee-CLI создайте мою команду, мы можем выводить информацию, и действие находится в действии, потому что мы Можете настроить много подкомандов, таких как Create \ Config \ init ... поэтому мы распространяем конкретные действия в разные файлы, вызывая относительный контент, чтение разных имен файлов.
Добавьте код в main.js
.action(() => {
if (action === '*') {
//访问不到对应的命令 就打印找不到命令
console.log(mapActions[action].description);
} else {
console.log(action);
// 分解命令 到文件里 有多少文件 就有多少配置 create config
// lee-cli create project-name ->[node,lee-cli,create,project-name]
console.log(process.argv);
require(path.join(__dirname,action))(...process.argv.slice(3));
}
}
Добавьте код в create.js:
module.exports = (projectName) => {
console.log(`此处是文件${projectName}`);
}
Рисунок (2-4-8)
~~~~~~ps: Объяснение кода и сводка возможных ошибок:
1)require(path.join(__dirname,action))(...process.argv.slice(3));
В действии мы вводим create.js и передаем имя проекта, которое мы ввели в командной строке, в create.js. process.argv.slice(3), также упомянутый ранее, что process.argv возвращает массив, что также видно из рисунка (2-4-8). воплощать в жизньlee-cli c myраспечатка 此处是文件my
4.1.4.2 Вытягивание проекта
На этом этапе нам нужно загрузить наш проект в git или другие проекты в облаке, чтобы получить всю информацию о шаблонах в хранилище.В качестве примера мы возьмем git.
1) Устанавливаем аксиомодуль
npm i axios
2) Добавить код в create.js
const axios = require('axios');
// 1).获取仓库列表
const fetchReopLists = async () => {
// 获取当前组织中的所有仓库信息,这个仓库中存放的都是项目模板
const { data } = await axios.get('https://api.github.com/orgs/lxy-cli/repos'); return data
};
module.exports = async (projectName) => {
let repos = await fetchReopLists();
repos = repos.map((item) => item.name);
console.log(repos);
console.log(`此处是文件${projectName}`);
};
~~~~~~ps: Объяснение кода и сводка возможных ошибок:
1)const { data } = await axios.get('https://api.github.com/orgs/lxy-cli/repos');
Код здесь использует axios.get() для вызова кода, хранящегося в репозитории gitHub Как найти этот адрес? Доступно через API: developer.github.com/v3/.Поскольку мой проектный склад — это организация с двумя складскими проектами, вы можете найти соответствующие правила адресов в соответствующем API. соответствие API:GET /orgs/:org/repos
4.2 Использование inquirer и ora
Мы используем inquirer для добавления опций. Например, в моей организации есть два репозитория, выберите один из них для загрузки, и у нас также есть варианты, когда мы создаем наш vue, используемoraЭтот пакет используется для отображения значка загрузки на терминале, подсказки, отображаемой в начале, и состояния в случае успеха.4.2.1 Использование опросникаИнструмент для взаимодействия пользователя с командной строкой
Может относиться к:Уууу, эта лошадь plus.com/package/in Q…
1) Установите модуль опросника
npm i inquirer
2) Объясните, используя случай вопрошающегоvar inquirer = require('inquirer')
inquirer.prompt([
{
type: 'confirm',
name: 'test',
message: '你确定使用这个吗?',
default: true
}
]).then((answers) => {
console.log('结果为:')
console.log(answers)
})
Выполнение заказаlee-cli c myРезультат:
(Рисунок 2-4-11)
На рис. 2-4-11 выше мы видим, что ? 这是一个测试项目?(Y/n) Мы можем выбрать Y, чтобы он отображался первым, потому что наш параметрtype: 'confirm',
(Рисунок 2-4-12)
Мы выводим в коде inquirer.prompt(). Результатом является обещание, и используется значение по умолчанию выше. Если мы хотим выбрать другой склад, мы можем использовать выбор, тип: «список»,
3) В нашем проекте меняем на: create.js code увеличить
const { repo} = await inquirer.prompt([
{
type: 'list',
name:'repo',
message:'请选择一个你要创建的项目',
choices: repos
}
]);
console.log(`我现在选择了那个仓库? ${repo}`);
Выполнение заказаlee-cli c myРезультат:
(Рисунок 2-4-13)
На картинке выше мы видим, сколько их появилось. Пожалуйста, выберите проект, который вы хотите создать. Ниже приведен список наших складов. Нажмите Enter, чтобы выбрать его.
(Рисунок 2-4-14)
~~~~~~ps: Объяснение кода и сводка возможных ошибок:
1) inquirer.prompt (параметр):
{
// 表示提问的类型,下文会单独解释
type: String,
// 在最后获取到的answers回答对象中,作为当前这个问题的键
name: String,
// 打印出来的问题标题,如果为函数的话
message: String|Function,
// 用户不输入回答时,问题的默认值。或者使用函数来return一个默认值。
//假如为函数时,函数第一个参数为当前问题的输入答案。
default: String|Number|Array|Function,
// 给出一个选择的列表,假如是一个函数的话,第一个参数为当前问题的输入答案。
//为数组时,数组的每个元素可以为基本类型中的值。
choices: Array|Function,
// 接受用户输入,并且当值合法时,函数返回true。当函数返回false时,
//一个默认的错误信息会被提供给用户。
validate: Function,
// 接受用户输入并且将值转化后返回填充入最后的answers对象内。
filter: Function,
// 接受当前用户输入的answers对象,并且通过返回true或者false来决定是否当前的问题应该去问。
//也可以是简单类型的值。
when: Function|Boolean,
// 改变渲染list,rawlist,expand或者checkbox时的行数的长度。
pageSize: Number, }
4.2.2 Использование ора
Когда мы загружаем проект в репозиторий gitHub, это занимает определенное время, если нет эффекта загрузки, мы часто будем думать, что это ошибка или какая-то причина, и делаем неправильное действие, чтобы увеличить эффект, чтобы знать, что он скачивается. . .
Вы можете обратиться к:www.npmjs.com/package/ora
1) Установите модуль
npm i ora
2) случай кода, связанный с ora
const spinner = ora('Loading 测试中哈哈哈。。。').start();
setTimeout(() => {
spinner.color = 'red';
spinner.text = 'Loading ora哈哈哈';
// 成功
spinner.succeed('拉取成功');
}, 1000);
(Рисунок 2-4-15)
(Рисунок 2-4-16)
3) Добавьте соответствующий код в utils/common.js.
const ora = require('ora');
// 封装loading效果
const fnLoadingByOra = async (fn, message) => {
const spinner = ora(message);
spinner.start();
let result = await fn();
spinner.succeed(); // 结束loading
return result; }
module.exports = {
mapActions,
fnLoadingByOra
};
4) Измените соответствующий код create.js
const { fnLoadingByOra } = require('./utils/common');
module.exports = async (projectName) => {
let repos = await fnLoadingByOra(fetchReopLists, '正在链接你的仓库...');
repos = repos.map((item) => item.name);
// 使用inquirer 在命令行中可以交互
const { repo} = await inquirer.prompt([
{
type: 'list',
name:'repo',
message:'请选择一个你要创建的项目',
choices: repos
}
]);
console.log(`我现在选择了那个仓库? ${repo}`);}
(Рисунок 2-4-17)
4.3 Версия Get.
У нас будут разные версии при скачивании склада.Например, при скачивании vue там тоже 1.0, 2.0 и т.д., поэтому нам нужны или разные версии склада, чтобы скачать нужную вам версию.
1) Добавить информацию об изменениях в utils/common.js
// 封装loading效果
const fnLoadingByOra = (fn, message) => async (...argv) =>{
const spinner = ora(message);
spinner.start();
let result = await fn(...argv);
spinner.succeed(); // 结束loading
return result; }// 获取仓库(repo)的版本号信息
const getTagLists = async (repo) =>{
const {data} = await axios.get(`https://api.github.com/repos/lxy-cli/${repo}/tags`);
return data;
}
module.exports = {
mapActions,
fnLoadingByOra,
fetchReopLists,
getTagLists
};
2) в create.js
const inquirer = require('inquirer');
const { fnLoadingByOra, fetchReopLists, getTagLists} = require('./utils/common');
module.exports = async (projectName) => {
let repos = await fnLoadingByOra(fetchReopLists, '正在链接你的仓库...')();
repos = repos.map((item) => item.name);
// 使用inquirer 在命令行中可以交互
const { repo} = await inquirer.prompt([
{
type: 'list',
name:'repo',
message:'请选择一个你要创建的项目',
choices: repos
}
]);
let tags = await fnLoadingByOra(getTagLists, `正在链接你的选择的仓库${repo}的版本号...`)(repo);
tags = tags.map((item) => item.name);
console.log(`我现在选择了那个仓库? ${repo}`);
console.log(`仓库 ${repo}的版本信息列表:${tags}`);
}
(Рисунок 2-4-18)
3) Добавьте информацию о версии опции
в create.js
let tags = await fnLoadingByOra(getTagLists, `正在链接你的选择的仓库${repo}的版本号...`)(repo);
tags = tags.map((item) => item.name);
const { tag } = await inquirer.prompt([{
type: 'list',
name: 'tag',
message: '请选择一个该项目的版本下载',
choices: tags
}]);
console.log(`我现在选择了那个仓库? ${repo}`);
console.log(`仓库 ${repo}的版本信息列表:${tag}`);
(Рисунок 2-4-19)
(Рисунок 2-4-20)
4.4 Загрузите проект с GitHub во временную папку
Нам нужно использовать модуль download-git-repo, чтобы фактически загрузить его с GitHub в локальную временную папку.Следует отметить, что адресная среда разных систем отличается.1) Установите модуль
npm i download-git-repo
2) Нам нужно скачать на локальный адрес
Перед загрузкой найдите временный каталог для хранения загруженных файлов и сохраните их для последующего использования.Для обновления проекта мы также можем перезаписать файлы во временном каталоге.
2.1) Добавьте константы в utils/constants.js
Загрузить адрес временного хранилища файлов, потому что разные компьютерные платформы имеют разные адреса временного хранилища
const downloadDirectory = `${process.env[process.platform === 'darwin' ? 'HOME' : 'USERPROFILE']}/.myTemplate`;
console.log(downloadDirectory);
module.exports = {
name,
version,
downloadDirectory
};
~~~~~~ps: Объяснение кода и сводка возможных ошибок:
1)process.platform
process.platform: перечислить среду операционной системы, в которой работает узел, и отображать только информацию, связанную с ядром, например: linux2, darwin, а не «Redhat ES3», «Windows 7», «OSX 10.7» и т. д.
Например, компьютер, которым я пользуюсь:
(Рисунок 2-4-21)
2.2) Получить каталог пользователя
Получите каталог пользователя в соответствии с соответствующей переменной среды и загрузите его во временную папку.
Добавьте код в utils\common.js
const { promisify } = require('util');
const downloadGit = require('download-git-repo');downloadGit = promisify(downloadGit);// 将项目下载到当前用户的临时文件夹下
const downDir = async (repo,tag)=>{
console.log(tag, 'downDir方法');
let project = `lxy-cli/${repo}`; //下载的项目
if(tag){
project += `#${tag}`;
}
// c:/users/lee/.myTemplate
let dest = `${downloadDirectory}/${repo}`;
//把项目下载当对应的目录中
console.log(dest, 'dest的内容。。。。。。。。。。');
console.log(project, 'dest的内容。。。。。。。。。。');
try {
await downloadGit(project, dest);
} catch (error) {
console.log('错误了吗???\n');
console.log(error);
}
return dest;
}
Добавить код и импорт в create.js
// 下载项目到临时文件夹 C:\Users\lee\.myTemplate
const target = await fnLoadingByOra(downDir, '下载项目中...')(repo, tag);
(Рисунок 2-4-22)
Согласно рис. 2-4-22, мы можем видеть, что когда мы выполняемlee-cli c myПри создании проекта выбранvue-tempalte, выберите версию для скачиванияv1.0Я также загрузил во временную папку каталог: загрузите проект во временную папку C:\Users\lee\.myTemplate, чтобы мы могли найти адрес: C:\Users\lee\.myTempalte\vue-tempalte откройте и вы можно увидеть следующий рисунок (рис. 2-4-23): Содержимое, соответствующее нашему адресу github, такое же, как показано на рисунке (рис. 2-4-24)
(Рисунок 2-4-23)
(Рисунок 2-4-24)
~~~~~~ps: Объяснение кода и сводка возможных ошибок:
1)promisify(downloadGit);
Мы знаем, что этот код будетdownloadGit заменен на promise, потому что download-git-repo — это не промис, а мы все используем в проекте async await, и нам нужно самим обернуть его как промис.
4.5 Копируем элементы временной папки в нужную нам директорию
Здесь необходимо использовать модуль ncp, а функцию копирования файлов можно реализовать, установив ncp.
1) Установите модуль
npm i ncp
2) Добавьте методы в utils\common.js
// 复制项目从临时文件到本地工作项目
const copyTempToLoclhost = async (target, projectName) => {
const resolvePath = path.join(path.resolve(), projectName);
// 此处模拟如果仓库中有ask.js就表示是复杂的仓库项目
if (!fs.existsSync(path.join(target, 'ask.js'))) {
await ncp(target, resolvePath);
fse.remove(target);
}else{
//复杂项目
// 1) 让用户填信息
await new Promise((resolve, reject) => {
MetalSmith(__dirname)
.source(target) // 遍历下载的目录
.destination(resolvePath) // 最终编译好的文件存放位置
.use(async (files, metal, done) => {
let args = require(path.join(target, 'ask.js'));
let res = await inquirer.prompt(args);
let met = metal.metadata();
// 将询问的结果放到metadata中保证在下一个中间件中可以获取到
Object.assign(met, res);
// ask.js 只是用于 判断是否是复杂项目 且 内容可以定制复制到本地不需要
delete files['ask.js'];
done();
})
.use((files, metal, done) => {
const res = metal.metadata();
// 获取文件中的内容
Reflect.ownKeys(files).forEach(async (file) => {
// 文件是.js或者.json才是模板引擎
if (file.includes('.js') || file.includes('.json')) {
let content = files[file].contents.toString(); //文件内容
// 我们将ejs模板引擎的内容找到 才编译
if (content.includes('<%')) {
content = await render(content, res);
files[file].contents = Buffer.from(content); //渲染
}
}
})
done();
})
.build((err) => {
if (err) {
reject();
} else {
resolve();
}
})
});
}
}
Добавьте код в файл create.js
await copyTempToLoclhost(target, projectName);
(Рисунок 2-4-25)
Мы нашли ту же команду выбора, что и выше, и обнаружили, что рисунок 2-4-25 имеет то же содержание, что и рисунок 2-4-24 и рисунок 2-4-23.
4.6 Компиляция шаблонов
Когда загружаемый шаблон представляет собой проект, который должен быть настроен пользователем, нам также необходимо скомпилировать шаблон.
Поскольку эта ситуация может принимать разные формы, здесь мы моделируем определенный сложный шаблон, который требует от пользователя выбора пользовательского ввода в командной строке. Сохраните ask.js в одном из хранилищ и поместите параметры командной строки, которые могут быть выполнены с модулем inquirer, чтобы попросить сгенерировать соответствующий файл package.json, потому что в нем используется ejs
1) Установите модуль
npm i metalsmith ejs consolidate
2) Код
Utils \ common.js добавить связанный код
// 复制项目从临时文件到本地工作项目
const copyTempToLoclhost = async (target, projectName) => {
const resolvePath = path.join(path.resolve(), projectName);
// 此处模拟如果仓库中有ask.js就表示是复杂的仓库项目
if (!fs.existsSync(path.join(target, 'ask.js'))) {
await ncp(target, resolvePath);
fse.remove(target);
}else{
//复杂项目
// 1) 让用户填信息
await new Promise((resolve, reject) => {
MetalSmith(__dirname)
.source(target) // 遍历下载的目录
.destination(resolvePath) // 最终编译好的文件存放位置
.use(async (files, metal, done) => {
let args = require(path.join(target, 'ask.js'));
let res = await inquirer.prompt(args);
let met = metal.metadata();
// 将询问的结果放到metadata中保证在下一个中间件中可以获取到
Object.assign(met, res);
// ask.js 只是用于 判断是否是复杂项目 且 内容可以定制复制到本地不需要
delete files['ask.js'];
done();
})
.use((files, metal, done) => {
const res = metal.metadata();
Reflect.ownKeys(files).forEach(async (file) => {
if (file.includes('.js') || file.includes('.json')) {
const content = files[file].contents.toString(); //文件内容
if (content.includes('<%')) {
content = await render(content, res);
files[file].contents = Buffer.from(content); //渲染
}
}
})
done();
})
.build((err) => {
if (err) {
reject();
} else {
resolve();
}
})
});
}}
create.js добавляет код
copyTempToLoclhost(filePath, projectName);
(Рисунок 2-4-26)
(Рисунок 2-4-27)
(Рисунок 2-4-28)
Резюме:
На данный момент начальное завершение использования lee-cli create
Исходная величина:
https://api.github.com/orgs/lxy-cli/reposПользовательские леса, написанные организацией, эталонное значение - анализ идей кода, вы можете заменить адрес ссылки внутри на свой, если это простая копия проекта, вам нужно только изменить адрес ссылки, если это ответственный проект, который нужно настроить, вы можете настроить его по собственной логике модификации, в этом проектеsrc/utils/common.jsметод вcopyTempToLoclhostСложные методы внутри также написаны для собственных проектов. Конечно, в будущем он будет оптимизирован ^_^^_^^_^5. Релиз проекта
Изначально мы написали скаффолдинг инструкций, которые нужно опубликовать на npm.
#当前项目下 切换到官网上
nrm use npm
npm addUser 或者 npm login #登录账号
npm publish #上传项目
Давайте проверим это
----Установочный тест
npm unlink
lee-cli
npm i lee-cli -g
Дополнительные инструкции будут добавлены в будущем, так что следите за обновлениями. . . .
Хотите увидеть полный код:кликните сюда:GitHub.com/Ли Сяоянь…