1

So I'm trying to build my Next.js project, which, for context, was being deployed without a problem, up until my main branch. When I then tried to implement mdx, with rehype and shiki, and tried to deploy that's what I got the errors. So trying to push the shiki-lol branch, that's when I get the error.

npm run dev works perfectly btw.

Deploying to Vercel or locally running npm run build, whichever I run, it doesn't work. I'm getting the following output:

> [email protected] build
> next build

   ▲ Next.js 15.2.1

   Creating an optimized production build ...
Failed to compile.

HookWebpackError: Cannot read properties of undefined (reading '0')
    at makeWebpackError (C:\Users\Santi\Documents\PERSONAL\code\WEB\santiu\node_modules\next\dist\compiled\webpack\bundle5.js:29:315788)
    at C:\Users\Santi\Documents\PERSONAL\code\WEB\santiu\node_modules\next\dist\compiled\webpack\bundle5.js:29:106487
    at eval (eval at create (C:\Users\Santi\Documents\PERSONAL\code\WEB\santiu\node_modules\next\dist\compiled\webpack\bundle5.js:14:9224), <anonymous>:44:1)
TypeError: Cannot read properties of undefined (reading '0')        
    at C:\Users\Santi\Documents\PERSONAL\code\WEB\santiu\static\css\f5a335e585685605.css:204:23247
    at Parser.attribute (C:\Users\Santi\Documents\PERSONAL\code\WEB\santiu\node_modules\next\dist\compiled\cssnano-simple\index.js:320:84899)
    at Parser.parse (C:\Users\Santi\Documents\PERSONAL\code\WEB\santiu\node_modules\next\dist\compiled\cssnano-simple\index.js:320:99055)
    at Parser.loop (C:\Users\Santi\Documents\PERSONAL\code\WEB\santiu\node_modules\next\dist\compiled\cssnano-simple\index.js:320:98727)
    at new Parser (C:\Users\Santi\Documents\PERSONAL\code\WEB\santiu\node_modules\next\dist\compiled\cssnano-simple\index.js:320:84494) 
    at Processor._root (C:\Users\Santi\Documents\PERSONAL\code\WEB\santiu\node_modules\next\dist\compiled\cssnano-simple\index.js:320:101743)
    at Processor._runSync (C:\Users\Santi\Documents\PERSONAL\code\WEB\santiu\node_modules\next\dist\compiled\cssnano-simple\index.js:320:102250)
    at Processor.processSync (C:\Users\Santi\Documents\PERSONAL\code\WEB\santiu\node_modules\next\dist\compiled\cssnano-simple\index.js:320:103005)
    at C:\Users\Santi\Documents\PERSONAL\code\WEB\santiu\node_modules\next\dist\compiled\cssnano-simple\index.js:320:39339
    at Array.every (<anonymous>)
    at ensureCompatibility (C:\Users\Santi\Documents\PERSONAL\code\WEB\santiu\node_modules\next\dist\compiled\cssnano-simple\index.js:320:38727)
caused by plugins in Compilation.hooks.processAssets
TypeError: Cannot read properties of undefined (reading '0')        
    at C:\Users\Santi\Documents\PERSONAL\code\WEB\santiu\static\css\f5a335e585685605.css:204:23247
    at Parser.attribute (C:\Users\Santi\Documents\PERSONAL\code\WEB\santiu\node_modules\next\dist\compiled\cssnano-simple\index.js:320:84899)
    at Parser.parse (C:\Users\Santi\Documents\PERSONAL\code\WEB\santiu\node_modules\next\dist\compiled\cssnano-simple\index.js:320:99055)
    at Parser.loop (C:\Users\Santi\Documents\PERSONAL\code\WEB\santiu\node_modules\next\dist\compiled\cssnano-simple\index.js:320:98727)
    at new Parser (C:\Users\Santi\Documents\PERSONAL\code\WEB\santiu\node_modules\next\dist\compiled\cssnano-simple\index.js:320:84494) 
    at Processor._root (C:\Users\Santi\Documents\PERSONAL\code\WEB\santiu\node_modules\next\dist\compiled\cssnano-simple\index.js:320:101743)
    at Processor._runSync (C:\Users\Santi\Documents\PERSONAL\code\WEB\santiu\node_modules\next\dist\compiled\cssnano-simple\index.js:320:102250)
    at Processor.processSync (C:\Users\Santi\Documents\PERSONAL\code\WEB\santiu\node_modules\next\dist\compiled\cssnano-simple\index.js:320:103005)
    at C:\Users\Santi\Documents\PERSONAL\code\WEB\santiu\node_modules\next\dist\compiled\cssnano-simple\index.js:320:39339
    at Array.every (<anonymous>)
    at ensureCompatibility (C:\Users\Santi\Documents\PERSONAL\code\WEB\santiu\node_modules\next\dist\compiled\cssnano-simple\index.js:320:38727)

