Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Next.js runtime error #84

Open
Chandler-Zhu opened this issue Jul 27, 2022 · 6 comments
Open

Next.js runtime error #84

Chandler-Zhu opened this issue Jul 27, 2022 · 6 comments

Comments

@Chandler-Zhu
Copy link

I tried to use splitting in my next.js app, but it gives me an error

import React, { useState, useRef, useEffect } from 'react'

import 'splitting/dist/splitting.css'
import 'splitting/dist/splitting-cells.css'
import Splitting from 'splitting'


export const SomePage = () => {

  const slideRef = useRef(null)

  useEffect(() => {
    // double checking we actually have a reference (and the value is not null)
    if (slideRef) {
     slideRef.current.Splitting();
    }
  }, [slideRef])

  return (
    <p
      ref={slideRef}
      data-splitting='true'
    >
      split some text here
    </p>
  )
}

image

@draZer0
Copy link

draZer0 commented Aug 19, 2022

I combined all the answers from previous issues and I managed to get it working in Next.js with the following code:

import "splitting/dist/splitting.css";
import "splitting/dist/splitting-cells.css";

const Component = () => {

    let target;

    setTimeout(() => {
        if ( window && document && target ) {
            const Splitting = require('Splitting');
            Splitting({ by: "chars", target: target,  });
        }
    });

    return (
        <>
            <span ref={(el) => { target = el; }}>Lorem ipsum dolor sit amet</span>
        </>
    )
}

export default Component;

@Chandler-Zhu
Copy link
Author

if the ref is an arrow function, when exactly does it run? After component mounted ?

@outdatedx
Copy link

outdatedx commented Jun 17, 2023

Im having a similar issue cause I'm using it in a hook

'use client'

import 'splitting/dist/splitting.css'
import 'splitting/dist/splitting-cells.css'

import { useEffect, useRef } from 'react'
import Splitting from 'splitting'

import { randomNumber } from '~/lib/utils'

interface CellOptions {
  position: number
  previousCellPosition: number
}

class Line {
  position = -1
  cells: Cell[] = []

  constructor(linePosition: number) {
    this.position = linePosition
  }
}

class Cell {
  DOM: {
    el: HTMLElement | null
  } = {
    el: null
  }
  position = -1
  previousCellPosition = -1
  original: string
  state: string
  color: string
  originalColor: string
  cache: any

  constructor(DOM_el: HTMLElement, options: CellOptions) {
    this.DOM.el = DOM_el
    this.original = this.DOM.el.innerHTML
    this.state = this.original
    this.color = this.originalColor = getComputedStyle(
      document.documentElement
    ).getPropertyValue('--color-text')
    this.position = options.position
    this.previousCellPosition = options.previousCellPosition
  }

  set(value: string) {
    this.state = value
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    this.DOM.el!.innerHTML = this.state
  }
}

class TypeShuffle {
  DOM: {
    el: HTMLElement | null
  } = {
    el: null
  }
  lines: Line[] = []
  lettersAndSymbols: string[] = [
    'A',
    'B',
    'C',
    'D',
    'E',
    'F',
    'G',
    'H',
    'I',
    'J',
    'K',
    'L',
    'M',
    'N',
    'O',
    'P',
    'Q',
    'R',
    'S',
    'T',
    'U',
    'V',
    'W',
    'X',
    'Y',
    'Z',
    '!',
    '@',
    '#',
    '$',
    '&',
    '*',
    '(',
    ')',
    '-',
    '_',
    '+',
    '=',
    '/',
    '[',
    ']',
    '{',
    '}',
    ';',
    ':',
    '<',
    '>',
    ',',
    '0',
    '1',
    '2',
    '3',
    '4',
    '5',
    '6',
    '7',
    '8',
    '9'
  ]
  effects: Record<string, () => void> = {
    fx: () => this.fx()
  }
  totalChars = 0
  isAnimating = false

