Как загрузить стили на серверную часть React с помощью Webpack и вернуться к клиентской стороне загрузчика стилей?
Моя цель состоит в том, чтобы сделать CSS похожим на тег сервера на стороне сервера или как style-loader
Плагин будет делать это на стороне клиента. Я знаю, что это невозможно, потому что style-loader
пишет напрямую в DOM, а DOM не существует в Node.js.
В настоящее время я использую ExtractTextPlugin, но если он не скомпилирует весь CSS в один большой файл, он пропустит некоторые стили при загрузке страницы, если я не запускаю Webpack на сервере и не компилирую его напрямую.
У меня есть этот код рендеринга страницы:
server.jsx
const renderedContent = renderToString(
<Provider store={store} history={history}>
<RoutingContext {...renderProps} />
</Provider>
)
const finalState = store.getState()
const renderedPage = renderFullPage(renderedContent, finalState)
рендеринга полный page.jsx
module.exports = function renderFullPage(renderedContent = undefined, state = {}) {
return '<!DOCTYPE html>' + renderToStaticMarkup(
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
{typeof __production !== 'undefined' && __production === true && <link id="css" rel="stylesheet" href="/main.css" />}
</head>
<body>
<div id="root"><div dangerouslySetInnerHTML={{__html: renderedContent}}></div></div>
<script dangerouslySetInnerHTML={{__html: 'window.__INITIAL_STATE__ =' + JSON.stringify(state)}} />
<script src="/bundle.js"></script>
</body>
</html>
)
}
Я импортирую стили по всему миру, когда они мне нужны в моих модулях React:
import './../../assets/styl/flex-video'
И я хотел бы изменить способ загрузки CSS, чтобы поместить весь CSS в переменную, которую я могу просмотреть и вывести <style>
теги так же style-loader
это так:
{typeof __production !== 'undefined' && __production === true && cssFiles.map((styles) => {
<style>{styles}</style>
})}
Это возможно в Webpack? Есть ли плагин, как isomorphic-style-loader
что способен на это? Если так, как бы я изменил свой код?
1 ответ
Вот пример того, что вы хотите использовать isomorphic-style-loader
,
Сначала вы создаете помощник по стилю, чтобы автоматизировать передачу стилей в DOM или загрузку их в переменную, которая впоследствии будет отображаться на сервере.
Это пример помощника по стилю, который я создал, модифицированный для приема массива файлов стилей (CSS, Sass, LESS, Stylus):
Утилиты / стиль-helper.jsx
import React, { Component } from 'react'
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment'
const css = []
const collectOrRender = function(styles) {
let renderedCollection = []
for (let i = 0, l = styles.length; i < l; i++) {
const stylesFile = styles[i]
if (canUseDOM) {
renderedCollection[stylesFile._insertCss()]
}
css.push(stylesFile._getCss())
}
return renderedCollection
}
export function styleHelper(ComposedComponent, styles) {
return class Styles extends Component {
componentWillMount() {
this.styleRemovers = collectOrRender(styles)
}
componentWillUnmount() {
setTimeout(() => {
for (let i = 0, l = this.styleRemovers.length; i < l; i++) {
let styleRemover = this.styleRemovers[i]
typeof styleRemover === 'function' && styleRemover()
}
}, 0)
}
render() {
return <ComposedComponent {...this.props} />
}
}
}
export function renderStyles() {
return css.join('')
}
Затем вы должны взять свой помощник по стилю и заставить его обернуть ваш модуль под нагрузкой.
Этот пример показывает, как вы это сделаете, используя connect()
от react-redux
,
мой-module.jsx
// Utilities
import { styleHelper } from 'utilities/style-helper'
const styles = [
require('normalize.css'),
require('styl/global'),
require('styl/site'),
require('styl/bubble')
]
class myModule extends Component {
render() { return (
<div />
)}
}
export default connect(
state => ({ menuIsOpen: state.collapsibleMenu.menuIsOpen })
)(styleHelper(myModule, styles))
Это обрабатывает загрузку на клиенте. Теперь на сервере вы храните все эти стили в массиве. Вы хотите вставить этот массив на свою HTML-страницу и поместить его между <style>
теги.
Вот пример того, как я это сделал:
рендеринга полный page.jsx
import React from 'react'
import { renderToStaticMarkup } from 'react-dom/server'
// Utilities
import { renderStyles } from './style-helper'
module.exports = function renderFullPage(renderedContent = undefined, state = {}) {
return '<!DOCTYPE html>' + renderToStaticMarkup(
<html lang="en">
<head>
{/* Critical Styles */}
<style dangerouslySetInnerHTML={{__html: renderStyles()}} />
</head>
<body>
<div id="root" dangerouslySetInnerHTML={{__html: renderedContent}}></div>
<script dangerouslySetInnerHTML={{__html: 'window.__INITIAL_STATE__ =' + JSON.stringify(state)}} />
<script src="/bundle.js"></script>
</body>
</html>
)
}
Обратите внимание, как тег style получает стили от Style Helper и помещает их в <style>
тег. Когда реагирует загрузка, он выяснит, что делать, но теперь на сервере будет только CSS, необходимый для правильного отображения страницы.