Открытие технологии Таро: таро-кли

Node.js Командная строка JavaScript Babel
Открытие технологии Таро: таро-кли

предисловие

TaroЭто многотерминальная унифицированная среда разработки, созданная Bump Labs и соответствующая спецификации синтаксиса React.

Используя Taro, мы можем написать только один набор кода, а затем использовать инструмент компиляции Taro для отдельной компиляции исходного кода в коды, которые можно запускать на разных сторонах (апплет WeChat, H5, сторона приложения и т. д.). выполнитьНапиши один раз, запускай много. Более подробную информацию о Таро можно найти в официальной вводной статье.Таро - мультитерминальная среда разработки, или сразу перейдите в репозиторий GitHubNervJS/taroОзнакомьтесь с документацией Taro и сопутствующими материалами.

image

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

Taro 技术揭秘Серия статей постепенно раскроет тайну могущественных функций Таро, позволит вам погрузиться вглубь Таро и понять, как шаг за шагом реализуется Таро.Напиши один раз, запускай многоВ то же время я также надеюсь воспользоваться этой возможностью, чтобы привлечь других и способствовать появлению большего количества проектов с открытым исходным кодом в кругу переднего плана, которые могут решить болевые точки каждого.

Во-первых, мы начнем с инструмента командной строки, отвечающего за инициализацию строительных лесов Taro и построение проекта, который является точкой входа в Taro:@tarojs/cliНачинать.

пакет таро-кли

команда таро

Пакет таро-кли находится по адресуTaroВ каталоге пакетов проекта перейдитеnpm install -g @tarojs/cliПри глобальной установке будет сгенерирована команда таро. В основном отвечает за инициализацию проекта, компиляцию, построение и т. д. Введите таро прямо в командной строке, и вы увидите следующее приглашение:

➜ taro
👽 Taro v0.0.63


  Usage: taro <command> [options]

  Options:

    -V, --version       output the version number
    -h, --help          output usage information

  Commands:

    init [projectName]  Init a project with default templete
    build               Build a project with options
    update              Update packages of taro
    help [cmd]          display help for [cmd]

Здесь вы можете подробно увидеть использование и функции команды таро.

Управление пакетами и публикация

Во-первых, нам нужно понять взаимосвязь между пакетом taro-cli и проектом таро.

После клонирования проекта Taro мы видим, что структура каталогов проекта выглядит следующим образом, и в целом все относительно просто и понятно.

.
├── CHANGELOG.md
├── LICENSE
├── README.md
├── build
├── docs
├── lerna-debug.log
├── lerna.json	 // Lerna 配置文件
├── package.json
├── packages
│   ├── eslint-config-taro
│   ├── eslint-plugin-taro
│   ├── postcss-plugin-constparse
│   ├── postcss-pxtransform
│   ├── taro
│   ├── taro-async-await
│   ├── taro-cli
│   ├── taro-components
│   ├── taro-components-rn
│   ├── taro-h5
│   ├── taro-plugin-babel
│   ├── taro-plugin-csso
│   ├── taro-plugin-sass
│   ├── taro-plugin-uglifyjs
│   ├── taro-redux
│   ├── taro-redux-h5
│   ├── taro-rn
│   ├── taro-rn-runner
│   ├── taro-router
│   ├── taro-transformer-wx
│   ├── taro-weapp
│   └── taro-webpack-runner
└── yarn.lock

TaroПроект в основном состоит из серии пакетов npm, которые расположены в каталоге пакетов проекта. его управление пакетами иBabelКак и проект, весь проект управляется как монорепозиторий, а также используется инструмент управления пакетами.Lerna.

Lerna – это инструмент управления, используемый для оптимизации рабочего процесса кодовых баз с несколькими пакетами, размещенных на git/npm. Он позволяет вам управлять несколькими подпроектами в рамках основного проекта, тем самым устраняя необходимость зависимости нескольких пакетов друг от друга и необходимости быть освобождены при публикации Проблемы с ручным обслуживанием нескольких пакетов.

Более подробную информацию о Lerna можно найти в официальной документации.Lerna: инструмент для управления проектами JavaScript с несколькими пакетами..

