I’m using Twin.macro with Next.JS 14, NX and emotion. I’ve followed the example of Twin.macro and either I keep running into errors as v8
doesn’t exist or Twin.macro is executed at run time
What am I trying to do? use SSR with Twin.macro
What is happening? Twin.macro is executed at run time/
My question? How can I reconfigure my code to use SSR.
next.config.mjs
//@ts-check
import { composePlugins, withNx } from '@nx/next';
import remarkGfm from 'remark-gfm';
import createMDX from '@next/mdx';
import { withSentryConfig } from '@sentry/nextjs';
import withTwin from './withTwin.mjs';
/**
* @type {import('@nx/next/plugins/with-nx').WithNxOptions}
**/
const nextConfig = {
typescript: {
// !! WARN !!
// Dangerously allow production builds to successfully complete even if
// your project has type errors.
// !! WARN !!
ignoreBuildErrors: true,
},
nx: {
// Set this to true if you would like to to use SVGR
// See: https://github.com/gregberge/svgr
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'],
swcMinify: false, // Ensure SWC is used for minification
images: {
domains: [],
},
// reactStrictMode: true,
compiler: {
// For other options, see https://nextjs.org/docs/architecture/nextjs-compiler#emotion
emotion: true,
},
};
const withMDX = createMDX({
// Add markdown plugins here, as desired
extension: /.mdx?$/,
// @ts-ignore
pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'],
options: {
remarkPlugins: [remarkGfm],
rehypePlugins: [],
},
});
const sentryWebpackPluginOptions = {
// Additional config options for the Sentry webpack plugin. Keep in mind that
// the following options are set automatically, and overriding them is not
// recommended:
// release, url, configFile, stripPrefix, urlPrefix, include, ignore
org: 's',
project: '',
// An auth token is required for uploading source maps.
authToken: process.env.SENTRY_AUTH_TOKEN,
silent: true, // Suppresses all logs
// For all available options, see:
// https://github.com/getsentry/sentry-webpack-plugin#options.
};
const plugins = [
// Add more Next.js plugins to this list if needed.
// @ts-ignore
(nextConfig) => withSentryConfig(nextConfig, sentryWebpackPluginOptions),
withNx,
withMDX,
withTwin,
];
// @ts-ignore
export default composePlugins(...plugins)(nextConfig);
.babelrc
{
"presets": ["next/babel"],
"plugins": [
[
"babel-plugin-macros"
],
[
"@emotion/babel-plugin",
{
"sourceMap": true,
"autoLabel": "dev-only",
"labelFormat": "[local]",
"cssPropOptimization": true
}
]
]
}
withTwin.mjs
// @ts-check
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';
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
// The folders containing files importing twin.macro
const includedDirs = [
path.resolve(__dirname, './'),
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 || [];
config.module.rules.push({
test: /.(tsx|ts)$/,
include: includedDirs,
use: [
{
loader: 'babel-loader',
options: {
sourceMaps: options.dev,
plugins: [
babelPluginTwin, // Optional
[
babelPluginMacros,
{
twin: {
config: path.resolve(__dirname, 'tailwind.config.js'),
},
},
],
[babelPluginTypescript, { isTSX: true }],
],
},
},
],
});
if (typeof nextConfig.webpack === 'function')
return nextConfig.webpack(config, options);
return config;
},
};
}