It appears to be a problem with cssnano-simple, but I can't quite pinpoint why it's happening, anyone knows what the issue could be?? AI hasn't been useful either.

I will show relevant code snippets and package.json info, but regardless the full project is in the repo.

next.config.mjs

import nextMDX from '@next/mdx';
import createNextIntlPlugin from 'next-intl/plugin';
import process from 'node:process';
import rehypePrettyCode from 'rehype-pretty-code';
import remarkUnwrapImages from 'remark-unwrap-images';
Object.assign(process.env, { NEXT_TELEMETRY_DISABLED: '1' });

const plugins = [];

const nextConfig = {
    reactStrictMode: true,
    poweredByHeader: false,

    experimental: {
        optimizePackageImports: ['lucide-react', '@vercel/analytics'],
        optimizeCss: false,
    },
    pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'],
    devIndicators: {
        position: 'bottom-right',
    },
    images: {
        formats: ['image/avif', 'image/webp'],
        deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
        imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
        minimumCacheTTL: 60,
        dangerouslyAllowSVG: true,
        contentDispositionType: 'attachment',
        contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
        remotePatterns: [
            { protocol: 'https', hostname: 'via.placeholder.com' },
            { protocol: 'https', hostname: 'robohash.org' },
        ],
    },
    env: {
        NEXT_TELEMETRY_DISABLED: '1',
    },
};

/** @type {import('rehype-pretty-code').Options} */
const rehypePrettyCodeOptions = {
    theme: 'catppuccin-macchiato',
    keepBackground: false,
    defaultLang: 'plaintext',

    // Optimize performance
    grid: false, // Disable grid layout for faster rendering

    // Prevent lines from collapsing
    onVisitLine(node) {
        if (node.children.length === 0) {
            node.children = [{ type: 'text', value: ' ' }];
        }
    },

    // Add class to highlighted lines
    onVisitHighlightedLine(node) {
        if (!node.properties.className) {
            node.properties.className = [];
        }
        node.properties.className.push('highlighted');
    },

    // Add class to highlighted words
    onVisitHighlightedChars(node) {
        node.properties.className = ['word'];
    },
};

// Push MDX plugin
plugins.push(
    nextMDX({
        extension: /\.(md|mdx)$/,
        options: {
            remarkPlugins: [remarkUnwrapImages],
            rehypePlugins: [[rehypePrettyCode, rehypePrettyCodeOptions]],
        },
    })
);

// Push next-intl plugin
plugins.push(createNextIntlPlugin());

export default () =>
    plugins.reduce((config, plugin) => plugin(config), nextConfig);

package.json

