AST: Полное название — «Абстрактное синтаксическое дерево», что означает «Абстрактное синтаксическое дерево», которое является абстрактным представлением грамматической структуры исходного кода.
AST — это очень простой, но также очень важный элемент знаний.TypeScript, babel, webpack и vue-cli, с которыми мы знакомы, все полагаются на AST для разработки. Эта статья продемонстрирует вам силу и важность AST в реальной битве между AST и интерфейсным проектированием.
Адрес видео в прямом эфире:Практика AST и фронтенд-инжиниринга
1. Знакомство с АСТ
1. демо-1
Впервые я увидел концепцию AST в книге «JavaScript, которого вы не знаете». Давайте посмотрим на пример
const a = 1
В традиционных компилируемых языках выполнение исходного кода сначала проходит три этапа.
-
Фаза лексического анализа: разложите строку, состоящую из символов, на кодовые блоки (лексические единицы), в примере код будет разобран на четыре лексические единицы: const, a, = и 1.
-
Фаза синтаксического анализа: преобразование потока лексических единиц в дерево синтаксической структуры, состоящее из элементов, вложенных один за другим, так называемое абстрактное синтаксическое дерево. Поток лексических единиц, состоящий из четырех лексических единиц const, a, = и 1, проанализированных в примере, будет преобразован в следующее структурное дерево.
- Фаза генерации кода: преобразуйте AST в серию исполняемых кодов машинных инструкций.Например, машина создаст переменную a в памяти, выполнив инструкцию, и присвоит ей значение 1.
2. демо-2
Разбираем еще одинrecast
Официальный пример относительно сложен.
function add (a, b) {
return a + b
}
- Во-первых, входя в стадию лексического анализа, мы получим
function、add、(、a、,、b、)、{、return、a、+、b、}
13 кодовых блоков - Затем войдите в стадию синтаксического анализа, как показано на рисунке
на картинке вышеFunctionDeclaration
,Identifier
,BlockStatement
Чтобы ознакомиться с описанием типов этих кодовых блоков, перейдите по ссылке, чтобы просмотреть ее самостоятельно:Документация по объекту AST
2. Переделать
Поскольку используемые в статье зависимости, связанные с AST,recast
, плюс он недокументированный, только очень краткийREADME.md
файл, так что вот отдельная статья, чтобы представить некоторые из его общих API. Прежде чем начать, позвольте мне порекомендовать платформу для просмотра структуры AST онлайн, которая очень проста в использовании.
вернееbabel
Студенты, которые знают немного, знают, что,babel
Существует ряд пакетов, обертывающих AST для работы с этой частью компиляции. а такжеrecast
также на основе@babel/core
,@babel/parser
,@babel/types
Такие пакеты упаковываются и разрабатываются.
представлять
представлятьrecast
Есть два пути, один из нихimport
форма, одинCommonJs
в виде следующего
-
import
форма
import { parse, print } from 'recast'
console.log(print(parse(source)).code)
import * as recast from 'recast'
console.log(recast.print(recast.parse(source)).code)
-
CommonJs
форма
const { parse, print } = require('recast')
console.log(print(parse(source)).code)
const recast = require('recast')
console.log(recast.print(recast.parse(source)).code)
представилrecast
После этого давайте посмотримrecast
может сделать что-нибудь
1. переделать.parse
Вернемся к нашему примеру, разберем его напрямую и посмотрим, как выглядит структура AST после разбора.
// parse.js
const recast = require('recast')
const code = `function add (a, b) {
return a + b
}`
const ast = recast.parse(code)
// 获取代码块 ast 的第一个 body,即我们的 add 函数
const add = ast.program.body[0]
console.log(add)
воплощать в жизньnode parse.js
Вы можете просмотреть структуру функции добавления в нашем терминале
FunctionDeclaration {
type: 'FunctionDeclaration',
id: Identifier...,
params: [Identifier...],
body: BlockStatement...
}
Конечно, если вы хотите увидеть больше контента, перейдите непосредственно кПлатформа AST Explorerустановить режим наrecast
режиме вы можете увидеть обзор ast, который в основном совпадает с тем, что мы проанализировали выше.
2. переделать.печать
Пока мы только дизассемблировали его, что, если мы соберем ast в код, который мы сможем выполнить? Хорошо, это нужно использоватьrecast.print
Теперь мы собираем приведенный выше дизассемблированный код без изменений.
// print.js
const recast = require('recast')
const code = `function add (a, b) {
return a + b
}`
const ast = recast.parse(code)
console.log(recast.print(ast).code)
затем выполнитьnode print.js
, как видите, выводим
function add (a, b) {
return a + b
}
Официальное объяснение состоит в том, что это всего лишь обратный процесс, т.
recast.print(recast.parse(source)).code === source
3. переделать.prettyPrint
В дополнение к тому, что мы упоминали вышеrecast.print
за пределами,recast
Он также предоставляет API для улучшения кода под названиемrecast.prettyPrint
// prettyPrint.js
const recast = require('recast')
const code = `function add (a, b) {
return a + b
}`
const ast = recast.parse(code)
console.log(recast.prettyPrint(ast, { tabWidth: 2 }).code)
воплощать в жизньnode prettyPrint.js
, вы обнаружите, что в коде можно отформатировать более N пробелов, и результат будет следующим:
function add(a, b) {
return a + b;
}
Пожалуйста, проверьте подробную конфигурацию самостоятельно:prettyPrint
4. переделать.типы.строителей
i. API
оbuilder
API, не волнуйтесь, я точно не буду об этом говорить, потому что их слишком много.
Если вы хотите узнать, что может делать каждый API, вы можете перейти непосредственно кParser API - Buildersчтобы просмотреть его, или просмотреть его напрямуюОпределение строителей переделки
II. Фактический боевой этап
ОК, наконец-то вступилrecast
Ядро, связанное с работой, тоже. Мы хотим преобразовать наш код, затемrecast.types.builders
Это наш самый важный инструмент. Здесь мы продолжаем преобразованиеrecast
Официальный кейс для изученияrecast.types.builders
Создать инструмент.
В простейшем примере теперь нам нужно что-то сделать, т.е.function add (a, b) {...}
изменить наconst add = function (a, b) {...}
.
Из главы 1 мы узнали, что если нам нужно сделать этоconst
Если он декларативен, вам нужно сначалаVariableDeclaration
иVariableDeclarator
тогда мы объявляемfunction
то необходимо создатьFunctionDeclaration
, а остальное — заполнить параметры и тело выражения. Конкретные операции заключаются в следующем
// builder1.js
const recast = require('recast')
const {
variableDeclaration,
variableDeclarator,
functionExpression
} = recast.types.builders
const code = `function add (a, b) {
return a + b
}`
const ast = recast.parse(code)
const add = ast.program.body[0]
ast.program.body[0] = variableDeclaration('const', [
variableDeclarator(add.id, functionExpression(
null, // 这里弄成匿名函数即可
add.params,
add.body
))
])
const output = recast.print(ast).code
console.log(output)
воплощать в жизньnode builder1.js
, вывод следующий
const add = function(a, b) {
return a + b
};
Видеть это, интересно? Самое интересное только началось.Далее на основе этого примера сделаем небольшое расширение. изменить его непосредственно наconst add = (a, b) => {...}
формат.
А вот и новая концепция, конечно же, стрелочные функции.recast.type.builders
при условииarrowFunctionExpression
чтобы мы могли создать стрелочную функцию. Итак, наш первый шаг — создать стрелочную функцию.
const arrow = arrowFunctionExpression([], blockStatement([])
распечататьconsole.log(recast.print(arrow))
, вывод следующий
() => {}
Итак, у нас есть пустая стрелочная функция. Далее нам нужно провести дальнейшее преобразование на основе приведенного выше преобразования.functionExpression
заменитьarrowFunctionExpression
Вот и все.
ast.program.body[0] = variableDeclaration('const', [
variableDeclarator(add.id, b.arrowFunctionExpression(
add.params,
add.body
))
])
Результаты печати следующие
const add = (a, b) => {
return a + b
};
Хорошо, мы здесь, мы уже знаемrecast.types.builders
Может предоставить нам ряд API, чтобы мы могли выводить сумасшедшие.
5. переделать.выполнить
Чтение командной строки файла. Сначала я создаю новыйread.js
, содержание следующее
// read.js
recast.run((ast, printSource) => {
printSource(ast)
})
Затем я создаю новыйdemo.js
, содержание следующее
// demo.js
function add (a, b) {
return a + b
}
затем выполнитьnode read demo.js
, вывод следующий
function add (a, b) {
return a + b
}
Мы видим, что находимся прямо вread.js
зачитатьdemo.js
содержание кода внутри. Так как именно это достигается?
На самом деле принцип очень простой, не более чем напрямую черезfs.readFile
Прочитайте файл, а затем получитеcode
провестиparse
операция, как мы видимprintSource
затем предоставляет функцию печати по умолчаниюprocess.stdout.write(output)
, конкретный код выглядит следующим образом
import fs from "fs";
export function run(transformer: Transformer, options?: RunOptions) {
return runFile(process.argv[2], transformer, options);
}
function runFile(path: any, transformer: Transformer, options?: RunOptions) {
fs.readFile(path, "utf-8", function(err, code) {
if (err) {
console.error(err);
return;
}
runString(code, transformer, options);
});
}
function defaultWriteback(output: string) {
process.stdout.write(output);
}
function runString(code: string, transformer: Transformer, options?: RunOptions) {
const writeback = options && options.writeback || defaultWriteback;
transformer(parse(code, options), function(node: any) {
writeback(print(node, options).code);
});
}
6. переделать.посетить
Это API для обхода узлов AST. Если вы хотите обойти некоторые типы в AST, вам придется полагаться наrecast.visit
Теперь типы, которые можно пройти здесь, такие же, как иrecast.types.builders
Может быть построен из того же типа,builders
Что это делает, это тип здания,recast.visit
Что он делает, так это перебирает типы в AST. Однако при использовании необходимо обратить внимание на следующие моменты.
- При каждом посещении необходимо добавлять
return false
,илиthis.traverse(path)
, иначе будет сообщено об ошибке.
if (this.needToCallTraverse !== false) {
throw new Error(
"Must either call this.traverse or return false in " + methodName
);
}
- Вы можете пройти, добавив посещение перед типом, который нужно пройти, Если вам нужно пройти стрелочную функцию в AST, вы можете просто написать это так
recast.run((ast, printSource) => {
recast.visit(ast, {
visitArrowFunctionExpression (path) {
printSource(path.node)
return false
}
})
})
7. recast.types.namedTypes
API для определения, относится ли объект AST к указанному типу.
В namedTypes есть два API, один из которыхnamedTypes.Node.assert
: Если тип не настроен, он сообщит об ошибке и выйдет напрямую. ДругойnamedTypes.Node.check
: определить, являются ли типы согласованными, и вывести true или false.
Где Node - это любой объект AST, например, я делаю определение типа функции относительно стрелочной функции, код выглядит следующим образом
// namedTypes1.js
const recast = require('recast')
const t = recast.types.namedTypes
const arrowNoop = () => {}
const ast = recast.parse(arrowNoop)
recast.visit(ast, {
visitArrowFunctionExpression ({ node }) {
console.log(t.ArrowFunctionExpression.check(node))
return false
}
})
воплощать в жизньnode namedTypes1.js
, вы можете видеть, что вывод станции печати верен.
Точно так же использование assert аналогично.
const recast = require('recast')
const t = recast.types.namedTypes
const arrowNoop = () => {}
const ast = recast.parse(arrowNoop)
recast.visit(ast, {
visitArrowFunctionExpression ({ node }) {
t.ArrowFunctionExpression.assert(node)
return false
}
})
Если вы хотите оценить больше типов объектов AST, вы можете напрямую заменить Node другими типами объектов AST.
3. Фронтенд-инжиниринг
Теперь поговорим о фронтенд-инжиниринге.
Фронтенд-инжиниринг можно разделить на четыре блока, а именно
-
Модульность: разделите файл на несколько взаимозависимых файлов и, наконец, выполните унифицированную упаковку и загрузку, что может обеспечить эффективную совместную работу нескольких человек. который содержит
- Модульный JS: модуль CommonJS, AMD, CMD и ES6.
- Модульность CSS: Sass, Less, Stylus, BEM, модули CSS и т. д. Одна из проблем, с которой сталкиваются как препроцессоры, так и БЭМ, — переопределение стилей. Модули CSS, с другой стороны, управляют зависимостями через JS, максимизируя сочетание модульности JS и экологии CSS, таких как область стиля в Vue.
- Модульность ресурсов: любой ресурс может быть загружен в виде модуля.В настоящее время большинство файлов, CSS, изображений и т. д. в проекте могут напрямую обрабатываться JS для унифицированных отношений зависимости.
-
Компонентизация: в отличие от модуляризации, модульность — это разделение файлов, кода и ресурсов, а компонентизация — это разделение уровня пользовательского интерфейса.
- Обычно нам нужно разделить страницу, разбить ее на части одну за другой, а затем реализовать каждую часть отдельно и, наконец, собрать ее.
- В нашем фактическом развитии бизнеса нам необходимо по-разному учитывать разделение компонентов, что в основном включает рассмотрение мелкозернистости и общности.
- Что касается бизнес-компонентов, вам нужно больше учитывать применимость бизнес-направления, за которое вы отвечаете, то есть станет ли бизнес-компонент, который вы разрабатываете, «универсальным» компонентом вашего текущего бизнеса, например компонент проверки разрешений, который я проанализировал. раньше Это типичная деловая составляющая. Заинтересованные друзья могут нажатьпорталЧитайте самостоятельно.
-
Стандартизация: как говорится, нет правил и кругов, несколько хороших спецификаций могут помочь нам хорошо разрабатывать и управлять проектом. Стандартизация относится к серии спецификаций, которые мы разрабатываем в начале и в ходе разработки проекта, что, в свою очередь, включает
- Структура каталогов проекта
- Спецификация кодирования: для ограничений кодирования мы обычно используем некоторые обязательные меры, такие как ESLint, StyleLint и т. д.
- Совместная спецификация отладки: эта часть может относиться к моему предыдущему ответу,Внешняя и внутренняя части разделены, и данные, возвращаемые серверной частью, не могут быть записаны во внешнюю часть. Что мне делать?
- соглашение об именах файлов
- Практики управления стилями: популярными средствами управления стилями являются BEM, Sass, Less, Stylus, модули CSS и другие средства.
- рабочий процесс git flow: который включает в себя соглашения об именовании ветвей, соглашения о слиянии кода и многое другое.
- Регулярный обзор кода
- … так далее
Выше я также написал статью, прежде чем сделать некоторые подробные объяснения,TypeScript + крупномасштабный бой проекта
-
Автоматизация: от самого раннего grunt, gulp и т. д. до текущего веб-пакета, посылки. Эти автоматизированные инструменты могут сэкономить нам много работы по автоматизации слияния, сборки и упаковки. И часть этой внешней автоматизации, внешняя автоматизация также включает в себя непрерывную интеграцию, автоматизированное тестирование и другие аспекты.
Однако нахождение в любом из этих блоков относится к фронтенд-инжинирингу.
В-четвертых, настоящий бой: AST и загрузчик webpack
Фактический бой, упомянутый в этой статье, заключается в том, чтобы написать собственный загрузчик веб-пакетов через преобразование AST и автоматически внедрить операции catch для промисов в нашем проекте, избегая необходимости вручную писать эти общие операции catch.
1. Трансформация АСТ
После стольких разговоров мы, наконец, вступили в настоящее боевое звено. Итак, что мы будем делать на практике?
Сценарий: в ежедневных проектах среднего уровня часто существуют некоторые требования к отправке формы, поэтому при отправке необходимо ввести некоторые ограничения, чтобы люди не пожимали друг другу руки несколько раз и не вызывали повторные запросы. Существует много решений для таких сценариев, но я лично считаю, что наилучшее взаимодействие — это добавить состояние загрузки к кнопке отправки после нажатия, затем отключить его, а затем удалить состояния загрузки и отключения после успешного выполнения запроса. Конкретные операции отправки следующие:
this.axiosFetch(this.formData).then(res => {
this.loading = false
this.handleClose()
}).catch(() => {
this.loading = false
})
Это вроде бы нормально, но если таких операций будет слишком много, это сделает весь код вашего проекта более или менее избыточным, так как же решить эту ситуацию?
Очень просто, мы напрямую используем AST для написания загрузчика веб-пакета для автоматического выполнения некоторого внедрения кода.Если в нашем проекте существует следующий код, обработка части catch будет автоматически добавлена, и первый абзац оператора then будет автоматически Логика обработки как catch
this.axiosFetch(this.formData).then(res => {
this.loading = false
this.handleClose()
})
Давайте сначала посмотрим, как выглядит AST-структура этого кода без catch, как показано на рисунке
Его MemberExpression
this.axiosFetch(this.formData).then
аргументы
res => {
this.loading = false
this.handleClose()
}
Хорошо, давайте посмотрим на AST-структуру кода с обработкой catch, как показано на рисунке.
Его MemberExpression
this.axiosFetch(this.formData).then(res => {
this.loading = false
this.handleClose()
}).catch
Есть два ArrowFunctionExpressions, соответственно
// ArrowFunctionExpression 1
res => {
this.loading = false
this.handleClose()
}
// ArrowFunctionExpression 2
() => {
this.loading = false
}
Итак, то, что нам нужно сделать, условно разделим на следующие шаги
- Пройдите через тип ArrowFunctionExpression, чтобы получить первый ExpressionStatement в его BlockStatement и сохранить его как firstExp.
- Используйте компоновщики, чтобы создать пустую стрелочную функцию и назначить сохраненный firstExp для BlockStatement пустой стрелочной функции.
- Перейдите к типу CallExpression и измените MemberExpression AST в формат с фрагментами перехвата.
- Вернуть преобразованный AST
Теперь, по нашему мнению, мы будем делать преобразование AST шаг за шагом
Во-первых, нам нужно получить первый ExpressionStatement в существующей стрелочной функции.При его получении нам нужно убедиться, что родительский узел текущего типа ArrowFunctionExpression является типом CallExpression и что его свойство является функцией then обещания. операции следующие
// promise-catch.js
const recast = require('recast')
const {
identifier: id,
memberExpression,
callExpression,
blockStatement,
arrowFunctionExpression
} = recast.types.builders
const t = recast.types.namedTypes
const code = `this.axiosFetch(this.formData).then(res => {
this.loading = false
this.handleClose()
})`
const ast = recast.parse(code)
let firstExp
recast.visit(ast, {
visitArrowFunctionExpression ({ node, parentPath }) {
const parentNode = parentPath.node
if (
t.CallExpression.check(parentNode) &&
t.Identifier.check(parentNode.callee.property) &&
parentNode.callee.property.name === 'then'
) {
firstExp = node.body.body[0]
}
return false
}
})
Далее нам нужно создать пустую стрелочную функцию и присвоить ей firstExp
const arrowFunc = arrowFunctionExpression([], blockStatement([firstExp]))
Затем нам нужно пройти через объект AST типа CallExpression и выполнить окончательное преобразование MemberExpression.
recast.visit(ast, {
visitCallExpression (path) {
const { node } = path
const arrowFunc = arrowFunctionExpression([], blockStatement([firstExp]))
const originFunc = callExpression(node.callee, node.arguments)
const catchFunc = callExpression(id('catch'), [arrowFunc])
const newFunc = memberExpression(originFunc, catchFunc)
return false
}
})
Наконец, мы заменяем его, когда CallExpression пересекает
path.replace(newFunc)
Полный код первой версии выглядит следующим образом
// promise-catch.js
const recast = require('recast')
const {
identifier: id,
memberExpression,
callExpression,
blockStatement,
arrowFunctionExpression
} = recast.types.builders
const t = recast.types.namedTypes
const code = `this.axiosFetch(this.formData).then(res => {
this.loading = false
this.handleClose()
})`
const ast = recast.parse(code)
let firstExp
recast.visit(ast, {
visitArrowFunctionExpression ({ node, parentPath }) {
const parentNode = parentPath.node
if (
t.CallExpression.check(parentNode) &&
t.Identifier.check(parentNode.callee.property) &&
parentNode.callee.property.name === 'then'
) {
firstExp = node.body.body[0]
}
return false
}
})
recast.visit(ast, {
visitCallExpression (path) {
const { node } = path
const arrowFunc = arrowFunctionExpression([], blockStatement([firstExp]))
const originFunc = callExpression(node.callee, node.arguments)
const catchFunc = callExpression(id('catch'), [arrowFunc])
const newFunc = memberExpression(originFunc, catchFunc)
path.replace(newFunc)
return false
}
})
const output = recast.print(ast).code
console.log(output)
воплощать в жизньnode promise-catch.js
, таблица печати выводит результат
this.axiosFetch(this.formData).then(res => {
this.loading = false
this.handleClose()
}).catch(() => {
this.loading = false
})
Итак, видно, что мы достигли того, чего хотели достичь.
-
Но нам все еще нужно иметь дело с некоторыми случаями, первый — убедиться, что его аргументы являются стрелочными функциями при обходе CallExpression.
-
Затем нам нужно определить, существует ли полученный нами firstExp, потому что наша обработка then может быть пустой стрелочной функцией.
-
Затем, чтобы предотвратить использование какой-либо пользовательской операции catch для обещания, вам необходимо убедиться, что его свойство имеет значение then.
-
Наконец, чтобы предотвратить ситуацию, когда несколько CallExpressions должны быть автоматически внедрены, а затем их операции различны, вам нужно выполнять операции обхода ArrowFunctionExpression внутри них.
После совместимости этих распространенных ситуаций конкретный код выглядит следующим образом.
recast.visit(ast, {
visitCallExpression (path) {
const { node } = path
const arguments = node.arguments
let firstExp
arguments.forEach(item => {
if (t.ArrowFunctionExpression.check(item)) {
firstExp = item.body.body[0]
if (
t.ExpressionStatement.check(firstExp) &&
t.Identifier.check(node.callee.property) &&
node.callee.property.name === 'then'
) {
const arrowFunc = arrowFunctionExpression([], blockStatement([firstExp]))
const originFunc = callExpression(node.callee, node.arguments)
const catchFunc = callExpression(id('catch'), [arrowFunc])
const newFunc = memberExpression(originFunc, catchFunc)
path.replace(newFunc)
}
}
})
return false
}
})
Затем нам нужно позже создать загрузчик webpack и использовать его в нашем реальном проекте. Итак, нам нужно заменить парсер parse, парсер по умолчаниюrecast/parsers/esprima
, и обычно используется в наших проектахbabel-loader
, поэтому нам также нужно изменить его парсер наrecast/parsers/babel
const ast = recast.parse(code, {
parser: require('recast/parsers/babel')
})
2. загрузчик веб-пакетов
Здесь мы завершили преобразование кода AST, но как применить его к нашему реальному проекту?
Хорошо, сейчас нам нужно написать загрузчик веб-пакетов самостоятельно.
На самом деле, о том, как разработать загрузчик веб-пакетов,официальная документация по веб-пакетуСказано очень ясно, позвольте мне сделать небольшое резюме для моих друзей.
I. Разработка локального загрузчика
Прежде всего, вам нужно создать новый файл вашего загрузчика разработки локально, например, мы закинем его вsrc/index.js
Вниз,webpack.config.js
Конфигурация выглядит следующим образом
const path = require('path')
module.exports = {
// ...
module: {
rules: [
{
test: /\.js$/,
use: [
// ... 其他你需要的 loader
{ loader: path.resolve(__dirname, 'src/index.js') }
]
}
]
}
}
src/index.js
Содержание выглядит следующим образом
const recast = require('recast')
const {
identifier: id,
memberExpression,
callExpression,
blockStatement,
arrowFunctionExpression
} = recast.types.builders
const t = recast.types.namedTypes
module.exports = function (source) {
const ast = recast.parse(source, {
parser: require('recast/parsers/babel')
})
recast.visit(ast, {
visitCallExpression (path) {
const { node } = path
const arguments = node.arguments
let firstExp
arguments.forEach(item => {
if (t.ArrowFunctionExpression.check(item)) {
firstExp = item.body.body[0]
if (
t.ExpressionStatement.check(firstExp) &&
t.Identifier.check(node.callee.property) &&
node.callee.property.name === 'then'
) {
const arrowFunc = arrowFunctionExpression([], blockStatement([firstExp]))
const originFunc = callExpression(node.callee, node.arguments)
const catchFunc = callExpression(id('catch'), [arrowFunc])
const newFunc = memberExpression(originFunc, catchFunc)
path.replace(newFunc)
}
}
})
return false
}
})
return recast.print(ast).code
}
Затем приступайте к работе.
II. Пакет npm
Здесь я упоминал об этом в предыдущих статьях, поэтому я не буду говорить об этом здесь. Если вы еще не сделали пакет npm, вы можете щелкнуть ссылку ниже, чтобы проверить это самостоятельно.
Демистифицирующие компонентные библиотеки (выпуск пакетов NPM)
Хорошо, на данный момент мойpromise-catch-loader
Он также был разработан. Далее просто используйте его в проекте
npm i promise-catch-loader -D
Поскольку мой проект построен на vue-cli3.x, мне нужно добавить в свойvue.config.js
настроено так
// js 版本
module.exports = {
// ...
chainWebpack: config => {
config.module
.rule('js')
.test(/\.js$/)
.use('babel-loader').loader('babel-loader').end()
.use('promise-catch-loader').loader('promise-catch-loader').end()
}
}
// ts 版本
module.exports = {
// ...
chainWebpack: config => {
config.module
.rule('ts')
.test(/\.ts$/)
.use('cache-loader').loader('cache-loader').end()
.use('babel-loader').loader('babel-loader').end()
.use('ts-loader').loader('ts-loader').end()
.use('promise-catch-loader').loader('promise-catch-loader').end()
}
}
Затем у меня есть следующие обещания в моем проекте
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import { Action } from 'vuex-class'
@Component
export default class HelloWorld extends Vue {
loading: boolean = false
city: string = '上海'
@Action('getTodayWeather') getTodayWeather: Function
getCityWeather (city: string) {
this.loading = true
this.getTodayWeather({ city: city }).then((res: Ajax.AjaxResponse) => {
this.loading = false
const { low, high, type } = res.data.forecast[0]
this.$message.success(`${city}今日:${type} ${low} - ${high}`)
})
}
}
</script>
Затем посмотрите на источник в браузере, и вы увидите следующие результаты.
Что касается кода, я разместил его на GitHub,promise-catch-loader
Суммировать
На этом наше собственно боевое звено закончилось. Конечно, статья является лишь предварительным руководством, и друзьям предстоит изучить больше типов.
AST имеет множество применений, например, хорошо известный Vue, его анализ файлов SFC (.vue) также основан на AST для автоматического анализа, а именно на vue-loader, что гарантирует, что мы можем использовать Vue для развития бизнеса в обычном режиме. Другим примером является наш широко используемый инструмент построения веб-пакетов, который также предоставляет нам очень практичные функции, такие как слияние, упаковка и оптимизация построения на основе AST.
Одним словом, освойте АСТ, и вы действительно сможете многое.
Наконец, я надеюсь, что содержание статьи поможет вам понять: что такое AST? Как мы можем сделать нашу работу более эффективной с помощью AST? Что AST может сделать для фронтенд-инжиниринга?
Если вы считаете, что статья хороша, то я надеюсь, что вы можете шевельнуть своей маленькой ручкой и помочь поставить лайк, спасибо~
Группа внешней связи: 731175396