3

我正在使用 Fluxible 帮助在一个新项目上创建一个同构应用程序,并且它运行良好。到目前为止我喜欢它。不过,我遇到了减速带,想知道如何克服它。

到目前为止,这是我的 Header 组件:

import React from 'react'
import Nav from '../Nav/Nav'

import classNames from 'classnames'
if (process.env.BROWSER) var styles = require('./Header.css')

class Header extends React.Component {
    render() {

        // Header classes
        var theClasses = process.env.BROWSER ? classNames({
            [styles.Header]: true
        }) : ''

        return (
            <header className={theClasses}>
                <Nav selected={this.props.selected} links={this.props.links} />
            </header>
        )
    }
}

export default Header

你会看到我process.env.BROWSER用来检测我在哪个 ENV 上。如果我们在客户端,我需要 CSS。如果我们在服务器上,我会跳过它。这非常有效。

问题出现在文件的后面,我theClasses根据Header.css文件的内容构建对象,然后在 Header 上使用这些类,如下所示:

<header className={theClasses}>
    <Nav selected={this.props.selected} links={this.props.links} />
</header>

问题是因为我没有在服务器上加载 css,theClasses最终为空,并且为客户端呈现的内容最终与服务器上的内容不同。React 显示此警告:

警告:React 尝试在容器中重用标记,但校验和无效。这通常意味着您正在使用服务器渲染,并且在服务器上生成的标记不是客户端所期望的。React 注入了新的标记来补偿哪些工作,但是您已经失去了服务器渲染的许多好处。相反,找出为什么生成的标记在客户端或服务器上是不同的:

(client) n28"><header class="Header--Header_ip_OK

(server) n28"><header class="" data-reactid=".2ei

你会建议什么来解决这个问题?


2015 年 9 月 24 日更新

最初的问题是我无法在服务器端编译 CSS,所以我开始像这样检查 BROWSER:

if (process.env.BROWSER) var styles = require('./Application.css')

如果我删除该if (process.env.BROWSER)位,我会收到此错误:

SyntaxError: src/components/Application/Application.css: Unexpected token (2:0)
  1 |
> 2 | @import 'styles/index.css';
    | ^
  3 |

在以下简单的 CSS 文件中:

@import 'styles/index.css';

.Application {
    box-shadow: 0 0 0 1px var(--medium-gray);
    box-sizing: border-box;
    lost-center: 1080px 32px;
}

我用Fluxible Yo Generator开始了这个项目,它在这里提供了两个 Webpack 配置文件:https ://github.com/yahoo/generator-fluxible/tree/master/app/templates

我用一些装载机更新了我的:

var webpack = require('webpack');
var path = require('path');

module.exports = {
    resolve: {
        extensions: ['', '.js', '.jsx']
    },
    entry: [
        'webpack-dev-server/client?http://localhost:3000',
        'webpack/hot/only-dev-server',
        './client.js'
    ],
    output: {
        path: path.resolve('./build/js'),
        publicPath: '/public/js/',
        filename: 'main.js'
    },
    module: {
        loaders: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                loaders: [
                    require.resolve('react-hot-loader'),
                    require.resolve('babel-loader')
                ]
            }, {
                test: /\.css$/,
                loader: 'style-loader!css-loader?modules&localIdentName=[name]__[local]_[hash:base64:5]!postcss-loader'
            }, {
                test: /\.(png|jpg|svg)$/,
                loader: 'url?limit=25000'
            }, {
                test: /\.json$/,
                loader: 'json-loader'
            }
        ]
    },
    postcss: function () {
        return [
            require('lost'),
            require('postcss-import')({
                path: ['./src/'],
                onImport: function (files) {
                    files.forEach(this.addDependency);
                }.bind(this)
            }),
            require('postcss-mixins'),
            require('postcss-custom-properties'),
            require('autoprefixer')({
                browsers: ['last 3 versions']
            })
        ];
    },
    node: {
        setImmediate: false
    },
    plugins: [
        new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoErrorsPlugin(),
        new webpack.DefinePlugin({
            'process.env': {
                NODE_ENV: JSON.stringify(process.env.NODE_ENV),
                BROWSER: JSON.stringify(true)
            }
        })
    ],
    devtool: 'eval'
};

所以这就是我所在的地方……不知道如何在服务器端编译 CSS。感谢我能得到的任何帮助。

4

4 回答 4

4

你可以试试css-modules-require-hook

webpack.config.js

{
  test: /\.css$/,
  loader: 'style-loader!css-loader?modules&localIdentName=[name]__[local]___[hash:base64:5]'
}

服务器.js

require('css-modules-require-hook')({
  // This path should match the localIdentName in your webpack css-loader config.
  generateScopedName: '[name]__[local]___[hash:base64:5]'
})
于 2015-12-03T08:14:39.853 回答
3

您需要确保服务器生成与客户端相同的标记,这意味着您也需要在服务器上使用 CSS 模块。

在我当前的项目中,我们也通过使用 Webpack 来编译我们的 Node 代码来实现这一点。James Long 写了一篇关于如何设置的非常好的指南,分布在三篇博客文章中:

使用 Webpack 的后端应用程序(第一部分)

使用 Webpack 的后端应用程序(第二部分)

使用 Webpack 的后端应用程序(第三部分)

于 2015-09-23T05:42:06.517 回答
2

您当然应该使用类来渲染服务器端 HTML,否则您将错过时间来获得同构应用程序的好处。这意味着您仍然必须等待 JS 加载才能应用 CSS 样式,这违背了构建 HTML 服务器端的某些目的。这也意味着您不能“切芥末”并在关闭 Javascript 的情况下为旧浏览器提供应用程序。

问题是你为什么不在服务器上渲染 CSS 类?这也让我困惑了一段时间,但我猜你没有两个 Webpack 入口点?一个用于客户端,一个用于服务器。

如果我的假设是正确的,那么看看这里的沙盒存储库,我正在为节点服务器入口点和浏览器入口点进行多次构建,也使用 Fluxible。

然而,我现在会用一点盐来接受这一切,因为它只是一个供个人使用的测试项目。我还在本地 css 中使用了这种方法,它在服务器和客户端上都构建它,它就像一个魅力。

编辑:我看到您使用的是 ES6,所以我假设您确实在构建服务器端?如果是这样,您不包含 CSS 的原因是什么?

于 2015-09-24T10:10:23.760 回答
0

所以你必须有两个 Webpack 配置,第一个用于编译浏览器包,第二个用于编译服务器包。

使用标准配置,您可以css-loader?...

{
    test: /\.css$/,
    loader: 'style-loader!css-loader?modules&localIdentName=[name]__[local]_[hash:base64:5]'
}

你会得到两个不同的捆绑包。

在服务器上。所有类都在css.locals对象中:

let css = require('styles.scss');
css.locals == { fooClass: 'some_foo_class' }

在浏览器上没有.locals

let css = require('styles.scss');
css == { fooClass: 'some_foo_class' }

所以你需要在服务器版本中去掉.locals,这样它就应该像在浏览器中一样。

您可以css-loader/locals?...在 webpack 服务器配置中使用它:

{
    test: /\.scss$/i,
    loader: "css/locals?modules&importLoaders=1&-minimize&localIdentName=[local]_[hash:3]!sass"
}

更多细节在这里https://github.com/webpack/css-loader/issues/59#issuecomment-109793167

于 2017-01-15T15:19:33.657 回答