为什么同构式装载机抛出一个TypeError:无法读取属性“申请”的未定义齐声正在使用CSS模块时(

2019-10-29 07:22发布

目前,我想要呈现的服务器,其作品为HTML和JS应用,却发现我的风格(.LESS | .scss)将不会加载。 我做了一些研究和揣摩,不知道,我是失踪的isomorphic-style-loader在我的WebPack配置基于别人运行到同样的问题。 我设置它,至少我是怎么理解的,但我现在发现,运行应用程序时,我收到以下错误:

TypeError: Cannot read property 'apply' of undefined at WithStyles.componentWillMount

我有点新的整个反应,和/快递的事情,但一直在努力与教程,跟着一起学习,我去,如果看出来的地方,请原谅我。 我希望看看是否有人能解释到底是什么导致这个错误,并为我提供什么,我可以遵循解决此错误的一些概念。 下面是类似我有问题之一,如果它可以帮助任何方式的一些示例代码。

(仅供参考我下面的泰勒·麦金尼斯反应路由器服务器渲染教程,并试图在它扩大到添加样式- 链接在这里 )

由于事先对,什么可能会导致此错误提供任何解释。


webpack.config.babel.js

import path from 'path'
import webpack from 'webpack'
import nodeExternals from 'webpack-node-externals'

const paths = {
  browser: path.join(__dirname, './src/browser'),
  server: path.join(__dirname, './src/server'),
  build: path.resolve(__dirname, 'public')
}

let browserConfig = {
  entry: `${paths.browser}/index.js`,
  output: {
    path: paths.build,
    filename: 'bundle.js',
    publicPath: '/'
  },
  module: {
    rules: [
      {
        test: /\.s?(a|c)ss$/,
        use: [
          'isomorphic-style-loader',
          {
            loader: 'css-loader',
            options: {
              modules: true,
              importLoaders: 1,
              localIdentName: '[name]__[local]___[hash:base64:5]',
              sourceMap: true
            }
          },
          'sass-loader',
          'postcss-loader'
        ]
      }, {
        test: /\.less$/,
        use: [
          'isomorphic-style-loader',
          {
            loader: 'css-loader',
            options: {
              modules: true,
              importLoaders: 1,
              localIdentName: '[name]__[local]___[hash:base64:5]',
              sourceMap: true
            }
          },
          {
            loader: 'less-loader',
            options: {
              javascriptEnabled: true
            }
          },
          'postcss-loader'
        ]
      }, {
        test: /\.jsx?$/,
        loader: 'babel-loader',
        exclude: /node_modules/
      }
    ]
  },
  plugins: [
    new webpack.DefinePlugin({
      __isBrowser__: true
    })
  ],
  resolve: {
    extensions: ['.js', '.jsx', '.json', '.css', '.scss', '.sass', '.less']
  }
}

let serverConfig = {
  entry: `${paths.server}/index.js`,
  target: 'node',
  externals: [nodeExternals()],
  output: {
    path: __dirname,
    filename: 'server.js',
    publicPath: '/'
  },
  module: {
    rules: [
      {
        test: /\.s?(a|c)ss$/,
        use: [
          'isomorphic-style-loader',
          {
            loader: 'css-loader',
            options: {
              modules: true,
              importLoaders: 1,
              localIdentName: '[name]__[local]___[hash:base64:5]',
              sourceMap: true
            }
          },
          'sass-loader',
          'postcss-loader'
        ]
      }, {
        test: /\.less$/,
        use: [
          'isomorphic-style-loader',
          {
            loader: 'css-loader',
            options: {
              modules: true,
              importLoaders: 1,
              localIdentName: '[name]__[local]___[hash:base64:5]',
              sourceMap: true
            }
          },
          {
            loader: 'less-loader',
            options: {
              javascriptEnabled: true
            }
          },
          'postcss-loader'
        ]
      }, {
        test: /\.jsx?$/,
        loader: 'babel-loader',
        exclude: /node_modules/
      }
    ]
  },
  plugins: [
    new webpack.DefinePlugin({
      __isBrowser__: false
    })
  ],
  resolve: {
    extensions: ['.js', '.jsx', '.json', '.css', '.scss', '.sass', '.less']
  }
}

module.exports = [browserConfig, serverConfig]

server.js

import express from "express"
import cors from "cors"
import React from "react"
import bodyParser from 'body-parser'
import serialize from "serialize-javascript"
import { renderToString } from "react-dom/server"
import { StaticRouter, matchPath } from "react-router-dom"
import App from '../shared/App'
import routes from '../shared/routes'

const app = express()
const port = process.env.PORT || 3000

app.use(cors())
app.use(bodyParser.json()) // support json encoded bodies
app.use(bodyParser.urlencoded({extended: true})) // support encoded bodies
app.use(express.static("public"))

app.get("*", (req, res, next) => {
  const activeRoute = routes.find((route) => matchPath(req.url, route)) || {}

  const promise = activeRoute.fetchInitialData
    ? activeRoute.fetchInitialData(req.path)
    : Promise.resolve()

  promise.then((data) => {
    const css = new Set()
    const context = { data, insertCss: (...styles) => styles.forEach(style => css.add(style._getCss())) }
    const markup = renderToString(
      <StaticRouter location={req.url} context={context}>
          <App />
      </StaticRouter>
    )

    res.send(`
      <!DOCTYPE html>
      <html>
        <head>
          <title>React on the Server!</title>
          <script src="/bundle.js" defer></script>
          <script>window.__INITIAL_DATA__ = ${serialize(data)}</script>
        </head>
        <body>
          <div id="app">${markup}</div>
        </body>
      </html>
    `)
  }).catch(next)
})

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

routes.js

import AboutMain from './components/About/AboutMain'

const routes =  [
  {
    path: '/about',
    component: AboutMain
  }
]

export default routes

browser.js

// Import the neccessary modules for use in file
import React from 'react' // Main React module
import { hydrate } from 'react-dom' // render alternative for server rendering
import App from '../shared/App'
import { BrowserRouter } from 'react-router-dom' // React Router component for client side routing
import '../shared/components/global.scss' // Only has general rules, which do get applied

hydrate(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById('app')
)

App.js

import React, { Component } from 'react'
import routes from './routes'
import { Route, Link, Redirect, Switch } from 'react-router-dom'

class App extends Component {
  render() {
    return (
      <div>    
        <Switch>
          {routes.map(({ path, exact, component: Component, ...rest }) => (
            <Route key={path} path={path} exact={exact} render={(props) => (
              <Component {...props} {...rest} />
            )} />
          ))}
          <Route render={(props) => <NoMatch {...props} /> } />
        </Switch>
      </div>
    )
  }
}

export default App

AboutMain.js

// Importing Required Modules
import React, {Component, Fragment} from 'react' // Importing React, Component, Fragment from "react"
import withStyles from 'isomorphic-style-loader/lib/withStyles';
import s from './about.scss'

class AboutMain extends Component {
  state = {
    phrase: 'We Made It!'
  }

  render() {
    return (
      <Fragment>
        <header className={s.banner}>
          <h1 className={s.heading}>{this.state.phrase}</h1>
        </header>
      </Fragment>
    )
  }
}

export default withStyles(s)(AboutMain) <-- Error Seems to occur here, at least I think.

about.scss

.banner {
  margin: 0 auto;
  padding: 15px;
  border: 2px solid #000;
}

.heading {
  text-transform: uppercase;
  text-decoration: underline;
}

Answer 1:

问题走了,只是因为你删除isomorphic-style-loader 。 请不要接受你自己的答案这样。 这里的问题是你没有提供context所以insertCss.apply(_context, styles)会抱怨,因为_contextundefined 。 为了解决这个问题,请按照下列步骤操作:

  1. 创建ContextProvider在同一目录组件App

ContextProvider.js

import React from 'react';
import PropTypes from 'prop-types'
import App from './App'

class ContextProvider extends React.Component {
    static childContextTypes = {
      insertCss: PropTypes.func,
    }

    getChildContext() {
      return { ...this.props.context }
    }

    render () {
      return <App { ...this.props } />
    }
  }

  export default ContextProvider
  1. 包裹ContextProvider 两个browser.jsserver.js 。 记住声明context的两个文件。

browser.js(在其他应用中,这将是根的客户端代码,即client.jsindex.js

// Import the neccessary modules for use in file
/* import statements */


const context = {
    insertCss: (...styles) => {
      const removeCss = styles.map(x => x._insertCss());
      return () => {
        removeCss.forEach(f => f());
      };
    },
  }

hydrate(
  <BrowserRouter>
    //ContextProvider wraps around and returns App so we can do this
    <ContextProvider context={context} />
  </BrowserRouter>,
  document.getElementById('app')
)

server.js

//Additional code above

app.get("*", (req, res, next) => {
  const activeRoute = routes.find((route) => matchPath(req.url, route)) || {}

  const promise = activeRoute.fetchInitialData
    ? activeRoute.fetchInitialData(req.path)
    : Promise.resolve()

  promise.then((data) => {
    const css = new Set()
    const context = { insertCss: (...styles) => 
styles.forEach(style => css.add(style._getCss()))}

    const markup = renderToString(
      <StaticRouter location={req.url}>
        <ContextProvider context={context}> 
         <App />
        </ContextProvider>
      </StaticRouter>
    )

    res.send(`
      <!DOCTYPE html>
      <html>
        <head>
          <title>React on the Server!</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(port, () => console.log(`Server is listening on port: ${port}`))

我写了一篇文章更详细地解释这个位置: https://medium.com/@danielnmai/load-css-in-react-server-side-rendering-with-isomorphic-style-loader-848c8140a096



Answer 2:

检查代码整夜不休谷歌搜索后。 我找到了解决的是我的代码的主要问题是在webpack.config.babel.js设置。

我改变了浏览器测试青菜|| SCSS使用style-loader ,而不是isomorphic-style-loader 。 我也删除了所有isomorphic-style-loader逻辑从我的应用程序(即withStylesinsertCss等)

我不知道这是否是正确的做法,但与此同时,它似乎解决我的问题,并且不返回任何错误或网络问题。



文章来源: Why does isomorphic-style-loader throw a TypeError: Cannot read property 'apply' of undefined when being used in unison with CSS-Modules