Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Styled components: babel-plugin-styled-components not working

I've been trying to get the babel-plugin-styled-components plugin to work with my webpack/babelrc configuration but I have not been able to do so. I am using babel-loader and no matter what I try I can't get the plugin to be recognised.

I am using Typescript 4 and Webpack 4.

I've searched and tried a number of proposed solutions but none have worked. I even tried the typescript-styled-components-plugin solution (https://github.com/Igorbek/typescript-plugin-styled-components), but no matter what it seems that the plugin is not recognised and the settings do not work.

I can only imagine that it's an issue with my configuration. Webpack is still a bit of a mystery to me in general.

My webpack.common.js file looks like this:

module.exports = [
  {
    context,
    cache: local,
    devtool: 'inline-source-map',
    mode: 'development',
    resolve: {
      symlinks: false,
      alias: {
        'app.veams$': `${context}/app.veams.tsx`,
        env: envFile
      },
      extensions: ['.ts', '.tsx', '.js']
    },
    // Entry point for webpack
    entry: {
      app: `${context}/app.tsx`
    },
    // Output directory and filename
    output: {
      filename: 'scripts/[name].bundle.js',
      chunkFilename: 'scripts/[name].chunk.js',
      path: outputPath,
      pathinfo: !local // Performance #2: Garbage Collection
    },
    // Tell webpack to run babel on every file it runs through
    module: {
      rules: [
        {
          test: /\.js$/,
          exclude: /node_modules/,
          use: [
            {
              loader: 'babel-loader',
              options: {
                babelrc: true,
                // This is a feature of `babel-loader` for webpack (not Babel itself).
                // It enables caching results in ./node_modules/.cache/babel-loader/
                // directory for faster rebuilds.
                cacheDirectory: true,
                // Let's add babel presets ...
                presets: [
                  '@babel/preset-react',
                  [
                    '@babel/preset-env',
                    {
                      targets: {
                        browsers: ['last 2 versions', 'ie >= 11']
                      }
                    }
                  ]
                ],
                // ... and plugins.
                plugins: [
                  '@babel/plugin-proposal-function-bind',
                  // Stage 2
                  [
                    '@babel/plugin-proposal-decorators',
                    {
                      legacy: true
                    }
                  ],
                  [
                    '@babel/plugin-proposal-class-properties',
                    {
                      loose: false
                    }
                  ]
                ]
              }
            }
          ]
        },
        scriptRule(configContext),
        styleRule(),
        assetsRule()
      ]
    },
    plugins: [].concat(scriptPlugins(configContext), stylePlugins(configContext)),
    // Some libraries import Node modules but don't use them in the browser.
    // Tell Webpack to provide empty mocks for them so importing them works.
    node: {
      dgram: 'empty',
      fs: 'empty',
      net: 'empty',
      tls: 'empty',
      child_process: 'empty'
    },
    // Turn off performance hints during development because we don't do any
    // splitting or minification in interest of speed. These warnings become
    // cumbersome.
    performance: {
      hints: false
    },
    optimization: {
      minimizer: optimizerPlugins(),
      removeAvailableModules: false, // Performance #1: Do not optimize so much in incremental builds
      removeEmptyChunks: false, // Performance #1: Do not optimize so much in incremental builds
      splitChunks: {
        cacheGroups: {
          vendor: {
            test: /node_modules/,
            chunks: 'initial',
            name: 'vendor',
            priority: 10,
            enforce: true
          }
        } // Performance #1: Do not optimize so much in incremental builds
      }
    },
    devServer: {
      contentBase: outputPath,
      compress: false,
      port: 3000,
      proxy: {
        '/': 'http://localhost:2999'
      },
      overlay: {
        warnings: true,
        errors: true
      }
    }
  }
];

The scriptRule file looks like this:

module.exports = function() {
  return {
    test: /\.tsx?$/,
    use: [
      {
        loader: 'cache-loader'
      },
      {
        loader: 'babel-loader',
        options: {
          babelrc: true,
          // This is a feature of `babel-loader` for webpack (not Babel itself).
          // It enables caching results in ./node_modules/.cache/babel-loader/
          // directory for faster rebuilds.
          cacheDirectory: true,
          // Let's add babel presets ...
          presets: [
            '@babel/preset-react',
            [
              '@babel/preset-env',
              {
                targets: {
                  browsers: ['last 2 versions', 'ie >= 11']
                }
              }
            ]
          ],
          // ... and plugins.
          plugins: [
            '@babel/plugin-proposal-function-bind',
            // Stage 2
           [
              'babel-plugin-styled-components',
              {
                displayName: true
              }
            ],
            [
              '@babel/plugin-proposal-decorators',
              {
                legacy: true
              }
            ],
            [
              '@babel/plugin-proposal-class-properties',
              {
                loose: false
              }
            ]
          ]
        }
      },
      {
        loader: 'thread-loader',
        options: {
          // there should be 1 cpu for the fork-ts-checker-webpack-plugin
          workers: require('os').cpus().length - 1
        }
      },
      {
        loader: 'ts-loader',
        options: {
          transpileOnly: true, // Performance #3 :: Limit amount of modules to transpile at a time per iteration
          experimentalWatchApi: true,
          happyPackMode: true // IMPORTANT! use happyPackMode mode to speed-up compilation and reduce errors
          // reported to webpack
        }
      }
    ]
  };
};

.babelrc looks like this:

{
  "env": {
    "client": {
      "presets": [
        [
          "@babel/preset-env",
          {
            "targets": {
              "browsers": ["last 2 versions", "ie >= 11"]
            }
          }
        ],
        "@babel-preset-react"
      ],
      "plugins": [
        "@babel/plugin-proposal-function-bind",
[
          "babel-plugin-styled-components",
          {
            "displayName": true
          }
        ],
        [
          "@babel/plugin-proposal-decorators",
          {
            "legacy": true
          }
        ],
        [
          "@babel/plugin-proposal-class-properties",
          {
            "loose": false
          }
        ]
      ]
    },
    "server": {
      "presets": ["@babel/preset-env"],
      "plugins": [
        "@babel/plugin-proposal-function-bind",
        "@babel/plugin-proposal-export-default-from",
        "@babel/plugin-proposal-logical-assignment-operators",
        [
          "@babel/plugin-proposal-optional-chaining",
          {
            "loose": false
          }
        ],
        [
          "@babel/plugin-proposal-pipeline-operator",
          {
            "proposal": "minimal"
          }
        ],
        [
          "@babel/plugin-proposal-nullish-coalescing-operator",
          {
            "loose": false
          }
        ],
        "@babel/plugin-proposal-do-expressions",
        [
          "@babel/plugin-proposal-decorators",
          {
            "legacy": true
          }
        ],
        "@babel/plugin-proposal-function-sent",
        "@babel/plugin-proposal-export-namespace-from",
        "@babel/plugin-proposal-numeric-separator",
        "@babel/plugin-proposal-throw-expressions",
        "@babel/plugin-syntax-dynamic-import",
        "@babel/plugin-syntax-import-meta",
        [
          "@babel/plugin-proposal-class-properties",
          {
            "loose": false
          }
        ],
        "@babel/plugin-proposal-json-strings",
        "@babel/plugin-transform-runtime"
      ]
    }
  }
}

And finally the package.json looks like this:

