ben-rogerson / twin.examples

Packed with examples for different frameworks, this repo helps you get started with twin a whole lot faster.
463 stars 129 forks source link

Can't resolve 'styled-components/jsx-dev-runtime' #131

Closed salman15 closed 1 month ago

salman15 commented 1 month ago

I'm running Next.JS with NX and am trying can not seem to run twin.macro

I keep running into an error: Can't resolve 'styled-components/jsx-dev-runtime'

What am I doing wrong in my configuration?

my setup:

withTwin.mjs


import babelPluginTypescript from '@babel/plugin-syntax-typescript';
import babelPluginMacros from 'babel-plugin-macros';
import * as path from 'path';
import * as url from 'url';
import babelPluginTwin from 'babel-plugin-twin';
import babelPluginStyledComponents from 'babel-plugin-styled-components';
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));

// The folders containing files importing twin.macro
const includedDirs = [
  path.resolve(__dirname, 'app'),
  path.resolve(__dirname, 'components'),
  path.resolve(__dirname, 'modules'),
  path.resolve(__dirname, 'styles'),
  path.resolve(__dirname, 'registry'),
  path.resolve(__dirname, '../../../libs/ui-web/src'),
];

/** @returns {import('next').NextConfig} */
export default function withTwin(
  /** @type {import('next').NextConfig} */
  nextConfig
) {
  return {
    ...nextConfig,
    webpack(
      /** @type {import('webpack').Configuration} */
      config,
      options
    ) {
      config.module = config.module || {};
      config.module.rules = config.module.rules || [];

      if (!options.isServer) {
        config.resolve.fallback = {
          fs: false,
          module: false,
          path: false,
          perf_hooks: false,
          v8: false,
        };
      }

      config.module.rules.push({
        test: /\.(tsx|ts)$/,
        include: includedDirs,
        use: [
          options.defaultLoaders.babel,
          {
            loader: 'babel-loader',
            options: {
              sourceMaps: options.dev,
              plugins: [
                [babelPluginTwin, { debug: true }], // Optional
                [
                  babelPluginStyledComponents,
                  {
                    ssr: true,
                    displayName: true,
                  },
                ],
                babelPluginMacros,
                [babelPluginTypescript, { isTSX: true }],
              ],
            },
          },
        ],
      });

      if (typeof nextConfig.webpack === 'function')
        return nextConfig.webpack(config, options);

      return config;
    },
  };
}

.babelrc.


{
  "presets":  [
    [
      "next/babel",
      {
        "preset-react": {
          "runtime": "automatic",
          "importSource": "styled-components",
        },
      },
    ],
  ],
  "plugins": [
    [
      "babel-plugin-twin",
      {
        "debug": false
      }
    ],
    "babel-plugin-macros",
    [
      "babel-plugin-styled-components",
      {
        "ssr": true,
        "displayName": true
      }
    ]
  ]
}

next.config.mjs


//@ts-check

import { composePlugins, withNx } from '@nx/next';
import { withSentryConfig } from '@sentry/nextjs';
import withTwin from './plugins/withTwin.mjs';
import withMDX from './plugins/withMDX.mjs';
import sentryWebpackPluginOptions from './sentry/options.mjs';

/**
 * @type {import('@nx/next/plugins/with-nx').WithNxOptions}
 **/
const nextConfig = {
  // experimental: {
  //   forceSwcTransforms: true,
  // },
  // swcMinify: true,
  compiler: {
    styledComponents: true,
  },
  typescript: {
    ignoreBuildErrors: true,
  },
  nx: {
    svgr: false,
  },
  env: {
    STRIPE_PUBLIC_KEY: process.env.STRIPE_PUBLIC_KEY,
    GRAPHQL_URL: process.env.GRAPHQL_URL,
    GRAPHQL_URL_WS: process.env.GRAPHQL_URL_WS,
    APP_URL: process.env.APP_URL,
    BE_URL: process.env.BE_URL,
  },
  pageExtensions: ['js', 'jsx', 'md', 'mdx', 'ts', 'tsx'],
  reactStrictMode: true,
};

const plugins = [
  withNx,
  withMDX,
  withTwin,
  // @ts-ignore
  (nextConfig) => withSentryConfig(nextConfig, sentryWebpackPluginOptions),
];

// @ts-ignore
export default composePlugins(...plugins)(nextConfig);
salman15 commented 1 month ago

Found this solution for emotion and here is my implementation:

'use client';
import { CacheProvider } from '@emotion/react';
import createCache from '@emotion/cache';
import { useServerInsertedHTML } from 'next/navigation';
import { FC, PropsWithChildren, useState } from 'react';

const RootStyleRegistry: FC<PropsWithChildren> = ({ children }) => {
  const [cache] = useState(() => {
    const cache = createCache({ key: 'css' });
    cache.compat = true;
    return cache;
  });

  useServerInsertedHTML(() => {
    return (
      <style
        data-emotion={`${cache.key} ${Object.keys(cache.inserted).join(' ')}`}
        dangerouslySetInnerHTML={{
          __html: Object.values(cache.inserted).join(' '),
        }}
      />
    );
  });

  return <CacheProvider value={cache}>{children}</CacheProvider>;
};

export default RootStyleRegistry;