Справочник по компилятору 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