  constructor(DOM_el: HTMLElement) {
    this.DOM.el = DOM_el

    const results = Splitting({ target: this.DOM.el, by: 'lines' })
    results.forEach((s: any) => Splitting({ target: s.words }))

    for (const [linePosition, lineArr] of results[0].lines.entries()) {
      const line = new Line(linePosition)
      const cells: Cell[] = []
      let charCount = 0

      for (const word of lineArr) {
        for (const char of Array.from(
          word.querySelectorAll('.char')
        ) as HTMLElement[]) {
          cells.push(
            new Cell(char, {
              position: charCount,
              previousCellPosition: charCount === 0 ? -1 : charCount - 1
            })
          )
          ++charCount
        }
      }

      line.cells = cells
      this.lines.push(line)
      this.totalChars += charCount
    }
  }

  clearCells() {
    for (const line of this.lines) {
      for (const cell of line.cells) {
        cell.set('&nbsp;')
      }
    }
  }

  getRandomChar() {
    return this.lettersAndSymbols[
      Math.floor(Math.random() * this.lettersAndSymbols.length)
    ]
  }

  fx() {
    const MAX_CELL_ITERATIONS = 10
    let finished = 0
    this.clearCells()

    const loop = (line: Line, cell: Cell, iteration = 0) => {
      if (iteration === MAX_CELL_ITERATIONS - 1) {
        cell.set(cell.original)
        ++finished
        if (finished === this.totalChars) {
          this.isAnimating = false
        }
      } else {
        const randomChar = this.getRandomChar()
        if (randomChar) {
          cell.set(randomChar)
        }
      }

      ++iteration
      if (iteration < MAX_CELL_ITERATIONS) {
        setTimeout(() => loop(line, cell, iteration), 50)
      }
    }

    for (const line of this.lines) {
      for (const cell of line.cells) {
        setTimeout(() => loop(line, cell), randomNumber(0, 100))
      }
    }
  }

  trigger(effect = 'fx') {
    if (this.effects && effect in this.effects && !this.isAnimating) {
      this.isAnimating = true
      const selectedEffect = this.effects[effect]
      selectedEffect && selectedEffect()
    }
  }
}

export const useTypeShuffle = (selector: string) => {
  const typeShuffleRef = useRef<TypeShuffle | null>(null)

  useEffect(() => {
    if (window && document) {
      const mainTextElement = document.querySelector(selector) as HTMLElement

      if (!mainTextElement) {
        return
      }

      const typeShuffleInstance = new TypeShuffle(mainTextElement)
      typeShuffleRef.current = typeShuffleInstance

      return () => {
        typeShuffleRef.current = null
      }
    }
  }, [selector])

  return typeShuffleRef
}

Its basically a typeShuffle Effect that uses splitting and spits out the error

- error node_modules/splitting/dist/splitting.js (7:0) @ eval
- error ReferenceError: document is not defined

@brett-sprad
Copy link

This worked for me:

'use client'

import 'splitting/dist/splitting.css'
import 'splitting/dist/splitting-cells.css'

import { gsap } from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
import { ReactNode, useEffect } from 'react'

gsap.registerPlugin(ScrollTrigger)

interface Props {
  children: ReactNode
}

const AnimateText = ({ children }: Props) => {
  let target: any = null

  const scroll = (fx17Titles: any) => {
    fx17Titles.forEach((title: HTMLElement) => {
      const chars = title.querySelectorAll('.char')
      chars.forEach((char) =>
        gsap.set(char.parentNode, {
          perspective: 1000,
        })
      )
      gsap.fromTo(
        // targets:
        chars,
        // from:
        {
          y: 10,
          'will-change': 'opacity, transform',
          opacity: 0.7,
          rotateX: () => gsap.utils.random(-120, 120),
          z: () => gsap.utils.random(-100, 200),
        },
        // to:
        {
          y: 0,
          z: -12.2,
          repeat: 0,
          ease: 'none',
          opacity: 1,
          rotateX: 10,
          stagger: 0.1,
          scrollTrigger: {
            trigger: title,
            start: 'top bottom',
            end: 'bottom top',
            scrub: true,
          },
        }
      )
    })
  }

  useEffect(() => {
    const fx17Titles = document.querySelectorAll('.animate-text[data-splitting][data-effect17]')
    const splitting = require('Splitting')
    splitting({ by: 'chars', target: target })
    scroll(fx17Titles)
  })

  return (
    <>
      <div
        ref={(el) => {
          target = el
        }}
        className={'animate-text'}
        data-splitting
        data-effect17
      >
        {children}
      </div>
    </>
  )
}

