Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error when styling React components imported from index file, but not when importing directly from component file

Newbie here, so apologies in advance if I am overlooking something obvious or missed a duplicate posting (and also for not posting directly on styled-components, apparently I need a rep for that...) .

The closest I found to my problem was in this resolved issue, at the bottom of the thread: https://github.com/styled-components/styled-components/issues/213

The guy had a very similar problem, but the solution was brief and Typescript specific.

BACKGROUND: I have an index file that imports my components from all over, and exports them under a webpack alias. Whenever I need to import elsewhere I just declare:

import { MyComponentA, MyComponentB, MyComponentC } from 'components';

I recently started incorporating styled-components into my project and have been getting an error like the following when I try to style components imported in this way:

Error: Cannot create styled-component for component: undefined._____________styled-components.browser.esm.js:233
   at new StyledComponentsError (/home/jhillert/Dropbox/Projects/TimeLockr/node_modules/styled-components/dist/styled-components.browser.esm.js:233:59)
   at constructWithOptions (/home/jhillert/Dropbox/Projects/TimeLockr/node_modules/styled-components/dist/styled-components.browser.esm.js:1355:12)
   at styled (/home/jhillert/Dropbox/Projects/TimeLockr/node_modules/styled-components/dist/styled-components.browser.esm.js:2293:11)
   at Module.eval (/home/jhillert/Dropbox/Projects/TimeLockr/src/components/card-area/CardArea.jsx:111:91)
   at eval (/home/jhillert/Dropbox/Projects/TimeLockr/src/components/card-area/CardArea.jsx:133:31)
   at Module../src/components/card-area/CardArea.jsx (http://localhost:8080/bundle.js:9343:1)
   at __webpack_require__ (http://localhost:8080/bundle.js:724:30)
   at fn (http://localhost:8080/bundle.js:101:20)
   at eval (/home/jhillert/Dropbox/Projects/TimeLockr/src/indexes/components.jsx:17:89)
   at Module../src/indexes/components.jsx (http://localhost:8080/bundle.js:9619:1)

If I import the component directly from the source file I do not get the error. It only happens when I try to pass components imported from the index file into the styled() method, and also when I try to use the CSS prop to add inline styling.

For some reason the error does not occur with all components imported in this way, and also I have made changes to my code that suddenly cause the index import to trigger the error. I really like having a central index file, so a fix would be greatly appreciated.

Example where css prop causes error:

*Project config below. Index File looks like this (components.jsx):

export { default as ActionBar } from '../components/action-bar/ActionBar';
export { default as AuthForm } from '../components/auth/AuthForm';
export { default as AuthModal } from '../components/auth/AuthModal';
export { default as AuthTabs } from '../components/auth/AuthTabs';
export { default as Box } from '../components/box/Box';

/*==============================================================*/

//CardArea.js
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import {
  CardColumn  ◀◀◀—————————————— DOES PRODUCE ERROR
  LockedEntryCard,
  ReleasedEntryCard,
} from 'components';

import CardColumn from '../card-column/CardColumn' ◀◀◀——————— DOES NOT

const S = {};

S.CardArea = styled.div`  ◀◀◀————— NOT IMPORTED, NOT A PROBLEM
     /* ommitted */                BUT WOULD CAUSE SAME ERROR 
`;                                 IF IMPORTED.

const CardArea = ({ entries, refresh }) => {
  const { locked, released } = entries;
  const hasLockedChildren = !!(locked.length);
  const hasReleasedChildren = !!(released.length);

  const [showLocked, updateShowLocked] = useState(false);
  const [showReleased, updateShowReleased] = useState(false);

  useEffect(() => {
      updateShowLocked(true);
      updateShowReleased(true);
    },
    []);

  return (
    <S.CardArea>
      {(hasReleasedChildren && showReleased)
        && (
          <CardColumn
            id='card-column-released-entries'
            css='                   ◀◀◀ TRIGGERS THE ERROR
              margin-left = 2rem;   ◀◀◀ TRIGGERS THE ERROR
              margin-right = 1rem;  ◀◀◀ TRIGGERS THE ERROR
            '                       ◀◀◀ TRIGGERS THE ERROR
            heading='Unlocked'
            Card={ReleasedEntryCard}

      /* ommitted */

CardArea.propTypes = {
    /* ommitted */
};

export default CardArea;

=================================================================

Webpack configuration (webpack.config.js):

Aliases are towards the bottom.

const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const Dotenv = require('dotenv-webpack');
const path = require('path');

const config = {
  entry: './src/index.jsx',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        use: 'babel-loader',
        exclude: /node_modules/,
      },
      {
        test: /\.jsx?$/,
        include: /node_modules/,
        use: ['react-hot-loader/webpack'],
      },
      {
        test: /\.css$/,
        use: [
          'style-loader',
          'css-loader/locals',
        ],
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'less-loader',
        ],
      },
      {
        test: /\.png$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              mimetype: 'image/png',
            },
          },
        ],
      },
    ],
  },
  node: {
    console: true,
    fs: 'empty',
    net: 'empty',
    tls: 'empty',
  },
  plugins: [
    new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /en/),
  ],
  plugins: [
    new CopyWebpackPlugin([
      // relative path is from src
      { from: './static/favicon.ico' }, // <- your path to favicon
    ]),
    new Dotenv({
      systemvars: true,
    }),
  ],
  devServer: {
    contentBase: './dist',
  },
  resolve: {
    extensions: ['.js', '.jsx', '.css'],
    alias: {
      components: path.resolve(__dirname, 'src/indexes/components.jsx'),
      contexts: path.resolve(__dirname, 'src/indexes/contexts.jsx'),
      theme: path.resolve(__dirname, 'src/indexes/theme.jsx'),
      utilities: path.resolve(__dirname, 'src/indexes/utilities.jsx'),
    },
  },
};

