задний план
В повседневной работе есть много небольших программ, настроенных с использованием одного и того же шаблона, поэтому я хочу создать инструмент для создания шаблонов и создать соответствующие небольшие программы на основе шаблона, а обычные небольшие программы написаны с использованием фреймворка mpvue, поэтому сначала обратитесь к принципу Vue-cli. Зная принцип, изготовление опалубочных лесов по индивидуальному заказу, безусловно, будет более эффективным.
Прежде чем говорить о коде, давайте сначала рассмотрим использование Vue-cli, Обычно мы используем пакет шаблонов webpack и вводим следующий код.
vue init webpack [project-name]
После выполнения этого кода система автоматически загрузит пакет шаблона, а затем задаст нам несколько вопросов, таких как имя шаблона, автор, использовать ли eslint, использовать ли npm или yarn для сборки и т. д. Когда на все вопросы будут даны ответы , мы начнем Генерировать проект строительных лесов.
Скачиваем исходники, нажимаем на репозиторий исходниковздесь, скаффолдинг, который обычно используется, все еще версии 2.0.Следует отметить, что ветка по умолчанию находится на dev, а версия 3.0 — на dev.
Давайте сначала посмотрим на package.json, в файле есть такой абзац
{
"bin": {
"vue": "bin/vue",
"vue-init": "bin/vue-init",
"vue-list": "bin/vue-list"
}
}
Видно, что команда, которую мы используемvue init
, должно быть изbin/vue-init
Этот файл, давайте посмотрим на содержимое этого файла далее
bin/vue-init
const download = require('download-git-repo')
const program = require('commander')
const exists = require('fs').existsSync
const path = require('path')
const ora = require('ora')
const home = require('user-home')
const tildify = require('tildify')
const chalk = require('chalk')
const inquirer = require('inquirer')
const rm = require('rimraf').sync
const logger = require('../lib/logger')
const generate = require('../lib/generate')
const checkVersion = require('../lib/check-version')
const warnings = require('../lib/warnings')
const localPath = require('../lib/local-path')
download-git-repo Модуль для скачивания проектов из репозиториев git.
командир может выводить текст на терминал
fs — модуль для чтения и записи файлов узла
Модуль path предоставляет служебные функции для работы с путями к файлам и каталогам.
ora Этот модуль используется для отображения анимации загрузки в терминале.
user-home Получить путь к домашнему каталогу пользователя
tildify преобразует абсолютные пути в волнистые пути, например./Users/sindresorhus/dev → ~/dev
inquirer — модуль ответов командной строки, вы можете сами задавать терминальные вопросы, а затем давать этим ответам соответствующую обработку
rimraf — это команда UNIX, которую можно использоватьrm -rf
модуль
Остальные модули локального пути на самом деле являются некоторыми инструментальными классами, и мы поговорим о них, когда они будут использоваться.
// 是否为本地路径的方法 主要是判断模板路径当中是否存在 `./`
const isLocalPath = localPath.isLocalPath
// 获取模板路径的方法 如果路径参数是绝对路径 则直接返回 如果是相对的 则根据当前路径拼接
const getTemplatePath = localPath.getTemplatePath
/**
* Usage.
*/
program
.usage('<template-name> [project-name]')
.option('-c, --clone', 'use git clone')
.option('--offline', 'use cached template')
/**
* Help.
*/
program.on('--help', () => {
console.log(' Examples:')
console.log()
console.log(chalk.gray(' # create a new project with an official template'))
console.log(' $ vue init webpack my-project')
console.log()
console.log(chalk.gray(' # create a new project straight from a github template'))
console.log(' $ vue init username/repo my-project')
console.log()
})
/**
* Help.
*/
function help () {
program.parse(process.argv)
if (program.args.length < 1) return program.help()
}
help()
Эта часть кода объявляетvue init
использование, если набрано в терминалеvue init --help
или следуйтеvue init
Если длина следующих параметров меньше 1, будет также выведено следующее описание
Usage: vue-init <template-name> [project-name]
Options:
-c, --clone use git clone
--offline use cached template
-h, --help output usage information
Examples:
# create a new project with an official template
$ vue init webpack my-project
# create a new project straight from a github template
$ vue init username/repo my-project
Далее происходит приобретение некоторых переменных
/**
* Settings.
*/
// 模板路径
let template = program.args[0]
const hasSlash = template.indexOf('/') > -1
// 项目名称
const rawName = program.args[1]
const inPlace = !rawName || rawName === '.'
// 如果不存在项目名称或项目名称输入的'.' 则name取的是 当前文件夹的名称
const name = inPlace ? path.relative('../', process.cwd()) : rawName
// 输出路径
const to = path.resolve(rawName || '.')
// 是否需要用到 git clone
const clone = program.clone || false
// tmp为本地模板路径 如果 是离线状态 那么模板路径取本地的
const tmp = path.join(home, '.vue-templates', template.replace(/[\/:]/g, '-'))
if (program.offline) {
console.log(`> Use cached template at ${chalk.yellow(tildify(tmp))}`)
template = tmp
}
Следующим шагом является загрузка и создание шаблона на основе имени шаблона.Если это локальный путь к шаблону, он будет сгенерирован напрямую.
/**
* Check, download and generate the project.
*/
function run () {
// 判断是否是本地模板路径
if (isLocalPath(template)) {
// 获取模板地址
const templatePath = getTemplatePath(template)
// 如果本地模板路径存在 则开始生成模板
if (exists(templatePath)) {
generate(name, templatePath, to, err => {
if (err) logger.fatal(err)
console.log()
logger.success('Generated "%s".', name)
})
} else {
logger.fatal('Local template "%s" not found.', template)
}
} else {
// 非本地模板路径 则先检查版本
checkVersion(() => {
// 路径中是否 包含'/'
// 如果没有 则进入这个逻辑
if (!hasSlash) {
// 拼接路径 'vuejs-tempalte'下的都是官方的模板包
const officialTemplate = 'vuejs-templates/' + template
// 如果路径当中存在 '#'则直接下载
if (template.indexOf('#') !== -1) {
downloadAndGenerate(officialTemplate)
} else {
// 如果不存在 -2.0的字符串 则会输出 模板废弃的相关提示
if (template.indexOf('-2.0') !== -1) {
warnings.v2SuffixTemplatesDeprecated(template, inPlace ? '' : name)
return
}
// 下载并生产模板
downloadAndGenerate(officialTemplate)
}
} else {
// 下载并生生成模板
downloadAndGenerate(template)
}
})
}
}
Давайте взглянемdownloadAndGenerate
Сюда
/**
* Download a generate from a template repo.
*
* @param {String} template
*/
function downloadAndGenerate (template) {
// 执行加载动画
const spinner = ora('downloading template')
spinner.start()
// Remove if local template exists
// 删除本地存在的模板
if (exists(tmp)) rm(tmp)
// template参数为目标地址 tmp为下载地址 clone参数代表是否需要clone
download(template, tmp, { clone }, err => {
// 结束加载动画
spinner.stop()
// 如果下载出错 输出日志
if (err) logger.fatal('Failed to download repo ' + template + ': ' + err.message.trim())
// 模板下载成功之后进入生产模板的方法中 这里我们再进一步讲
generate(name, tmp, to, err => {
if (err) logger.fatal(err)
console.log()
logger.success('Generated "%s".', name)
})
})
}
слишком далеко,bin/vue-init
Только что закончил, самое главное, что делает этот файл, это загрузка и создание шаблонов в соответствии с именем шаблона, но метод загрузки и создания шаблонов не включен.
Скачать шаблон
Метод загрузки, используемый для загрузки шаблона, принадлежитdownload-git-repoмодуль.
Самое основное использование выглядит следующим образом.Параметры здесь хорошо понятны.Первый параметр-это адрес склада,второй-выходной адрес,и требуется ли третий параметрgit clone
, с четырьмя параметрами обратного вызова
download('flipxfx/download-git-repo-fixture', 'test/tmp',{ clone: true }, function (err) {
console.log(err ? 'Error' : 'Success')
})
надrun
Один из упомянутых способов#
Строка на самом деле является использованием этого модуля для загрузки модуля ветки.
download('bitbucket:flipxfx/download-git-repo-fixture#my-branch', 'test/tmp', { clone: true }, function (err) {
console.log(err ? 'Error' : 'Success')
})
Создать шаблон
Генерация шаблонаgenerate
метод вgenerate.js
Среди них мы продолжаем рассматривать
generate.js
const chalk = require('chalk')
const Metalsmith = require('metalsmith')
const Handlebars = require('handlebars')
const async = require('async')
const render = require('consolidate').handlebars.render
const path = require('path')
const multimatch = require('multimatch')
const getOptions = require('./options')
const ask = require('./ask')
const filter = require('./filter')
const logger = require('./logger')
chalk — это модуль, который может изменить цвет вывода терминала.
Metalsmith — библиотека генерации статических сайтов (блогов, проектов)
handlerbars — это компилятор шаблонов, черезtemplate
а такжеjson
, вывести html
async Модуль асинхронной обработки, что-то вроде превращения метода в поток.
объединить библиотеку интеграции механизма шаблонов
multimatch Библиотека для сопоставления строковых массивов
options - это самоопределяемый файл элемента конфигурации
Затем было прописано 2 рендерера, аналогично условному рендерингу виф велсе в вью
// register handlebars helper
Handlebars.registerHelper('if_eq', function (a, b, opts) {
return a === b
? opts.fn(this)
: opts.inverse(this)
})
Handlebars.registerHelper('unless_eq', function (a, b, opts) {
return a === b
? opts.inverse(this)
: opts.fn(this)
})
Далее посмотрите на ключgenerate
метод
module.exports = function generate (name, src, dest, done) {
// 读取了src目录下的 配置文件信息, 同时将 name auther(当前git用户) 赋值到了 opts 当中
const opts = getOptions(name, src)
// 拼接了目录 src/{template} 要在这个目录下生产静态文件
const metalsmith = Metalsmith(path.join(src, 'template'))
// 将metalsmitch中的meta 与 三个属性合并起来 形成 data
const data = Object.assign(metalsmith.metadata(), {
destDirName: name,
inPlace: dest === process.cwd(),
noEscape: true
})
// 遍历 meta.js元数据中的helpers对象,注册渲染模板数据
// 分别指定了 if_or 和 template_version内容
opts.helpers && Object.keys(opts.helpers).map(key => {
Handlebars.registerHelper(key, opts.helpers[key])
})
const helpers = { chalk, logger }
// 将metalsmith metadata 数据 和 { isNotTest, isTest 合并 }
if (opts.metalsmith && typeof opts.metalsmith.before === 'function') {
opts.metalsmith.before(metalsmith, opts, helpers)
}
// askQuestions是会在终端里询问一些问题
// 名称 描述 作者 是要什么构建 在meta.js 的opts.prompts当中
// filterFiles 是用来过滤文件
// renderTemplateFiles 是一个渲染插件
metalsmith.use(askQuestions(opts.prompts))
.use(filterFiles(opts.filters))
.use(renderTemplateFiles(opts.skipInterpolation))
if (typeof opts.metalsmith === 'function') {
opts.metalsmith(metalsmith, opts, helpers)
} else if (opts.metalsmith && typeof opts.metalsmith.after === 'function') {
opts.metalsmith.after(metalsmith, opts, helpers)
}
// clean方法是设置在写入之前是否删除原先目标目录 默认为true
// source方法是设置原路径
// destination方法就是设置输出的目录
// build方法执行构建
metalsmith.clean(false)
.source('.') // start from template root instead of `./src` which is Metalsmith's default for `source`
.destination(dest)
.build((err, files) => {
done(err)
if (typeof opts.complete === 'function') {
// 当生成完毕之后执行 meta.js当中的 opts.complete方法
const helpers = { chalk, logger, files }
opts.complete(data, helpers)
} else {
logMessage(opts.completeMessage, data)
}
})
return data
}
meta.js
Далее, посмотрите на следующий полный метод
complete: function(data, { chalk }) {
const green = chalk.green
// 会将已有的packagejoson 依赖声明重新排序
sortDependencies(data, green)
const cwd = path.join(process.cwd(), data.inPlace ? '' : data.destDirName)
// 是否需要自动安装 这个在之前构建前的询问当中 是我们自己选择的
if (data.autoInstall) {
// 在终端中执行 install 命令
installDependencies(cwd, data.autoInstall, green)
.then(() => {
return runLintFix(cwd, data, green)
})
.then(() => {
printMessage(data, green)
})
.catch(e => {
console.log(chalk.red('Error:'), e)
})
} else {
printMessage(data, chalk)
}
}
Создание пользовательских шаблонов
после чтенияvue-init
По принципу команды настроить пользовательский шаблон на самом деле очень просто, нам нужно сделать всего 2 вещи
- Сначала нам нужно иметь собственный шаблон проекта
- Если вам нужно настроить некоторые переменные, вам нужно
meta.js
среди обычаев
Из-за использования модуля загрузкиdownload-git-repo
Сам модуль поддерживает загрузку на github, gitlab и bitucket, в то время нам нужно только разместить настроенный проект шаблона на удаленном хранилище git.
Поскольку мне нужно определить шаблон разработки апплета, сам mpvue также имеетшаблон быстрого запуска, затем на его основе настраиваем.Сначала делаем форк, создаем новую кастомную ветку и на этой ветке кастомизируем.
Там, где нам нужно настроить полезную библиотеку зависимостей, нам нужно дополнительно использовать less и wxparse
Поэтому мыtemplate/package.json
добавить в
{
// ... 部分省略
"dependencies": {
"mpvue": "^1.0.11"{{#vuex}},
"vuex": "^3.0.1"{{/vuex}}
},
"devDependencies": {
// ... 省略
// 这是添加的包
"less": "^3.0.4",
"less-loader": "^4.1.0",
"mpvue-wxparse": "^0.6.5"
}
}
Кроме того, нам также необходимо настроить правила eslint.Так как используется только стандарт, мы находимся вmeta.js
Среди них можно удалить вопросы в стиле airbnb.
"lintConfig": {
"when": "lint",
"type": "list",
"message": "Pick an ESLint preset",
"choices": [
{
"name": "Standard (https://github.com/feross/standard)",
"value": "standard",
"short": "Standard"
},
{
"name": "none (configure it yourself)",
"value": "none",
"short": "none"
}
]
}
.eslinttrc.js
'rules': {
{{#if_eq lintConfig "standard"}}
"camelcase": 0,
// allow paren-less arrow functions
"arrow-parens": 0,
"space-before-function-paren": 0,
// allow async-await
"generator-star-spacing": 0,
{{/if_eq}}
{{#if_eq lintConfig "airbnb"}}
// don't require .vue extension when importing
'import/extensions': ['error', 'always', {
'js': 'never',
'vue': 'never'
}],
// allow optionalDependencies
'import/no-extraneous-dependencies': ['error', {
'optionalDependencies': ['test/unit/index.js']
}],
{{/if_eq}}
// allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
}
Наконец, мы задаем вопрос о названии апплета в вопросе при построении, и это имя будет установлено в заголовке навигации.
вопрос вmeta.js
добавить в
"prompts": {
"name": {
"type": "string",
"required": true,
"message": "Project name"
},
// 新增提问
"appName": {
"type": "string",
"required": true,
"message": "App name"
}
}
main.json
{
"pages": [
"pages/index/main",
"pages/counter/main",
"pages/logs/main"
],
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#fff",
// 根据提问设置标题
"navigationBarTitleText": "{{appName}}",
"navigationBarTextStyle": "black"
}
}
Наконец, давайте попробуем наш собственный шаблон
vue init Baifann/mpvue-quickstart#custom min-app-project
Суммировать
Настройка вышеперечисленных шаблонов очень проста, и это определенно сложнее в реальных проектах, но в соответствии с этой идеей это должно быть осуществимо. Например, в проекте также размещены некоторые самоинкапсулированные компоненты и т. д., поэтому я не буду здесь вдаваться в подробности. Принципиальный анализ основан на vue-cli 2.0, но на самом деле 3.0 тоже готов к работе.Если будет шанс в будущем, после глубокого понимания, я поделюсь им с вами, спасибо.
Справочная статья
-
Как работает vue-cli]6
Широкая реклама
Эта статья была опубликована вЕженедельный выпуск Mint Front End, Добро пожаловать в Watch & Star ★, пожалуйста, указывайте источник при перепечатке.