【问题标题】:SCSS compilation in an isomorphic React app同构 React 应用程序中的 SCSS 编译
【发布时间】:2016-12-07 03:43:25
【问题描述】:

我正在编写一个基于:

的同构 React 应用程序

https://github.com/choonkending/react-webpack-node

我想使用 scss,而不是示例中使用的 css 模块。出于某种原因,我很难让他们工作。我的第一步是从服务器和客户端 configs 中删除 css webpack 加载器,用 scss 特定的加载器替换它们(以及删除 postcss):

  loaders: [
    'style-loader',
    'css-loader?modules&localIdentName=[name]_[local]_[hash:base64:3]',
    'sass-loader?sourceMap',
  ]

但这会抛出ReferenceError: window is not defined,因为样式加载器显然不适合服务器端渲染。所以我的下一个想法是使用isomorphic-style-loader。据我了解,要让它工作,我需要用他们的高阶组件 withStyles 装饰我的组件:

import React, { PropTypes } from 'react';
import classNames from 'classnames';
import withStyles from 'isomorphic-style-loader/lib/withStyles';
import s from '../assets/scss/common/index.scss';

const App = (props, context) => (
  <div className={classNames('app')}>
    <h1 className="home_header">Welcome!</h1>
    {props.children}
  </div>
);

export default withStyles(s)(App);

然后在服务器上的代码渲染页面做一些诡计。但问题是,包文档中的示例显示了在 Express (https://libraries.io/npm/isomorphic-style-loader#webpack-configuration) 内部触发的通量操作,而我正在使用的样板文件使用 react-router。所以我有点迷茫,我应该如何将这个带有insertCss 的对象注入到上下文中。我试过这个:

import React from 'react';
import { renderToString } from 'react-dom/server';
import { RouterContext, match, createMemoryHistory } from 'react-router';
import axios from 'axios';
import { Provider } from 'react-redux';
import createRoutes from 'routes.jsx';
import configureStore from 'store/configureStore';
import headconfig from 'components/Meta';
import { fetchComponentDataBeforeRender } from 'api/fetchComponentDataBeforeRender';

const clientConfig = {
  host: process.env.HOSTNAME || 'localhost',
  port: process.env.PORT || '3001'
};

// configure baseURL for axios requests (for serverside API calls)
axios.defaults.baseURL = `http://${clientConfig.host}:${clientConfig.port}`;

function renderFullPage(renderedContent, initialState, head = {
  title: 'cs3',
  css: ''
}) {
  return `
  <!DOCTYPE html>
  <html lang="en">
  <head>
    ${head.title}
    ${head.link}
    <style type="text/css">${head.css.join('')}</style>
  </head>
  <body>
    <div id="app">${renderedContent}</div>
    <script type="text/javascript">window.__INITIAL_STATE__ = ${JSON.stringify(initialState)};</script>
    <script type="text/javascript" charset="utf-8" src="/assets/app.js"></script>
  </body>
  </html>
  `;
}

export default function render(req, res) {
  const history = createMemoryHistory();
  const store = configureStore({
    project: {}
  }, history);

  const routes = createRoutes(store);

  match({ routes, location: req.url }, (error, redirectLocation, renderProps) => {
    const css = [];

    if (error) {
      res.status(500).send(error.message);
    } else if (redirectLocation) {
      res.redirect(302, redirectLocation.pathname + redirectLocation.search);
    } else if (renderProps) {
      const context = { insertCss: (styles) => css.push(styles._getCss()) };

      const InitialView = (
        <Provider context={context} store={store}>
            <RouterContext {...renderProps} />
        </Provider>
      );

      fetchComponentDataBeforeRender(store.dispatch, renderProps.components, renderProps.params)
      .then(() => {
        const componentHTML = renderToString(InitialView);
        const initialState = store.getState();
        res.status(200).end(renderFullPage(componentHTML, initialState, {
          title: 'foo',
          css
        }));
      })
      .catch(() => {
        res.end(renderFullPage('', {}));
      });
    } else {
      res.status(404).send('Not Found');
    }
  });
}

但我仍然收到Warning: Failed context type: Required context 'insertCss' was not specified in 'WithStyles(App)'. 任何想法如何解决这个问题?更重要的是 - 没有更简单的方法吗?这似乎需要做很多额外的工作。

【问题讨论】:

    标签: reactjs sass webpack isomorphic-javascript webpack-style-loader


    【解决方案1】:

    在进行服务器端渲染时,使用 webpack 处理 scss 编译有几个部分。首先,您不希望节点尝试将.scss 文件导入到您的组件中。

    所以在你的 webpack 配置中设置一个全局变量 WEBPACK: true

    plugins: [
        new webpack.DefinePlugin({
            'process.env': {
                WEBPACK: JSON.stringify(true),
            }
        })
    ],
    

    并且在您的组件中,如果组件正在由 webpack 处理(在构建或开发期间),则仅尝试导入 .scss 文件:

    if (process.env.WEBPACK) require('../assets/scss/common/index.scss');
    

    如果每个组件只有一个 Sass 文件(你应该),那么这始终只是一个单行。如果需要,可以在 index.scss 中导入任何其他 Sass 文件。

    然后在您的配置中,您可能仍然需要 css 加载器,因此您的开发服务器应该如下所示:

    {
        test: /\.s?css$/,
        loaders: ['style', 'css', 'sass']
    
    },
    

    还有这样的东西为你构建配置:

    {
        test: /\.s?css$/,
        loader: ExtractTextPlugin.extract('style', 'css!sass')
    },
    

    【讨论】:

    • 酷,这个有效。但我有点觉得我失去了这个同构加载器的一些优点,因为它应该只加载所需的最低 css。在我的组件中使用这个 webpack 插件变量也不是最干净的解决方案,但现在我不得不忍受我猜的。
    猜你喜欢
    • 1970-01-01
    • 2018-02-17
    • 1970-01-01
    • 1970-01-01
    • 2019-05-04
    • 1970-01-01
    • 2018-06-12
    • 2022-01-25
    • 2020-01-06
    相关资源
    最近更新 更多