Справочник по компилятору Svelte
Процесс компиляции Svelte можно разбить на 4 этапа
- Разбор исходного кода в абстрактном синтаксическом дереве (AST)
- Отслеживание ссылок и зависимостей
- Создание блоков кода и фрагментов
- Генерировать код
Который суммируется следующим псевдокодом:
const source = fs.readFileSync('App.svelte');
// parse source code into AST
const ast = parse(source);
// tracking references and dependencies
const component = new Component(ast);
// creating code blocks and fragments
const renderer = options.generate === 'ssr' ? SSRRenderer(component) : DomRenderer(component);
// Generate code
const { js, css } = renderer.render();
fs.writeFileSync('App.js', js);
fs.writeFileSync('App.css', css);
1. Разбор исходного кода в AST
// parse source code into AST
const ast = parse(source);
Синтаксис Svelte - это расширенный набор HTML. Svelte реализует собственный синтаксический анализатор для синтаксиса Svelte, который обрабатывает:
- Синтаксис HTML
div - Фигурные скобки
{ data } - Логические блоки
{#each list as item}
Анализатор обрабатывает специальные теги script и style.
Когда синтаксический анализатор обнаруживает тег script, он использует acorn для анализа содержимого тега. Когда анализатор тег style, он использует css-tree для анализа содержимого CSS.
Кроме того, синтаксический анализатор Svelte различает скрипт экземпляра script и скрипт модуля script context="module".
Svelte AST выглядит так:
{
html: { type: 'Fragment', children: [...] },
css: { ... },
instance: { context: 'default', content: {...} },
module: { context: 'context', content: {...} },
}
Вы можете попробовать парсер Svelte в ASTExplorer. Вы можете найти анализатор Svelte в HTML> Svelte.
2. Отслеживание ссылок и зависимостей
// tracking references and dependencies
const component = new Component(ast);
На этом этапе Svelte использует AST, чтобы отследить все объявленные и на которые ссылаются переменные и их зависимости.
а. Svelte создает экземпляр Component.
Component xранит информацию класса компонента, который включает в себя:
- HTML-фрагмент,
fragment - скрипт экземпляра и скрипт модуля AST и их лексические области действия, instance_scope и module_scope
- переменные экземпляра,
vars - реактивные переменные,
reactive_declarations - слоты,
slots - использовали имена переменных для предотвращения конфликта имен при создании временных переменных
- предупреждения и ошибки
- параметры компиляции и игнорируемые предупреждения
б. Пройдите сценарий экземпляра и сценарий модуля AST
Component обходит скрипт экземпляра и скрипт модуля AST, чтобы найти все переменные, объявленные, на которые есть ссылки и которые были обновлены в скрипте экземпляра и скрипте модуля.
Svelte определяет все доступные переменные перед тем, как перейти к шаблону. При обнаружении переменной во время обхода шаблона Svelte помечает переменную как referenced из шаблона.
с. Пройдите шаблон
Svelte проходит через шаблон AST и создает дерево фрагментов из шаблона AST.
Каждый узел фрагмента содержит такую информацию, как:
- выражение и зависимости
Логические блоки {#if} и теги { data } содержат выражения и зависимости выражения.
- сфера
{#each} и {#await} логический блок и let: привязка создают новые переменные для дочернего шаблона.
Svelte создает отдельный узел Fragment для каждого типа узла в AST, поскольку разные виды узла Fragment по-разному обрабатывают вещи:
- Элемент узла проверяет атрибут, привязки, контент и обработчики событий.
- Узел слота регистрирует имя слота в
Component. - EachBlock узел создает новые возможности и отслеживает
key,indexи название итерируемого списка. - ...
д. Пройдите через скрипт AST
После обхода шаблона Svelte теперь знает, обновляется ли когда-либо переменная в компоненте или когда на нее ссылаются.
С помощью этой информации Svelte пытается подготовиться к оптимизации вывода, например:
- определить, какие переменные или функции могут быть безопасно выведены из функции
instance. - определить реактивные декларации, которые не должны быть реактивными
е. Обновите CSS-селекторы, чтобы сделать декларацию стиля компонентной областью
Svelte обновляет селекторы CSS, добавляя класс .svelte-xxx к селекторам при необходимости.
В конце этого шага у Svelte достаточно информации для генерации скомпилированного кода, что приводит нас к следующему шагу.
3. Создание блоков кода и фрагментов
// creating code blocks and fragments
const renderer =
options.generate === 'ssr' ? SSRRenderer(component) : DomRenderer(component);
На этом этапе Svelte создает экземпляр Renderer, который отслеживает информацию, необходимую для генерации скомпилированного вывода. В зависимости от того, выводить ли код в DOM или SSR , Svelte создает различные экземпляры Renderer.
DOM Renderer
DOM Renderer отслеживает список блоков и контекст.
Блок содержит фрагменты кода для генерации create_fragment.
Контекст отслеживает список переменных экземпляра, которые будут представлены в $$.ctx скомпилированном выводе.
В рендере Svelte создает дерево рендеринга из дерева фрагментов.
Каждый узел в дереве визуализации реализует функцию render, которая генерирует коды, которые создают и обновляют DOM для узла.
SSR Renderer
SSR Renderer предоставляет помощники для генерации литералов шаблона в скомпилированном выводе, таких как add_string(str) и add_expression(node).
Где я могу найти Rendererв исходном коде?
DOM Renderer реализован в src/compiler/compile/render_dom/Renderer.ts, и вы можете проверить код SSR Renderer в src/compiler/compile/render_ssr/Renderer.ts.
4. Генерация кода
// Generate code
const { js, css } = renderer.render();
Разный рендер рендерит по разному.
Рендерер DOM проходит по дереву рендеринга и по пути вызывает функцию render каждого узла. Экземпляр Block передается в функцию render, так что каждый узел вставляет код в соответствующую функцию create_fragment.
Рендерер SSR, с другой стороны, использует разные обработчики узлов для вставки строк или выражений в конечный литерал шаблона.
Функция визуализации возвращает js и css которая будет потребляться в Bundler, через rollup-plugin-svelte и svelte-loader для WebPack соответственно.
Svelte Runtime
Для удаления дублирующегося кода в скомпилированном выводе Svelte предоставляет функцию util, которую можно найти в src/runtime/internal, например:
- РОМ связанные Utils, например:
append,insert,detach - планирования Utils, например:
schedule_update,flush - Жизненный цикл утилитами, например:
onMount,beforeUpdate - анимации, например:
create_animation