"dependencies": {
    "@veams/core": "^1.0.0",
    "@veams/helpers": "^1.2.8",
    "@veams/http-service": "^1.0.2",
    "c3": "0.7.20",
    "carbon-components": "^9.66.3",
    "carbon-components-react": "^6.74.1",
    "carbon-icons": "^7.0.7",
    "connected-react-router": "6.8.0",
    "cors": "2.8.5",
    "downshift": "3.1.5",
    "express-http-proxy": "1.6.2",
    "file-saver": "2.0.2",
    "history": "4.7.2",
    "html-to-react": "1.4.5",
    "immutable": "4.0.0-rc.12",
    "json5": "2.1.3",
    "query-string": "6.13.7",
    "react": "17.0.1",
    "react-c3js": "0.1.20",
    "react-d3-cloud": "0.7.0",
    "react-dom": "17.0.1",
    "react-excel-workbook": "0.0.4",
    "react-redux": "7.2.2",
    "react-router-config": "4.4.0-beta.6",
    "react-router-dom": "5.2.0",
    "redux": "4.0.5",
    "redux-devtools-extension": "2.13.8",
    "redux-immutable": "4.0.0",
    "redux-immutable-state-invariant": "2.1.0",
    "redux-observable": "1.2.0",
    "reselect": "4.0.0",
    "rxjs": "6.6.3",
    "styled-components": "5.2.1",
    "tslib": "2.0.3",
    "xlsx": "0.16.8"
  },
  "devDependencies": {
    "@babel/core": "^7.0.0",
    "@babel/plugin-proposal-class-properties": "^7.0.0",
    "@babel/plugin-proposal-decorators": "^7.0.0",
    "@babel/plugin-proposal-do-expressions": "^7.0.0",
    "@babel/plugin-proposal-export-default-from": "^7.0.0",
    "@babel/plugin-proposal-export-namespace-from": "^7.0.0",
    "@babel/plugin-proposal-function-bind": "^7.0.0",
    "@babel/plugin-proposal-function-sent": "^7.0.0",
    "@babel/plugin-proposal-json-strings": "^7.0.0",
    "@babel/plugin-proposal-logical-assignment-operators": "^7.0.0",
    "@babel/plugin-proposal-nullish-coalescing-operator": "^7.0.0",
    "@babel/plugin-proposal-numeric-separator": "^7.0.0",
    "@babel/plugin-proposal-optional-chaining": "^7.0.0",
    "@babel/plugin-proposal-pipeline-operator": "^7.0.0",
    "@babel/plugin-proposal-throw-expressions": "^7.0.0",
    "@babel/plugin-syntax-dynamic-import": "^7.0.0",
    "@babel/plugin-syntax-import-meta": "^7.0.0",
    "@babel/plugin-transform-runtime": "^7.0.0",
    "@babel/preset-env": "^7.0.0",
    "@babel/preset-react": "^7.0.0",
    "@babel/register": "^7.0.0",
    "@babel/runtime": "^7.0.0",
    "@types/history": "^4.6.2",
    "@types/jest": "^23.3.12",
    "@types/node": "^10.12.18",
    "@types/react": "16.9.56",
    "@types/react-dom": "16.9.9",
    "@types/react-redux": "7.1.11",
    "@types/react-router": "4.4.3",
    "@types/react-router-config": "1.0.7",
    "@types/react-router-dom": "5.1.6",
    "@types/redux-immutable-state-invariant": "2.1.1",
    "babel-core": "^7.0.0-bridge.0",
    "babel-eslint": "^10.0.1",
    "babel-jest": "^23.4.2",
    "babel-loader": "^8.0.5",
    "babel-plugin-styled-components": "1.11.1",
    "babel-plugin-transform-class-properties": "^6.24.1",
    "babel-plugin-transform-decorators-legacy": "^1.3.4",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-preset-env": "^1.6.0",
    "babel-preset-react": "^6.24.1",
    "babel-preset-stage-0": "^6.16.0",
    "babel-preset-stage-1": "^6.24.1",
    "babel-register": "^6.26.0",
    "babel-runtime": "^6.26.0",
    "body-parser": "^1.18.1",
    "browser-sync": "^2.24.4",
    "cache-loader": "^2.0.1",
    "case-sensitive-paths-webpack-plugin": "^2.1.1",
    "chalk": "^2.0.1",
    "command-line-args": "^4.0.7",
    "command-line-usage": "^4.0.2",
    "compression-webpack-plugin": "^2.0.0",
    "connect-browser-sync": "^2.1.0",
    "copy-webpack-plugin": "^4.3.1",
    "cross-env": "^5.0.5",
    "css-loader": "^2.1.0",
    "deep-extend": "^0.6.0",
    "eslint": "^5.12.0",
    "eslint-config-prettier": "^3.4.0",
    "eslint-plugin-prettier": "^3.0.1",
    "express": "^4.16.3",
    "fork-ts-checker-webpack-plugin": "^0.5.2",
    "globby": "^9.0.0",
    "husky": "^1.0.0-rc.8",
    "include-media": "^1.4.8",
    "jshint-stylish": "^2.0.0",
    "lint-staged": "^8.1.5",
    "lodash": "^4.17.4",
    "mini-css-extract-plugin": "^0.5.0",
    "node-sass": "^4.7.2",
    "node-sass-magic-importer": "^5.0.3",
    "nodemon": "^1.14.0",
    "npm-run-all": "^4.1.1",
    "optimize-css-assets-webpack-plugin": "^5.0.1",
    "postcss": "^7.0.11",
    "postcss-cssnext": "^3.1.0",
    "postcss-loader": "^3.0.0",
    "prettier": "^1.13.4",
    "react-dev-utils": "^7.0.1",
    "request": "^2.81.0",
    "rimraf": "^2.6.2",
    "sass-loader": "^7.0.2",
    "style-loader": "^0.23.1",
    "stylelint": "^9.2.0",
    "stylelint-config-prettier": "^5.0.0",
    "stylelint-prettier": "^1.0.6",
    "thread-loader": "^2.1.1",
    "ts-jest": "^23.10.5",
    "ts-loader": "^5.3.3",
    "tslint": "^5.12.0",
    "tslint-config-airbnb": "^5.9.2",
    "tslint-config-prettier": "^1.13.0",
    "tslint-plugin-prettier": "^2.0.1",
    "tslint-react": "^3.6.0",
    "typescript": "4.0.5",
    "uglifyjs-webpack-plugin": "^2.1.1",
    "webpack": "^4.10.2",
    "webpack-cli": "^3.0.1",
    "webpack-dev-server": "^3.1.14",
    "winston": "^2.3.1"
  },