Среди более чем дюжины пакетов в каталоге пакетов наиболее часто используемые инструменты командной строки для инициализации и построения проектаtaro-cliявляется одним из них. Запуск из корневого каталога проекта Tarolerna publishПосле команды,lerna.jsonВсе настроенные в нем пакеты будут опубликованы в npm.

Структура каталогов

Структура каталогов пакета taro-cli выглядит следующим образом:

./
├── bin	// 命令行
│   ├── taro		// taro 命令
│   ├── taro-build		// taro build 命令
│   ├── taro-update		// taro update 命令
│   └── taro-init		// taro init 命令
├── package.json
├── node_modules
├── src
│   ├── build.js		// taro build 命令调用,根据 type 类型调用不同的脚本
│   ├── config
│   │   ├── babel.js	// Babel 配置
│   │   ├── babylon.js		// JavaScript 解析器 babylon 配置
│   │   ├── browser_list.js	// autoprefixer browsers 配置
│   │   ├── index.js		// 目录名及入口文件名相关配置
│   │   └── uglify.js
│   ├── creator.js
│   ├── h5.js		// 构建h5 平台代码
│   ├── project.js	// taro init 命令调用,初始化项目
│   ├── rn.js		// 构建React Native 平台代码
│   ├── util		// 一系列工具函数
│   │   ├── index.js
│   │   ├── npm.js
│   │   └── resolve_npm_files.js
│   └── weapp.js		// 构建小程序代码转换
├── templates		// 脚手架模版
│   └── default
│       ├── appjs
│       ├── config
│       │   ├── dev
│       │   ├── index
│       │   └── prod
│       ├── editorconfig
│       ├── eslintrc
│       ├── gitignore
│       ├── index.js	// 初始化文件及目录,copy模版等
│       ├── indexhtml
│       ├── npmrc
│       ├── pagejs
│       ├── pkg
│       └── scss
└── yarn-error.log

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

Как видно из приведенного выше дерева каталогов, в проекте taro-cli не так много файлов, основные каталоги:/bin,/src,/template, выше я подробно отметил функции основных директорий и файлов, а что касается конкретного процесса, то его мы разберем далее.

используемая основная библиотека

  • tj/commander.js Node.jsКомплексное решение с интерфейсом командной строки, вдохновленное Ruby.commander. Он может автоматически анализировать команды и параметры, комбинировать несколько параметров, обрабатывать короткие параметры и т. д. Он мощный и простой в использовании.
  • jprichardson/node-fs-extraДобавлены некоторые новые методы на основе фс нодджей, которые проще в использовании, а также могут копировать шаблоны.
  • chalk/chalkМожет использоваться для управления стилем выходной строки терминала.
  • SBoudrias/Inquirer.jsИнтерактивный инструмент командной строки NodeJ, набор общих пользовательских интерфейсов командной строки для взаимодействия с пользователями.
  • sindresorhus/oraКогда указано состояние загрузки, как может хватить загрузки, а потом добавить перед ним маленький кружок и перевернуть.Если консоль удачная, то как успеха может хватить?Можно еще добавить маленький крючок в перед ним, что и делает ora.
  • SBoudrias/mem-fs-editorПредоставляет ряд API для облегчения работы с файлами шаблонов.
  • shelljs/shelljsShellJS — это расширение Node.js для реализации выполнения команд оболочки Unix.
  • Node.js child_processМодули используются для создания новых дочерних процессов. Результат выполнения дочернего процесса сохраняется в системном кеше (максимум 200 КБ).После завершения выполнения дочернего процесса основной процесс использует функцию обратного вызова для чтения результата выполнения дочернего процесса.

taro init

Основной процесс команды taro init выглядит следующим образом:

image

ввод команды таро

Когда мы устанавливаем пакет taro-cli глобально, в нашей командной строке появляется еще одна команда taro.

$ npm install -g @tarojs/cli

Так как же добавляется команда таро?package.jsonвнутри поля корзины;

"bin": {
    "taro": "bin/taro"
  },

