1

style-loader我的目标是将 CSS 渲染到服务器端的样式标签中,或者与插件在客户端的操作方式完全相同。我知道这是不可能style-loader的,因为直接写入 DOM 并且 Node.js 中不存在 DOM。

目前我正在使用 ExtractTextPlugin,但是如果我没有将所有 CSS 编译到一个大文件中,那么当页面加载时它会丢失一些样式,除非我在服务器上运行 Webpack 而不是直接编译它。

我有这个代码呈现页面:

服务器.jsx

const renderedContent = renderToString(
    <Provider store={store} history={history}>
        <RoutingContext {...renderProps} />
    </Provider>
)

const finalState = store.getState()
const renderedPage = renderFullPage(renderedContent, finalState)

呈现-full-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 放入一个 var 中,我可以循环并输出<style>标签style-loader,就像这样:

{typeof __production !== 'undefined' && __production === true && cssFiles.map((styles) => {
    <style>{styles}</style>
})}

这在 Webpack 中可行吗?有没有这样的插件isomorphic-style-loader能够做到这一点?如果是这样,我将如何修改我的代码?

4

1 回答 1

3

这是您想要使用的示例isomorphic-style-loader

首先,您创建一个 Style Helper 来自动将样式推送到 DOM 或将它们加载到稍后将在服务器上呈现的 var 中。

这是我创建的 Style Helper 示例,修改后接受一组样式文件(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('')
}

然后你必须抓住你的 Style Helper 并让它在加载时包装你的模块。

这个例子展示了你在使用connect()from时如何做到这一点react-redux

我的模块.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>标签之间。

这是我如何做到的一个例子:

呈现-full-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。

于 2016-02-19T17:32:49.707 回答