module.exports = config;

Babel Config (.bablerc):

{
  presets: [
    [
      '@babel/preset-env',
      {
        modules: false
      }
    ],
    '@babel/preset-react'
  ],
  plugins: [
    'react-hot-loader/babel',
    '@babel/plugin-proposal-class-properties',
    '@babel/plugin-transform-react-jsx-source',
    [
      'babel-plugin-styled-components',
      {
        "ssr": false
      }
    ],
  ]
}

Dependencies (Package.json)

{
  "name": "timelockr",
  "version": "1.0.0",
  "description": "Making information inaccessible.",
  "main": "index.js",
  "keywords": [],
  "author": "",
  "license": "ISC",
  "repository": {
    "type": "git",
    "url": "https://github.com/jehillert/Keep-Away"
  },
  "scripts": {
    "clean": "rm dist/bundle.js",
    "build-dev": "webpack -d --mode development",
    "build-prod": "webpack -p --mode production",
    "dev-server": "nodemon --ignore node_modules --inspect server",
    "start": "webpack-dev-server --host 0.0.0.0 --hot --mode development",
    "start:dev": "nodenv -f .",
    "lint:css": "stylelint './src/**/*.js'"
  },
  "dependencies": {
    "@date-io/date-fns": "^1.1.0",
    "@date-io/moment": "^1.1.0",
    "@material-ui/core": "^3.9.3",
    "@material-ui/icons": "^3.0.2",
    "@material-ui/styles": "^4.0.0-alpha.4",
    "@material-ui/system": "^3.0.0-alpha.2",
    "ajv": "^6.10.0",
    "axios": "^0.18.0",
    "bluebird": "^3.5.3",
    "body-parser": "^1.18.3",
    "bootstrap": "^4.3.1",
    "classnames": "^2.2.6",
    "cors": "^2.8.5",
    "date-fns": "^2.0.0-alpha.27",
    "debug": "^4.1.1",
    "dotenv-webpack": "^1.7.0",
    "express": "^4.16.4",
    "express-mysql-session": "^2.1.0",
    "express-session": "^1.15.6",
    "jquery": "^3.3.1",
    "less": "^3.9.0",
    "material-ui-pickers": "^2.2.4",
    "moment": "^2.24.0",
    "mysql": "^2.16.0",
    "notistack": "^0.6.1",
    "pbkdf2-password": "^1.2.1",
    "prop-types": "^15.7.2",
    "react": "^16.8.6",
    "react-bootstrap": "^1.0.0-beta.6",
    "react-copy-to-clipboard": "^5.0.1",
    "react-dom": "^16.8.6",
    "react-hot-loader": "^4.8.2",
    "react-router-dom": "^5.0.0",
    "react-transition-group": "^2.7.1",
    "styled-components": "^4.2.0",
    "typeface-roboto": "0.0.54"
  },
  "devDependencies": {
    "@babel/core": "^7.4.0",
    "@babel/plugin-proposal-class-properties": "^7.4.0",
    "@babel/preset-env": "^7.4.2",
    "@babel/preset-react": "^7.0.0",
    "async": "^2.6.2",
    "babel-eslint": "^10.0.1",
    "babel-loader": "^8.0.5",
    "babel-plugin-styled-components": "^1.10.0",
    "babel-plugin-transform-react-jsx-source": "^6.22.0",
    "copy-webpack-plugin": "^5.0.2",
    "css-loader": "^1.0.0",
    "eslint": "^5.16.0",
    "eslint-config-airbnb": "^17.1.0",
    "eslint-import-resolver-webpack": "^0.11.0",
    "eslint-plugin-import": "^2.16.0",
    "eslint-plugin-jsx-a11y": "^6.2.1",
    "eslint-plugin-react": "^7.12.4",
    "eslint-plugin-react-hooks": "^1.6.0",
    "eslint_d": "^7.3.0",
    "faker": "^4.1.0",
    "less-loader": "^4.1.0",
    "node-cmd": "^3.0.0",
    "nodemon": "^1.18.10",
    "style-loader": "^0.23.1",
    "stylelint": "^9.10.1",
    "stylelint-config-recommended": "^2.1.0",
    "stylelint-config-styled-components": "^0.1.1",
    "stylelint-processor-styled-components": "^1.6.0",
    "url-loader": "^1.1.2",
    "webpack": "^4.29.6",
    "webpack-cli": "^3.3.0",
    "webpack-dev-server": "^3.2.1"
  }
}

like image 505
jehillert Avatar asked Oct 27 '25 17:10

jehillert


1 Answers

The following github issues from the arc repo seem to describe problems similar to the one you are having here: #339, #130. The last issue specifically has this comment which suggests a potential solution. By styling in the following manner in most cases the problem is said to be resolved:

const StyledCComponent = styled(props => <CComponent {...props} />)``

The root underlying cause seem to be a circular dependency issue. By wrapping the component in a function the dependency is evaluated at runtime.

like image 176
etarhan Avatar answered Oct 29 '25 07:10

etarhan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!