javascriptreactjsframer-motion

REACT.js Failed to compile: unexpected end of JSON input error


When I run 'npm run build' I get the following error:

> my-app@0.1.0 build
> react-scripts build

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

Unexpected end of JSON input

However, 'npm start' works and the website works locally. This issue only arises when I run 'npm run build'

I've tried a variety of things to fix this issue, rebuilding after each (and trying all of them and then rebuilding):

My package.json passes jsonlint, and I cannot figure out the issue But nothing is working. Here are my files: package.json:

{
  "homepage": "http://[redacted].github.io/",
  "name": "my-website",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "framer-motion": "^10.16.4",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-icons": "^4.11.0",
    "react-scripts": "5.0.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "predeploy": "npm run build",
    "deploy": "gh-pages -d build",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "autoprefixer": "^10.4.14",
    "gh-pages": "^6.1.1",
    "postcss": "^8.4.23",
    "tailwindcss": "^3.3.5"
  }
}

webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'build'),
    filename: 'bundle.js',
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: ['babel-loader'],
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader', 'postcss-loader'],
      },
    ],
  },
  resolve: {
    extensions: ['*', '.js', '.jsx'],
  },
};

tailwind.config.js:

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./src/**/*.{js,jsx,ts,tsx}"],
  theme: {
    extend: {},
  },
  plugins: [],
}

App.js:

import React from 'react';
import HomePage from './components/Homepage';

function App() {
  return (
    <div className="App">
      <HomePage />
    </div>
  );
}

export default App;

Homepage.js:

import React, { useEffect, useRef, useState } from 'react';
import { motion, useScroll, useSpring } from 'framer-motion';
import HeroSection from './HeroSection';
import AboutSection from './AboutSection';
import ProjectsSection from './ProjectsSection';
import SkillsSection from './SkillsSection';
import './styles.css';

const Home = () => {
  const [arrowSize, setArrowSize] = useState(window.innerHeight / 6);
  const heroSectionRef = useRef(null);
  const [showName, setShowName] = useState(true);
  const [nameSize, setNameSize] = useState('text-4xl sm:text-6xl');

  const { scrollY } = useScroll();
  const scaleX = useSpring(scrollY, {
    stiffness: 100,
    damping: 30,
    restDelta: 0.001
  });

  useEffect(() => {
    return scrollY.onChange((latest) => {
      if (latest > 0) {
        setShowName(false);
      } else {
        setShowName(true);
      }
    });
  }, [scrollY]);

  useEffect(() => {
    const handleResize = () => {
      const screenWidth = window.innerWidth;
      if (screenWidth < 640) {
        setNameSize('text-2xl');
      } else {
        setNameSize('text-4xl sm:text-6xl');
      }
    };

    handleResize(); // Initial calculation
    window.addEventListener('resize', handleResize); // Recalculate on window resize

    return () => {
      window.removeEventListener('resize', handleResize);
    };
  }, []);

  useEffect(() => {
    const arrowObserver = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          const newSize = window.innerHeight / 6;
          setArrowSize(newSize);
        }
      },
      { threshold: [0, 0.5, 1] }
    );

    if (heroSectionRef.current) {
      arrowObserver.observe(heroSectionRef.current);
    }

    return () => {
      if (heroSectionRef.current) {
        arrowObserver.unobserve(heroSectionRef.current);
      }
    };
  }, []);

  return (
    <div className="snap-y snap-mandatory h-screen overflow-y-scroll">
      {showName && (
        <motion.div
          className="fixed top-2 right-2 p-5 text-orange-500 z-50"
          initial={{ opacity: 0, scale: 0.5 }}
          animate={{ opacity: 1, scale: 0.7 }}
          transition={{
            duration: 0.8,
            delay: 0.5,
            ease: [0, 0.71, 0.2, 1.01]
          }}
        >
          <h1 className={nameSize}>[MY NAME]</h1>
        </motion.div>
      )}

      {/* <HeroSection arrowSize={arrowSize} />
      <AboutSection arrowSize={arrowSize} />
      <ProjectsSection arrowSize={arrowSize} />
      <SkillsSection arrowSize={arrowSize} />
      <motion.div className="progress" style={{ scaleX }} /> */}
    </div>
  );
};

export default Home;

styles.css:

/* Custom scrollbar styles */
::-webkit-scrollbar {
    width: 12px;
  }
  
  ::-webkit-scrollbar-track {
    background: #a5f3fc; /* Cyan-200 color */
  }
  
  ::-webkit-scrollbar-thumb {
    background-color: #ff7f00; /* Orange color */
    border-radius: 10px;
    border: 3px solid #a5f3fc; /* Cyan-200 color to match the track */
  }
  
  ::-webkit-scrollbar-thumb:hover {
    background-color: #ff6600; /* Darker orange color on hover */
  }

  .line-drawing {
    stroke-dasharray: 1000;
    stroke-dashoffset: 1000;
    animation: draw 2s forwards;
  }
  
  @keyframes draw {
    to {
      stroke-dashoffset: 0;
    }
  }

Homepage.css:

