首页 > 解决方案 > 同构样式加载器无法正常工作

问题描述

嘿,我正在做这个简单的react+SSR项目,其中包含isomorphic-style loader. 我按照这里的分步指南来实现它https://www.npmjs.com/package/isomorphic-style-loader但它不起作用。我做的风格没有表现出来。谁能指导我解决这个问题?

这是我的webpack config

var path = require('path');
var webpack = require('webpack');
var nodeExternals = require('webpack-node-externals');

var browserConfig = {
    entry: './src/browser/index.js',
    output: {
        path: path.resolve(__dirname, 'public'),
        filename: 'bundle.js',
        publicPath: '/',
    },
    module: {
        rules: [
            { test: /\.(js)$/, use: 'babel-loader' },
            {
                test: /\.css$/,
                use: [
                    'isomorphic-style-loader',
                    {
                        loader: 'css-loader',
                        options: {
                            importLoaders: 1,
                        },
                    },
                    'postcss-loader',
                ],
            },
        ],
    },
    mode: 'production',
    plugins: [
        new webpack.DefinePlugin({
            __isBrowser__: 'true',
        }),
    ],
};

var serverConfig = {
    entry: './src/server/index.js',
    target: 'node',
    externals: [nodeExternals()],
    output: {
        path: __dirname,
        filename: 'server.js',
        publicPath: '/',
    },
    mode: 'production',
    module: {
        rules: [
            { test: /\.(js)$/, use: 'babel-loader' },
            {
                test: /\.css$/,
                use: [
                    'isomorphic-style-loader',
                    {
                        loader: 'css-loader',
                        options: {
                            importLoaders: 1,
                        },
                    },
                    'postcss-loader',
                ],
            },
        ],
    },
    plugins: [
        new webpack.DefinePlugin({
            __isBrowser__: 'false',
        }),
    ],
};

module.exports = [browserConfig, serverConfig];

这是我的index.js (server)

import express from 'express';
import cors from 'cors';
import React from 'react';
import { renderToString } from 'react-dom/server';
import { StaticRouter, matchPath } from 'react-router-dom';
import serialize from 'serialize-javascript';
import StyleContext from 'isomorphic-style-loader/StyleContext';
import App from '../shared/App';
import routes from '../shared/routes';

const app = express();

app.use(cors());
app.use(express.static('public'));

app.get('*', (req, res, next) => {
    const css = new Set(); // CSS for all rendered React components
    const insertCss = (...styles) =>
        styles.forEach((style) => css.add(style._getCss()));

    const activeRoute = routes.find((route) => matchPath(req.url, route)) || {};
    const promise = activeRoute.fetchInitialData
        ? activeRoute.fetchInitialData(req.path)
        : Promise.resolve();

    promise
        .then((data) => {
            const context = { data };
            const markup = renderToString(
                <StyleContext.Provider value={{ insertCss }}>
                    <StaticRouter location={req.url} context={context}>
                        <App />
                    </StaticRouter>
                </StyleContext.Provider>
            );

            res.send(`
      <!DOCTYPE html>
      <html>
        <head>
          <title>SSR with RR</title>
          <script src="/bundle.js" defer></script>
          <script>window.__INITIAL_DATA__ = ${serialize(data)}</script>
          <style type="text/css">${[...css].join('')}</style>
        </head>

        <body>
          <div id="app">${markup}</div>
        </body>
      </html>
    `);
        })
        .catch(next);
});

app.listen(3000, () => {
    console.log(`Server is listening on port: 3000`);
});

这是我的index.js (browser)

import React from 'react';
import { hydrate } from 'react-dom';
import App from '../shared/App';
import { BrowserRouter } from 'react-router-dom';
import StyleContext from 'isomorphic-style-loader/StyleContext';

const insertCss = (...styles) => {
    const removeCss = styles.map((style) => style._insertCss());
    return () => removeCss.forEach((dispose) => dispose());
};

hydrate(
    <StyleContext.Provider value={{ insertCss }}>
        <BrowserRouter>
            <App />
        </BrowserRouter>
    </StyleContext.Provider>,
    document.getElementById('app')
);

这是App.js其中使用css styling不起作用的组件。

import React from 'react';
import { NavLink } from 'react-router-dom';
import style from './css/style.css';
import withStyles from 'isomorphic-style-loader/withStyles';

function Navbar() {
    const languages = [
        {
            name: 'All',
            param: 'all',
        },
        {
            name: 'JavaScript',
            param: 'javascript',
        },
        {
            name: 'Ruby',
            param: 'ruby',
        },
        {
            name: 'Python',
            param: 'python',
        },
        {
            name: 'Java',
            param: 'java',
        },
    ];

    return (
        <ul className='navbar'>
            {languages.map(({ name, param }) => (
                <li key={param}>
                    <NavLink
                        activeStyle={{ fontWeight: 'bold' }}
                        to={`/popular/${param}`}
                    >
                        {name}
                    </NavLink>
                </li>
            ))}
        </ul>
    );
}

export default withStyles(style)(Navbar);

标签: reactjsserver-side-renderingisomorphic-style-loader

解决方案


我遇到了同样的问题。问题与 css-loader 有关。默认情况下,css-loader 生成使用 ES 模块语法的 JS 模块。isomorphic-style-loader 需要 CommonJS 模块语法。

尝试这个:

{
  loader: 'css-loader',
  options: {
    importLoaders: 1,
    esModule: false,
  },
}

推荐阅读