Webpack SCSS "Мерцание" перед pageload

Я работаю над изоморфным приложением React + Flux + express и использую загрузчики webpack для моего sass (с sass-loader) и jsx файлов. Я не уверен, как вводить мои таблицы стилей в шаблон на стороне сервера. Я посмотрел на Extract Text Plugin для этой цели, но я действительно хочу иметь возможность использовать горячую замену модуля. Прямо сейчас я загружаю файл main.scss в компонент React следующим образом:

if (typeof window !== 'undefined') {
  require("!style!css!sass!../../../styles/main.scss");
}

Это хорошо работает для загрузки отдельной таблицы стилей в компоненте, но перед тем, как часть React будет смонтирована, будет мерцание. Я понимаю, что это потому, что это инъекция таблицы стилей после загрузки моего приложения на стороне клиента, поэтому таблица стилей недоступна. Это приводит к актуальному вопросу: есть ли способ внедрить этот стиль в мой серверный шаблон, все еще используя загрузчик webpack, или это вызывает отдельный файл gulpfile или промежуточное ПО? Ранее я использовал gulpfile для создания таблиц стилей, но в итоге у меня будет много таблиц стилей и не хочу, чтобы все они застряли в один файл.

Ответ 1

Итак, идея состоит в том, чтобы скомпилировать webpack с двумя отдельными конфигурациями, один из которых нацелен на web (браузер), другой - на node (на стороне сервера). Пакет на стороне сервера может потребоваться в другом node/экспресс-коде для создания предварительно визуализированного HTML с помощью css.

Вот полный пример здесь, и я проведу вас через соответствующие его части. https://github.com/webpack/react-starter

prerender.html в app - это шаблон на стороне сервера, который использует автор. Обратите внимание на следующие две строки кода:

<link rel="stylesheet" href="STYLE_URL">
<script src="SCRIPT_URL"></script>

См. здесь конфигурацию для webpack https://github.com/webpack/react-starter/blob/master/make-webpack-config.js. Параметры, передаваемые здесь, зависят от того, выполняете ли вы конструкцию prod или dev build. Поскольку мы хотим создать клиентский пакет и пакет сервера prerendering, давайте посмотрим https://github.com/webpack/react-starter/blob/master/webpack-production.config.js. Он создает два пакета, в частности первый с отдельными таблицами стилей, предназначенных для браузера, а второй - для предварительной записи.

Для первой компиляции он использует это:

plugins.push(new ExtractTextPlugin("[name].css" + (options.longTermCaching ? "?[contenthash]" : "")));

чтобы создать отдельный файл css вместе с вашим пакетом. Во время второй компиляции (для предварительной записи) она использует null-loader для загрузки стилей (потому что у нас уже есть стили, которые нам нужны в файле css, мы можем просто использовать это).

Теперь здесь, где мы вводим путь к css в ваш шаблон сервера. Взгляните здесь на упрощенный server.js: https://github.com/webpack/react-starter/blob/8e6971d8fc9d18eeef7818bd6e9be45f6b8643e6/lib/server.js

var STYLE_URL = "main.css?" + stats.hash;
var SCRIPT_URL = [].concat(stats.assetsByChunkName.main)[0];
app.get("/*", function(req, res) {
    res.contentType = "text/html; charset=utf8";
    res.end(prerenderApplication(SCRIPT_URL, STYLE_URL, COMMONS_URL));
});

Предполагая, что ваш выходной путь для вашего пакета совпадает с server.js(в противном случае вы можете получить publicPath с помощью require("../build/stats.json").publicPath и добавить его к вашим STYLE_URL и SCRIPT_URL выше.

Затем в prerender.jsx: https://github.com/webpack/react-starter/blob/8e6971d8fc9d18eeef7818bd6e9be45f6b8643e6/config/prerender.jsx Возьмите серверный шаблон prerender.html и замените URL-адреса:

var html = require("../app/prerender.html");
module.exports = function(scriptUrl, styleUrl, commonsUrl) {
    var application = React.renderComponentToString(<Application />);
    return html.replace("STYLE_URL", styleUrl).replace("SCRIPT_URL", scriptUrl).replace("COMMONS_URL", commonsUrl).replace("CONTENT", application);
};

Я признаю, что это может быть сложным и запутанным, и если вам будет проще использовать отдельный файл gulpfile для этого. Но поиграйте с этим. Если вам нужно больше разъяснений и помощи, вы можете оставить комментарий, и я подойду к нему, как только смогу, или вы можете использовать здесь веб-чат (https://gitter.im/webpack/webpack), Я уверен, что один из разработчиков может, вероятно, дать вам лучшее объяснение, чем я.

Надеюсь, что это несколько (?) полезно!

Ответ 2

Начальная вспышка появляется, потому что "стиль-загрузчик" еще не загрузил ваши стили CSS.

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

Вы можете добиться изоморфного рендеринга, следуя пути проекта "реакция-стартер" (упомянутый в комментарии выше) или используя webpack-isomorphic-tools

https://github.com/halt-hammerzeit/webpack-isomorphic-tools

Ответ 3

Вам понадобятся 2 сборника webpack: 1 для сети, 1 для node.

Если вы удалите стиль, вы сможете загрузить таблицу стилей как на сервере, так и на клиенте.

  var css = require("!css!sass!../../../styles/main.scss");

Поскольку вы больше не используете загрузчик стилей, вам нужно вручную ввести полученный css в свой вид.

В вашем представлении вам нужно будет включить этот

<style>{css.toString()}</style>

Это должно работать как на сервере, так и на клиенте. Когда вы выполните React.renderToString(), css будет разбираться в любом порядке, указанном в вашем html. Если он находится в верхней части/в <head>, не должно быть мерцания.