/* Homepage specific styles */
.home-container {
  scroll-snap-type: y mandatory;
  overflow-y: scroll;
  height: 100vh;
}

section {
  scroll-snap-align: center;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
  padding: 20px;
  transition: opacity 0.5s ease-in-out;
  position: relative;
  width: 100%;
}

/* Animation styles */
@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

.animate-fade-in {
  animation: fade-in 1s ease-in-out forwards;
}

.animate-fade-in-delay {
  animation: fade-in 2s ease-in-out forwards;
  animation-delay: 2s;
}

/* Line drawing animation */
.line-drawing {
  stroke-dasharray: 1000;
  stroke-dashoffset: 1000;
  animation: draw 2s forwards;
}

@keyframes draw {
  to {
      stroke-dashoffset: 0;
  }
}

here are one of the inner screens, which works when I do 'npm start':

import React, { useRef, useState, useEffect } from 'react';
import { motion } from 'framer-motion';
import Arrow from './Arrow';
import { FaLinkedin, FaGithub, FaEnvelope } from 'react-icons/fa';

const HeroSection = ({ arrowSize }) => {
  const heroSectionRef = useRef(null);
  const [arrowSizeDynamic, setArrowSizeDynamic] = useState(arrowSize);
  const [buttonSize, setButtonSize] = useState('text-base sm:text-lg');
  const [textSize, setTextSize] = useState('text-xl sm:text-2xl');
  const [titleSize, setTitleSize] = useState('text-4xl sm:text-6xl');

  useEffect(() => {
    const handleResize = () => {
      if (heroSectionRef.current) {
        const heroSectionHeight = heroSectionRef.current.clientHeight;
        const contentHeight = heroSectionRef.current.scrollHeight;
        const remainingSpace = heroSectionHeight - contentHeight;
        const newSize = Math.max(arrowSize, remainingSpace / 2); // Adjust the divisor to control the size
        setArrowSizeDynamic(newSize);

        // Adjust button and text sizes based on screen width
        const screenWidth = window.innerWidth;
        if (screenWidth < 640) {
          setButtonSize('text-sm px-4 py-2');
          setTextSize('text-lg');
          setTitleSize('text-4xl');
        } else {
          setButtonSize('text-base sm:text-lg px-6 py-3 sm:px-10 sm:py-5');
          setTextSize('text-xl sm:text-3xl');
          setTitleSize('text-5xl sm:text-9xl');
        }
      }
    };

    handleResize(); // Initial calculation
    window.addEventListener('resize', handleResize); // Recalculate on window resize

    return () => {
      window.removeEventListener('resize', handleResize);
    };
  }, [arrowSize]);

  return (
    <section
      ref={heroSectionRef}
      className="section hero snap-start h-screen flex flex-col justify-between items-center text-center relative bg-cyan-200"
    >
      <div className="container mx-auto px-4 sm:px-10 relative z-10 mt-10">
        <motion.h1
          className={`${titleSize} mb-6 hero-title`}
          initial={{ opacity: 0, y: -50 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ duration: 1 }}
        >
          Hi! 👋
        </motion.h1>
        <motion.p
          className={`${textSize} mb-4`}
          initial={{ opacity: 0, y: -50 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ duration: 1, delay: 0.5 }}
        >
          I'm [Redacted]
        </motion.p>
        <motion.p
          className="text-lg sm:text-2xl mb-16 sm:mb-32"
          initial={{ opacity: 0, y: 20 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ duration: 1, delay: 1.5 }}
        >
          Passionate about things.
        </motion.p>
        <motion.div
          className="flex justify-center space-x-4 sm:space-x-8 mb-8"
          initial={{ opacity: 0 }}
          animate={{ opacity: 1 }}
          transition={{ duration: 1, delay: 2 }}
        >
          <a href="https://www.linkedin.com/in/myname" target="_blank" rel="noopener noreferrer">
            <FaLinkedin className="text-3xl sm:text-5xl text-blue-600 hover:text-blue-800" />
          </a>
          <a href="https://github.com/myusername" target="_blank" rel="noopener noreferrer">
            <FaGithub className="text-3xl sm:text-5xl text-gray-800 hover:text-gray-600" />
          </a>
          <a href="mailto:email@gmail.com" target="_blank" rel="noopener noreferrer">
            <FaEnvelope className="text-3xl sm:text-5xl text-orange-500 hover:text-orange-700" />
          </a>
        </motion.div>
        <motion.a
          href="/resume.pdf"
          className={`inline-block ${buttonSize} bg-orange-500 text-white rounded-full hover:bg-orange-600 transition-colors mb-10`}
          initial={{ opacity: 0, scale: 0.8 }}
          animate={{ opacity: 1, scale: 1 }}
          transition={{ duration: 1, delay: 2.5 }}
          download
        >
          Download Resume
        </motion.a>
      </div>
      <Arrow size={arrowSizeDynamic} target="#about" />
    </section>
  );
};

export default HeroSection;

Solution

  • If you were already on v23.2.0 when facing this issue, roll back to the LTS (v22.11.0).