{
    "name": "santiu",
    "version": "0.1.0",
    "private": true,
    "type": "module",
    "scripts": {
        "dev": "next dev ",
        "build": "next build",
        "start": "next start",
        "lint": "next lint"
    },
    "dependencies": {
        "@heroicons/react": "^2.2.0",
        "@mdx-js/loader": "^3.1.1",
        "@mdx-js/react": "^3.1.1",
        "@next/mdx": "^16.0.1",
        "@tailwindcss/typography": "^0.5.16",
        "@types/mdx": "^2.0.13",
        "@vercel/analytics": "^1.5.0",
        "clsx": "^2.1.1",
        "framer-motion": "^12.4.11",
        "next": "^15.2.1",
        "next-intl": "^4.0.1",
        "next-themes": "^0.4.5",
        "react": "^19.0.0",
        "react-dom": "^19.0.0",
        "react-icons": "^5.5.0",
        "rehype-pretty-code": "^0.14.1",
        "remark-unwrap-images": "^4.0.1",
        "santiu": "file:",
        "sharp": "^0.34.5",
        "shiki": "^3.15.0",
        "tailwind-merge": "^3.0.2"
    },
    "devDependencies": {
        "@eslint/eslintrc": "^3",
        "@tailwindcss/postcss": "^4",
        "@types/node": "^20",
        "@types/react": "^19",
        "@types/react-dom": "^19",
        "autoprefixer": "^10.4.21",
        "eslint": "^9",
        "eslint-config-next": "15.2.1",
        "tailwindcss": "^4",
        "typescript": "^5"
    }
}

styles/globals.css

@import 'tailwindcss';

@layer base {
    :root {
        --background: #ffffff;
        --foreground: #171717;
        --foreground-rgb: 23, 23, 23;
        color-scheme: dark;
    }

    [data-theme='dark'] {
        --background: #171717;
        --foreground: #fff;
        --foreground-rgb: 237, 237, 237;
    }

    html {
        @apply max-h-screen antialiased;
        font-family: var(--font-inter), sans-serif;
        background: var(--background);
        color: var(--foreground);
        transition: background-color 0.3s ease-in-out;
        min-height: 100vh;
        min-height: -webkit-fill-available;
        will-change: background-color;
    }

    * {
        box-sizing: border-box;
        font-family: var(--font-inter), sans-serif;
    }

    body {
        @apply transition-colors duration-300 m-0 p-0;
        min-height: 100vh;
        min-height: -webkit-fill-available;
        font-family: var(--font-inter), sans-serif;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
    }

    /* Code font family */
    code,
    pre {
        font-family: 'SF Mono', 'Monaco', 'Menlo', 'Consolas', 'Liberation Mono',
            'Courier New', monospace !important;
    }

    /* Control tab size */
    pre {
        tab-size: 2;
        -moz-tab-size: 2;
        @apply !px-0 rounded-lg;
    }

    code {
        @apply text-sm md:text-base;
    }

    pre > code {
        counter-reset: line;
    }

    /* Enhanced scrollbar for code blocks */
    pre::-webkit-scrollbar {
        height: 8px;
    }

    pre::-webkit-scrollbar-track {
        background: #161b22;
    }

    pre::-webkit-scrollbar-thumb {
        background: #30363d;
        border-radius: 4px;
    }

    pre::-webkit-scrollbar-thumb:hover {
        background: #484f58;
    }

    .capsize::before {
        content: '';
        margin-bottom: -0.098em;
        display: table;
    }

    .capsize::after {
        content: '';
        margin-top: -0.219em;
        display: table;
    }
}

.font-menlo {
    font-family: var(--font-menlo);
    font-weight: 100;
    text-transform: uppercase;
}

.font-menlo-thin {
    font-family: var(--font-menlo);
    font-weight: 400;
    font-size: 0.825rem;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: rgba(var(--foreground-rgb), 0.55);
    opacity: 0.9;
}

@layer components {
    button {
        @apply select-none;
        -webkit-touch-callout: none;
        -webkit-user-select: none;
        -khtml-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none;
        -webkit-tap-highlight-color: transparent;
    }
}

@layer utilities {
    .text-primary {
        color: var(--foreground);
    }
    .text-secondary {
        color: rgba(var(--foreground-rgb), 0.8);
    }
    .text-tertiary {
        color: rgba(var(--foreground-rgb), 0.6);
    }
    .text-quaternary {
        color: rgba(var(--foreground-rgb), 0.4);
    }
}