export default AnimateText

...and then you use it like so:

<AnimateText>Some text here</AnimateText>

@AlexandraKlein
Copy link

I am using this:

  React.useEffect(() => {
        const splitText = async () => {
            const { default: Splitting } = await import('splitting');

            if (ref.current) {
                Splitting({ target: ref.current });
            }
        };

        splitText();
    }, []);

@Baraff24
Copy link

This worked for me:

'use client'

import 'splitting/dist/splitting.css'
import 'splitting/dist/splitting-cells.css'

import { gsap } from 'gsap'
import { ScrollTrigger } from 'gsap/ScrollTrigger'
import { ReactNode, useEffect } from 'react'

gsap.registerPlugin(ScrollTrigger)

interface Props {
  children: ReactNode
}

const AnimateText = ({ children }: Props) => {
  let target: any = null

  const scroll = (fx17Titles: any) => {
    fx17Titles.forEach((title: HTMLElement) => {
      const chars = title.querySelectorAll('.char')
      chars.forEach((char) =>
        gsap.set(char.parentNode, {
          perspective: 1000,
        })
      )
      gsap.fromTo(
        // targets:
        chars,
        // from:
        {
          y: 10,
          'will-change': 'opacity, transform',
          opacity: 0.7,
          rotateX: () => gsap.utils.random(-120, 120),
          z: () => gsap.utils.random(-100, 200),
        },
        // to:
        {
          y: 0,
          z: -12.2,
          repeat: 0,
          ease: 'none',
          opacity: 1,
          rotateX: 10,
          stagger: 0.1,
          scrollTrigger: {
            trigger: title,
            start: 'top bottom',
            end: 'bottom top',
            scrub: true,
          },
        }
      )
    })
  }

  useEffect(() => {
    const fx17Titles = document.querySelectorAll('.animate-text[data-splitting][data-effect17]')
    const splitting = require('Splitting')
    splitting({ by: 'chars', target: target })
    scroll(fx17Titles)
  })

  return (
    <>
      <div
        ref={(el) => {
          target = el
        }}
        className={'animate-text'}
        data-splitting
        data-effect17
      >
        {children}
      </div>
    </>
  )
}

export default AnimateText

...and then you use it like so:

<AnimateText>Some text here</AnimateText>

Error: Prevent writing to file that only differs in casing or query string from already written file. This will lead to a race-condition and corrupted files on case-insensitive file systems. /.../.next/server/vendor-chunks/Splitting.js /.../.next/server/vendor-chunks/splitting.js at checkSimilarFile (/.../node_modules/next/dist/compiled/webpack/bundle5.js:28:142411) at writeOut (/.../node_modules/next/dist/compiled/webpack/bundle5.js:28:144419) at /.../node_modules/next/dist/compiled/webpack/bundle5.js:28:1369729 at FSReqCallback.oncomplete (node:fs:191:23)

I have this error with the same code as you, this is my package.json:
{ "name": "x-website", "version": "0.1.0", "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint" }, "dependencies": { "gsap": "^3.12.5", "next": "14.1.0", "react": "^18", "react-dom": "^18", "sass": "^1.71.0", "splitting": "^1.0.6" }, "devDependencies": { "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", "eslint": "^8", "eslint-config-next": "14.1.0", "jarallax": "^2.2.0", "paroller.js": "^1.4.7", "swiper": "^9.4.1", "typescript": "^5" } }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants