Главная » Статьи » Динамический импорт CSS

Динамический импорт CSS

Динамический импорт CSS

От автора: отложенная загрузка CSS с помощью динамического import() на примере Stencil Web Components. Целью решения является загрузка CSS по требованию. Для достижения этой цели мы можем воспользоваться динамическим import() JavaScript . Вместо обработки статических стилей сборки мы откладываем загрузку, интегрируя стили в виде кода JavaScript. Вкратце, мы внедряем CSS через JavaScript на лету.

Динамический import(), который допускает асинхронную загрузку и выполнение модулей скриптов, является частью официального предложения TC39 и был стандартизирован с ECMAScript 2020. Более того, он также уже поддерживается транспиллерами, такими как Webpack или Typescript.

Настройка

Прежде чем перейти непосредственно к решению, давайте запустим проект из командной строки с помощью Stencil — npm init stencil.

Этот компонент, который мы собираемся разработать для демонстрационных целей, имеет целью визуализировать текст с «зеленым» или «красным» фоном. Вот для чего мы можем добавить такое свойство ./src/components/my-component/my-component.tsx.

import { Component, Prop, h } from '@stencil/core'; @Component({ tag: 'my-component', styleUrl: 'my-component.css', shadow: true
})
export class MyComponent { @Prop() theme: 'green' | 'red' = 'green' render() { return <div class={this.theme}>Hello, World!</div>; }
}

Поскольку мы применяем свойство, как имя класса, мы должны определить связанный CSS в ./src/components/my-component/my-component.css. Обратите внимание, что в настоящее время мы только настраиваем демонстрационный проект, мы еще не внедряем решение, поэтому добавляем стиль в файл CSS.

:host { display: block;
} .red { background: red;
} .green { background: green;
}

Наконец, в дополнение к компоненту мы также добавляем в./src/index.html для целей тестирования поле select, которое должно позволить нам переключаться между этими цветами.

<!DOCTYPE html>
<html dir="ltr" lang="en">
<head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0"> <title>Stencil Component Starter</title> <script type="module" src="/build/lazy-css.esm.js"></script> <script nomodule src="/build/lazy-css.js"></script> </head>
<body> <my-component></my-component> <select id="themeToggler" onchange="updateTheme()"> <option value="green" selected="selected">green</option> <option value="red">red</option> </select> <script type="text/javascript"> function updateTheme() { const toggler = document.getElementById('themeToggler'); const elem = document.querySelector('my-component'); elem.theme = toggler.value; } </script>
</body>
</html>

Если мы теперь запустим локальный сервер npm run start, чтобы протестировать компонент в нашем любимом браузере, мы сможем переключать фоны.

Динамический импорт CSS

Более важно, если мы откроем отладчик, мы должны также увидеть, что и наши стили .green и .red были загружены. Это означает, что клиентская сторона извлекает эти два стиля, даже если мы не используем, например, один из этих двух цветов.

Динамический импорт CSS

Первым делом мы удалим стиль из ./src/components/my-component/my-component.css, из CSS, относящегося к компоненту.

:host { display: block;
}

Поскольку мы удалили статический стиль, теперь нам нужен способ применить его на лету. Вот почему мы создаем функциональный компонент, целью которого является внедрение узла style в наш веб-компонент. Согласно свойству theme, этот новый компонент должен применять либо «зеленый», либо «красный» фон. Для простоты мы объявляем это в основном скрипте компонента ./src/components/my-component/my-component.tsx.

import {Component, Prop, h, FunctionalComponent, Host, State} from '@stencil/core'; const ThemeStyle: FunctionalComponent<{style: string}> = ({style}) => { return ( <style>{` :host ${style}; `}</style> );
}; @Component({ tag: 'my-component', styleUrl: 'my-component.css', shadow: true
})
export class MyComponent { @Prop() theme: 'green' | 'red' = 'green' @State() private style: string; // TODO: Dynamically import style render() { return <Host> <ThemeStyle style={this.style}></ThemeStyle> <div class={this.theme}>Hello, World!</div> </Host>; }
}

Динамический импорт

Компонент настроен для динамического рендеринга тем, но мы пока не загружаем их. Кроме того, наш CSS-контент был удален. Вот почему мы создаем одну константу JavaScript для каждого стиля, который хотим получить во время выполнения. Конкретно, в проекте мы создаем файл ./src/components/my-component/red.ts для «красной» темы.

const theme: string = `{ background: red;
}`; export {theme};

И еще один ./src/components/my-component/green.ts для «зеленого» стиля.

const theme: string = `{ background: green;
}`; export {theme};

Это определения, которые будут выполняться с помощью динамических функций import(), которые мы в конце добавим к нашему компоненту ./src/components/my-component/my-component.tsx.

private async importTheme(): Promise<{theme}> { if (this.theme === 'red') { return import('./red'); } else { return import('./green'); }
}

Обратите внимание, что, к сожалению, в настоящее время невозможно использовать динамический import() с переменной. Причина, насколько я понимаю, заключается в том, что такие упаковщики, как Webpack или Rollup, даже если скрипты будут включаться во время выполнения, должны знать, какой код используется, чтобы оптимизировать пакеты. Вот почему, например return import(${this.theme});, не будет компилироваться.

Загрузка

Мы объявили темы и внедрили import(), но нам все еще нужно применить результаты к рендерингу, который мы выполняем, загружая значения, когда компонент будет монтироваться и когда свойство темы будет изменено путем объявления @Watch().

import {Component, Prop, h, FunctionalComponent, Host, State, Watch} from '@stencil/core'; const ThemeStyle: FunctionalComponent<{style: string}> = ({style}) => { return ( <style>{` :host ${style}; `}</style> );
}; @Component({ tag: 'my-component', styleUrl: 'my-component.css', shadow: true
})
export class MyComponent { @Prop() theme: 'green' | 'red' = 'green' @State() private style: string; async componentWillLoad() { await this.loadTheme(); } @Watch('theme') private async loadTheme() { const {theme} = await this.importTheme(); this.style = theme; } private async importTheme(): Promise<{theme}> { if (this.theme === 'red') { return import('./red'); } else { return import('./green'); } } render() { return <Host> <ThemeStyle style={this.style}></ThemeStyle> <div class={this.theme}>Hello, World!</div> </Host>; }
}

И вуаля, мы можем отложенно загружать CSS с помощью динамического import(). Если мы снова протестируем компонент в браузере, используя сервер разработки (npm run start), мы должны заметить, что он по-прежнему отображает другой фон в соответствии с нашим выбором.

Динамический импорт CSS

Что более важно, если мы посмотрим отладчик, мы также должны заметить, что тема загружается на лету.

Динамический импорт CSS

Аналогично, если мы наблюдаем за теневыми элементами, мы должны заметить, что style содержит только связанный узел.

Динамический импорт CSS

Заключение

Это был первый раз, когда я использовал динамический import() для отложенной загрузки CSS в веб-компоненте, и я должен признать, что я действительно доволен результатом. Более того, добавление этих тем для кода, отображаемого на слайдах, созданных с помощью DeckDeckGo, я считаю действительно заметным улучшением. Попробуйте сами.

Динамический импорт CSS

Автор: David Dal Busco

Источник: https://medium.com

Редакция: Команда webformyself.