/* MDX prose container */
.prose-mdx {
    max-width: 78ch;
    margin: 0 auto;
}

.prose {
    @apply max-w-220 sm:text-lg md:text-xl !leading-7 sm:!leading-9;
}

/* ============================================ */
/* REHYPE-PRETTY-CODE THEME SUPPORT */
/* ============================================ */

/* Light/Dark theme handling with Shiki variables */
code[data-theme*=' '],
code[data-theme*=' '] span {
    color: var(--shiki-light);
    background-color: var(--shiki-light-bg);
}

@media (prefers-color-scheme: dark) {
    code[data-theme*=' '],
    code[data-theme*=' '] span {
        color: var(--shiki-dark);
        background-color: var(--shiki-dark-bg);
    }
}

/* ============================================ */
/* CODE BLOCK STRUCTURE */
/* ============================================ */

/* Figure wrapper for code blocks */
figure[data-rehype-pretty-code-figure] {
    @apply shadow-xl mb-6 mt-1 rounded-lg border border-neutral-700 overflow-hidden;
}

/* Pre styling */
figure[data-rehype-pretty-code-figure] pre {
    @apply m-0 p-6 bg-neutral-800/50;
}

/* Main code block styling */
pre [data-line] {
    @apply px-4 border-l-2 border-l-transparent;
    line-height: 1.4; /* Control line spacing here too */
}

/* ============================================ */
/* LINE NUMBERS */
/* ============================================ */

code[data-line-numbers] {
    counter-reset: line;
}

code[data-line-numbers] > [data-line]::before {
    counter-increment: line;
    content: counter(line);
    @apply inline-block w-4 mr-4 text-right text-gray-500;
}

/* ============================================ */
/* HIGHLIGHTING */
/* ============================================ */

/* Highlighted lines */
[data-highlighted-line] {
    background: rgba(200, 200, 255, 0.1);
    @apply border-l-blue-400;
}

/* Highlighted characters/words */
[data-highlighted-chars] {
    @apply bg-zinc-600/50 rounded;
    box-shadow: 0 0 0 4px rgb(82 82 91 / 0.5);
}

/* Custom character highlighting with IDs */
[data-chars-id] {
    @apply shadow-none p-1 border-b-2;
}

[data-chars-id] span {
    @apply !text-inherit;
}

[data-chars-id='v'] {
    @apply !text-pink-300 bg-rose-800/50 border-b-pink-600 font-bold;
}

[data-chars-id='s'] {
    @apply !text-yellow-300 bg-yellow-800/50 border-b-yellow-600 font-bold;
}

[data-chars-id='i'] {
    @apply !text-purple-200 bg-purple-800/50 border-b-purple-600 font-bold;
}

/* ============================================ */
/* CODE BLOCK TITLE */
/* ============================================ */

[data-rehype-pretty-code-title] {
    @apply border-b border-neutral-700/20 bg-neutral-800/50 text-neutral-100 rounded-t-lg py-2 pb-2.5 pl-5 text-sm underline;
}

/* Remove top border radius from pre when title exists */
figure[data-rehype-pretty-code-figure]:has(> [data-rehype-pretty-code-title])
    pre {
    @apply !rounded-t-none;
}

/* ============================================ */
/* INLINE CODE */
/* ============================================ */
/* text-blue-300 */
:not(pre) > code {
    @apply font-mono text-sm bg-neutral-800/70 text-blue-300 px-1.5 py-0.5 rounded border border-neutral-700/50;
}

/* h3 inline code sizing */
h3 code {
    @apply !text-lg md:!text-xl;
}

/* ============================================ */
/* OVERFLOW HANDLING */
/* ============================================ */

pre,
code,
figure {
    @apply overflow-x-auto;
}

/* p {
    @apply text-xl;
}

article p {
    @apply leading-9;
} */

[data-rehype-pretty-code-figure] span {
    font-family: 'SF Mono', 'Monaco', 'Menlo', 'Consolas', 'Liberation Mono',
        'Courier New', monospace !important;
    @apply text-sm;
}