I didn't originally write this webpack config and have tried moving the order of the plugin etc. to no avail.

I hope someone can help...

Cheers!

like image 338
Karl Knuttel Avatar asked May 30 '26 18:05

Karl Knuttel


1 Answers

It seems you may need to add "babel-plugin-macros" before it in your plugins array. I was trawling the web for ages trying to get babel-plugin-styled-components working for Twin in Create React App (which also uses Webpack). I was using CRACO to add babel plugins, but nothing I was doing was working.

I finally stumbled upon this absolutely perfect example repo twin.examples/webpack-styled-components-typescript which contained literally everything I wanted. Here is the .babelrc file it used:

{
  "presets": [
    [
      "@babel/preset-react",
      { "runtime": "automatic" }
    ],
    "@babel/preset-typescript"
  ],
  "plugins": [
    "babel-plugin-twin",
    "babel-plugin-macros",
    "babel-plugin-styled-components"
  ]
}

The plugins part was what I needed, so I just copied it across and everything worked perfectly.

To check it applied to situations without babel-plugin-twin, I removed it from the plugins list and tested my setup using the alternative method for using Twin (adding import "twin.macro" at the top of the file I was styling in). The setup worked, but not if I removed babel-plugins-macro, supporting my theory.

What seems odd is CRA already loads babel-plugins-macro from babel-preset-react-app. I think actually babel-plugins-macro needs to be specifically loaded just before babel-plugin-styled-components, as I tried swapping the order of just those two and it silently broke the styling.

Hope my findings help you or someone else out there!

like image 186
Geoff Davids Avatar answered Jun 01 '26 10:06

Geoff Davids