Приведенный выше код указывает, что исполняемый файл, соответствующий команде taro, — bin/taro. npm будет искать этот файл в[prefix]/binСоздайте символическую ссылку в каталоге. В приведенном выше примере таро создаст символическую ссылку[prefix]/bin/taro. так как[prefix]/binКаталог будет добавлен в системную переменную PATH во время выполнения, поэтому при запуске npm вы можете вызывать эти скрипты напрямую через команды без пути.

оprefix, в состоянии пройтиnpm config get prefixПолучать.

$ npm config get prefix
/usr/local

Символические связи между ними можно увидеть более четко с помощью следующих команд:

$ ls -al `which taro`
lrwxr-xr-x  1 chengshuai  admin  40  6 15 10:51 /usr/local/bin/taro -> ../lib/node_modules/@tarojs/cli/bin/taro

подкоманда таро

Выше мы уже знаем, как команда taro работает с пакетом taro-cli после его установки./bin/taroфайлы связаны, так как же taro init и taro build связаны с соответствующими файлами?

Ассоциация команд и анализ параметров

Здесь я должен упомянуть полезный пакет:tj/commander.js Node.jsКомплексное решение с интерфейсом командной строки, вдохновленное Ruby.commander. Он может автоматически анализировать команды и параметры, комбинировать несколько параметров, обрабатывать короткие параметры и т. д. Он мощный и простой в использовании. Для конкретного метода использования, пожалуйста, обратитесь к README проекта.

Что еще более важно, Commander поддерживает обработку подкоманд в стиле git и может автоматически направлять к файлу выполнения команды, названному в определенном формате в соответствии с подкомандой.[command]-[subcommand],Например:

taro init => taro-init
taro build => taro-build

/bin/taroСодержимого файла не так много, а основной код — это только те строки.command()Заказ:

#! /usr/bin/env node

const program = require('commander')
const {getPkgVersion} = require('../src/util')

program
  .version(getPkgVersion())
  .usage('<command> [options]')
  .command('init [projectName]', 'Init a project with default templete')
  .command('build', 'Build a project with options')
  .command('update', 'Update packages of taro')
  .parse(process.argv)

командный метод

использование:.command('init <path>', 'description')

Использование команды немного сложнее, в принципе, она может принимать три параметра, первый - это определение команды, второй - описание команды, а третий - объект вспомогательного оформления команды.

  • Вы можете использовать или [] для изменения параметров команды в первом параметре.
  • Второй параметр является необязательным.
    • Когда второй параметр отсутствует, command.js вернет объект Command, если есть второй параметр, он вернет объект-прототип.
    • Когда action(fn) вызывается со вторым параметром, а action(fn) не вызывается явно, он будет использоватьсяподкомандный режим.
    • Так называемый режим подкоманды,./pm,./pm-install,./pm-searchЖдать. Эти подкоманды находятся в отдельных файлах от основной команды.
  • Третий параметр обычно не используется, он может установить, следует ли отображать использование подкомандного режима.

Обратите внимание на первую строку#!/usr/bin/env node, есть ключевое слово под названиемShebang, если вы не понимаете, вы можете пойти в Сосо.

Парсинг параметров и взаимодействие с пользователями

Как упоминалось ранее, пакет command может автоматически анализировать команды и параметры, а после настройки команд он также может автоматически генерировать команды справки (help) и команды версии (view версии). и черезprogram.argsВы можете получить параметры командной строки, а затем вызывать разные скрипты в соответствии с параметрами.

но когда мы бежимtaro initКак после команды достигается взаимодействие с командной строкой, как показано ниже?

$ taro init taroDemo
Taro即将创建一个新项目!
Need help? Go and open issue: https://github.com/NervJS/taro/issues/new

Taro v0.0.50

? 请输入项目介绍!
? 请选择模板 默认模板

используется здесьSBoudrias/Inquirer.jsдля обработки взаимодействия с командной строкой.

Использование на самом деле очень простое:

const inquirer = require('inquirer')  // npm i inquirer -D

if (typeof conf.description !== 'string') {
      prompts.push({
        type: 'input',
        name: 'description',
        message: '请输入项目介绍!'
      })
}