mdx-components.tsx

import type { MDXComponents } from 'mdx/types';
import Link from 'next/link';

export function useMDXComponents(components: MDXComponents): MDXComponents {
    return {
        h1: ({ children }) => (
            <h1 className='text-lg font-bold text-neutral-100 leading-tight'>
                {children}
            </h1>
        ),
        h2: ({ children }) => (
            <h2 className='font-menlo-thin scroll-mt-20 !text-xs mt-30 mb-6 leading-tight'>
                {children}
            </h2>
        ),
        p: ({ children }) => (
            <p className='mb-6 leading-[1.75] text-base md:text-lg text-neutral-300'>
                {children}
            </p>
        ),
        a: ({ href, children }) => {
            if (href?.startsWith('http')) {
                return (
                    <a
                        href={href}
                        className='text-blue-400 underline underline-offset-2 hover:text-blue-300 transition-colors'
                        target='_blank'
                        rel='noopener noreferrer'
                    >
                        {children}
                    </a>
                );
            }
            return (
                <Link
                    href={href || ''}
                    className='text-blue-400 underline underline-offset-2 hover:text-blue-300 transition-colors'
                >
                    {children}
                </Link>
            );
        },
        ul: ({ children }) => (
            <ul className='list-disc list-inside mb-6 space-y-2 text-base md:text-lg text-neutral-300'>
                {children}
            </ul>
        ),
        ol: ({ children }) => (
            <ol className='list-decimal list-inside mb-6 space-y-2 text-base md:text-lg text-neutral-300'>
                {children}
            </ol>
        ),
        li: ({ children }) => <li className='leading-[1.75]'>{children}</li>,
        blockquote: ({ children }) => (
            <blockquote className='border-l-4 border-neutral-600 pl-6 py-2 my-6 italic text-neutral-400'>
                {children}
            </blockquote>
        ),
        img: (props) => (
            <figure className='my-12 -mx-4 md:-mx-12 lg:-mx-24'>
                <img
                    {...props}
                    className='w-full h-auto rounded-none md:rounded-lg shadow-2xl'
                    loading='lazy'
                />
                {props.alt && (
                    <figcaption className='text-center text-xs text-neutral-500 mt-4 px-4'>
                        {props.alt}
                    </figcaption>
                )}
            </figure>
        ),
        hr: () => <hr className='my-12 border-t border-neutral-800' />,
        ...components,
    };
}
4
  • Starting from TailwindCSS v4, the important modifier should be written after the class (bg-red-500!) instead of before it (!bg-red-500). Starting from TailwindCSS v4, you need to use @custom-variant for the dark: variant. Dark and light modes can be handled like this: stackoverflow.com/a/79499827/15167500 Commented Nov 11 at 8:11
  • Starting from TailwindCSS v4, using @utility better than @layer utilities. However, for something like text-primary, you don't need to create a utility - just define a new color in @theme, --color-primary: var(--foreground). I think you should read through the breaking changes documentation. -- What's breaking changes from v4 --- Useful references for v4 Commented Nov 11 at 8:19
  • And yes, AI can't learn in your place - especially if it doesn't have the necessary knowledge. TailwindCSS v4 was released in January 2025, but most AI models, especially free ones, are trained on data from 2023. Moreover, AI can mix up different versions - for example, v3 with v4 - if it hasn't been specifically trained not to, which means you'll just keep stacking errors. As a result, your "portfolio" project will give the impression that you couldn't have done it on your own. Commented Nov 11 at 8:20
  • 1
    @rozsazoltan I appreciate the help, you're correct, specifically with the tailwind classes I was getting heavily assisted by AI, I decided to take a look at the docs and improve certain areas I could. This did not fix the issue though. Commented Nov 15 at 6:42

1 Answer 1

1

Unfortunately the only fix I found was adding this to my next.config.mjs

webpack: (config) => {
    config.optimization.minimize = false;
    return config;
},

And the code runs properly with no build errors, or console errors or warnings. I don't know what causes this settings being turned on, to not function.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.