Styled components: babel-plugin-styled-components not working
Asked Answered
H

1

9

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!

Herringbone answered 17/11, 2020 at 17:14 Comment(2)
You should change your loader to ts-loader instead of babel-loader and then install this github.com/Igorbek/typescript-plugin-styled-componentsTerse
Would be great to know whether you were able to solve this issue :)Lytta
H
3

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!

Haemachrome answered 4/9, 2022 at 10:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.