prompt()Принять данные объекта вопроса, сохранить ввод пользователя в объекте ответа во время взаимодействия между пользователем и терминалом, а затем вернутьPromise,пройти черезthen()Получите этот объект ответа. так легко!

Таким образом, такая информация, как имя, номер версии, описание и другая информация о новом проекте, может быть непосредственно вставлена ​​в шаблон проекта через терминальное взаимодействие для улучшения процесса взаимодействия.

Конечно, интерактивная задача этим не ограничивается, и вы можете добавить больше интерактивных задач в зависимости от ситуации в вашем собственном проекте. Сила inquirer.js заключается в том, что он поддерживает множество типов взаимодействий, помимо простыхinputconfirm,list,password,checkboxи т. д. Для получения подробной информации обратитесь к технической документации проекта.README.

Кроме того, вы все еще находитесь в процессе выполнения асинхронной операции, вы также можете использоватьsindresorhus/oraДобавим эффект загрузки. использоватьchalk/chalkДобавляйте различные стили в вывод терминала.

Операции с файлами шаблонов

Наконец, работа с файлом шаблона в основном делится на две части:

  • Вставьте ввод в шаблон
  • Создайте соответствующую структуру каталогов по команде, скопируйте файл
  • Обновить содержимое существующего файла

Эти операции в основном/template/index.jsв файле.

Также используется здесьshelljs/shelljsВыполнение сценариев оболочки, таких как инициализация gitgit init, установить зависимости после инициализации проектаnpm installЖдать.

скопировать файл шаблона

Копирование файлов шаблонов в основном используетсяjprichardson/node-fs-extraизcopyTpl()метод, этот метод используетejsСинтаксис шаблона, вы можете вставить входное содержимое в соответствующую позицию шаблона:

this.fs.copyTpl(
      project,
	  path.join(projectPath, 'project.config.json',
	  {description,projectName}
    );

Обновить содержимое существующего файла

Обновление содержимого существующего файла — сложная работа, самый надежный способ — разобрать файл какAST, а затем отредактируйте. некоторые популярныеAST parserвключают:

  • Cheerio: разборHTML.
  • Babylon: разборJavaScript.
  • заJSONфайл, используйте роднойJSONобъектный метод.

использоватьRegexРазбор кодового файла - это зло, не делай этого, не принимайте шансов.

taro build

taro buildКоманда — это душа и ядро ​​всего проекта Таро, в основном отвечающая заМноготерминальная компиляция кода(h5, апплет, React Native и т. д.).

ассоциация команд таро, анализ параметров и т. д. иtaro initНа самом деле это точно так же, так как же реализована самая важная часть преобразования кода?

Эта часть содержания слишком велика, и ее нужно вытащить в виде отдельной лекции. Но здесь кратко упоминается.

Рабочий процесс компиляции и абстрактное синтаксическое дерево (AST)

Основная часть Taro — это компиляция кода в код другой стороны (H5, апплет, React Native и т. д.). В общем, компиляция кода на одном структурированном языке в код на другом аналогичном структурированном языке включает следующие шаги:

image

Первый — парсинг, код解析(Parse)стать抽象语法树(Abstract Syntex Tree), а затем выполните AST遍历(traverse)и替换(replace)(Это не чуждо фронтенду, это можно сравнить с работой DOM-дерева), и наконец生成(generate), который генерирует скомпилированный код из нового AST.

Вавилонские модули

Babel — универсальныйJavaScript 编译器, точнее компилятор исходного кода, также обычно называемый转换编译器(transpiler). Это означает, что вы предоставляете Babel некоторый код JavaScript, Babel изменяет этот код и возвращает вам вновь сгенерированный код.

Кроме того, он имеет множество модулей для различных форм静态分析.

Статический анализ — это процесс анализа кода без выполнения кода (анализ кода во время его выполнения — это динамический анализ). Назначение статического анализа разнообразно, его можно использовать для проверки синтаксиса, компиляции, подсветки кода, преобразования кода, оптимизации, сжатия и так далее.

Babel на самом деле представляет собой набор модулей и имеет огромную экологию. Раздел компиляции кода проекта Taro основан на следующих модулях Babel:

  • babylonВавилон — это парсер Бабеля. Первоначально разветвлен от проекта Acorn. Acorn очень быстрый, простой в использовании и имеет архитектуру на основе плагинов, предназначенную для нестандартных функций (и тех, которые станут стандартными в будущем).
  • babel-traverseМодуль Babel Traverse поддерживает состояние всего дерева и отвечает за замену, удаление и добавление узлов.
  • babel-typesМодуль Babel Types — это библиотека инструментов в стиле Lodash для узлов AST, содержащая методы построения, проверки и преобразования узлов AST. Библиотека инструментов содержит продуманные методы инструментов, которые полезны для написания логики для обработки AST.
  • babel-generatorМодуль Babel Generator — это генератор кода Babel, который считывает AST и преобразует его в код и исходные карты.
  • babel-templatebabel-template — еще один небольшой, но очень полезный модуль. Он позволяет писать строковый код с заполнителями вместо ручного кодирования, особенно при создании крупномасштабных AST. В информатике эта способность называется квазикавычками.

Разобрать конфигурацию страницы

В процессе компиляции бизнес-кода в код апплета одним из шагов является анализ атрибута конфигурации записи страницы js и запись его в*.jsonфайл для использования апплетом. Так как же достигается этот шаг?Здесь извлекается ключевой код этой части функции:

// 1. babel-traverse方法, 遍历和更新节点
traverse(ast, {  
    ClassProperty(astPath) { // 遍历类的属性声明
        const node = astPath.node
        if (node.key.name === 'config') { // 类的属性名为 config
            configObj = traverseObjectNode(node)
            astPath.remove() // 将该方法移除掉
        }
    }
})

// 2. 遍历,解析为 JSON 对象
function traverseObjectNode(node, obj) { 
    if (node.type === 'ClassProperty' || node.type === 'ObjectProperty') {
        const properties = node.value.properties
        obj = {}
        properties.forEach((p, index) => {
            obj[p.key.name] = traverseObjectNode(p.value)
        })
        return obj
    }
    if (node.type === 'ObjectExpression') {
        const properties = node.properties
        obj = {}
        properties.forEach((p, index) => {
            // const t = require('babel-types')  AST 节点的 Lodash 式工具库
            const key = t.isIdentifier(p.key) ? p.key.name : p.key.value
            obj[key] = traverseObjectNode(p.value)
        })
        return obj
    }
    if (node.type === 'ArrayExpression') {
        return node.elements.map(item => traverseObjectNode(item))
    }
    if (node.type === 'NullLiteral') {
        return null
    }
    return node.value
}

// 3. 写入对应目录的 *.json 文件
fs.writeFileSync(outputPageJSONPath, JSON.stringify(configObj, null, 2))

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

Однако даже эту небольшую функциональную точку реализовать не так просто, к тому же нужно учитывать большое количество реальных бизнес-сценариев и экстремальных ситуаций:

  • Должны ли конфигурации для записи приложения app.js и записи страницы index.js обрабатываться отдельно?
  • Как преобразовать конфигурацию tabBar и обеспечить согласованное функционирование и взаимодействие?
  • Как подсказать, если информация о конфигурации пользователя неверна?

Больше контента, связанного с компиляцией кода, или поместите его в следующую статью.

Суммировать

Уже,taro-cliОсновная структура каталогов, вызов команд, метод инициализации проекта и т. д. в основном завершены.Заинтересованные студенты могут самостоятельно следить за исходным кодом проекта, это не должно быть слишком сложно.

taro-cliВ настоящее время шаблон размещен в проекте, и леса должны обновляться синхронно при каждом обновлении шаблона. иvue-cliОн заключается в том, чтобы поместить шаблон проекта в git, а затем загрузить различные шаблоны в соответствии с взаимодействием с пользователем при запуске и отобразить их через механизм шаблонов для создания проекта. Таким образом, шаблон и каркас можно разделить, чтобы их можно было поддерживать отдельно.Даже если шаблон изменится, необходимо загрузить только последний шаблон, и можно создать последний проект, не требуя от пользователя обновления каркаса. . Это было включено в объем последующей оптимизации.

В следующей статье мы вместе войдем в мир составления кода Таро.