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

After updating to expo 52: ReferenceError: _WORKLET | __reanimatedLoggerConfig is not defined #6740

Open
abretonc7s opened this issue Nov 21, 2024 · 17 comments
Assignees
Labels
Platform: Android This issue is specific to Android Platform: iOS This issue is specific to iOS Platform: Web This issue is specific to web Repro provided A reproduction with a snippet of code, snack or repo is provided

Comments

@abretonc7s
Copy link

Description

After updating to Expo SDK 52, I encountered a ReferenceError: _WORKLET is not defined error on web platform. This error occurred after running expo install --fix to update dependencies. The error prevents the application from running properly on web.

Relevant dependencies:

{
  "dependencies": {
    "expo": "~52.0.0",
    "react-native-reanimated": "~3.6.1",
    "@react-native-community/slider": "4.5.5",
    "@gorhom/bottom-sheet": "^5.0.5",
    "@gorhom/portal": "~1.0.14"
  }
}
// packages/expo-audio-ui/src/AnimatedCandle/AnimatedCandle.tsx
import { Rect } from '@shopify/react-native-skia'
import React, { useEffect } from 'react'
import { Platform } from 'react-native'
import { useSharedValue, withTiming } from 'react-native-reanimated'

import { CANDLE_OFFCANVAS_COLOR } from '../constants'

export interface AnimatedCandleProps {
    height: number
    x: number
    y: number
    startY: number
    width: number
    color: string
    animated?: boolean
}
const AnimatedCandle: React.FC<AnimatedCandleProps> = ({
    color: targetColor,
    x: targetX,
    y: targetY,
    startY,
    height: targetHeight,
    width,
    animated = true,
}) => {
    const y = useSharedValue(startY)
    const height = useSharedValue(0)
    const x = useSharedValue(targetX)
    const color = useSharedValue(CANDLE_OFFCANVAS_COLOR)

    useEffect(() => {
        if (Platform.OS === 'web') {
            y.value = targetY
            height.value = targetHeight
            x.value = targetX
            color.value = targetColor
            return
        }

        if (animated) {
            y.value = withTiming(targetY, { duration: 500 })
            height.value = withTiming(targetHeight, { duration: 500 })
            x.value = withTiming(targetX, { duration: 500 })
            color.value = withTiming(targetColor, { duration: 500 })
        } else {
            y.value = targetY
            height.value = targetHeight
            x.value = targetX
            color.value = targetColor
        }
    }, [targetY, targetHeight, targetX, targetColor, animated])

    return <Rect x={x} y={y} width={width} height={height} color={color} />
}

export default React.memo(AnimatedCandle)

Steps to reproduce

on Web it seems that using any wtihTiming creates the issue.

Snack or a link to a repository

https://github.com/deeeed/expo-audio-stream/blob/main/apps/playground/src/app/minimal.tsx

Reanimated version

3.6.1

React Native version

0.76.2

Platforms

Android, iOS, Web

JavaScript runtime

Hermes

Workflow

Expo Dev Client

Architecture

Fabric (New Architecture)

Build type

Debug app & dev bundle

Device

Real device

Device model

iphone pro 13

Acknowledgements

Yes

@github-actions github-actions bot added Missing repro This issue need minimum repro scenario Platform: Android This issue is specific to Android Platform: iOS This issue is specific to iOS Platform: Web This issue is specific to web labels Nov 21, 2024
@hirbod
Copy link
Contributor

hirbod commented Nov 22, 2024

I can confirm the problem. 3.16.* is failing on web for me. 3.15 works fine.

Screenshot 2024-11-22 at 10 27 12 Screenshot 2024-11-22 at 09 58 36

@tjzel
Copy link
Collaborator

tjzel commented Nov 22, 2024

@hirbod @abretonc7s I'm on it!

@tjzel tjzel self-assigned this Nov 22, 2024
@tjzel
Copy link
Collaborator

tjzel commented Nov 22, 2024

Heyi @abretonc7s @hirbod I tried to reproduce it locally but it didn't work. Could you provide some minimal expo repo where this issue appears?

@MariusCatanoiu
Copy link

similar here.
Property '_reanimatedLoggerConfig' doesn't exit
at line 96 in the logger.ts file

@hirbod
Copy link
Contributor

hirbod commented Nov 22, 2024

For now, I added

if (Platform.OS === 'web') {
  global._WORKLET = false
  // @ts-expect-error
  global._log = console.log
  // @ts-expect-error
  global._getAnimationTimestamp = () => performance.now()
}

as a hack in my entrypoint. Everything works now, beside reanimatedLoggerConfig, but I don't import configureReanimatedLogger for web.

@tjzel
Copy link
Collaborator

tjzel commented Nov 25, 2024

@abretonc7s @hirbod @MariusCatanoiu

The supposed fix is available on @next and @nightly versions of Reanimated. Could you install it and see if it resolves the issue?

@abretonc7s
Copy link
Author

I tried the latest night build "react-native-reanimated": "3.17.0-nightly-20241124-af73db066"
image

@tjzel
Copy link
Collaborator

tjzel commented Nov 25, 2024

Well that sucks 🤔

@hirbod
Copy link
Contributor

hirbod commented Nov 25, 2024

That aligns with my observations, as I also tried patch 3.16.2, and it didn’t work.
I’m starting to think this issue occurs when both iOS and the web are running simultaneously and Metro strips code?

Now, let me add a bit more confusion to the topic:

if (Platform.OS !== 'web') {
  // We need to set the log level to error to avoid spamming the console because of NativeWind for now
  configureReanimatedLogger({
    level: ReanimatedLogLevel.error,
  });
} else {
  global._WORKLET = false;
  // @ts-expect-error
  global._log = console.log;
  // @ts-expect-error
  global._getAnimationTimestamp = () => performance.now();
}

This is my "hack." After adding it, changing the if condition from !== to ===, reloading, and then switching it back, the "bug" disappeared—even without the hack. Does that make sense? No. I’m starting to think the Metro bundler and its cache are doing something strange.

@tjzel
Copy link
Collaborator

tjzel commented Nov 25, 2024

Yes, it happened to me a few times recently that only after git clean -Xdf the Metro cache was properly reset in some exotic cases 🤔

@tjzel
Copy link
Collaborator

tjzel commented Nov 25, 2024

@abretonc7s Could you see if wiping all the caches works for you on the nightly versions?

@abretonc7s
Copy link
Author

Doesn't work with the nighlty, cleaning all caches.

You can easily reproduce, just make a component and run it on web

import React, { useEffect } from 'react'
import { ColorValue, View } from 'react-native'
import { Text } from 'react-native-paper'
import Animated, {
    useAnimatedStyle,
    useSharedValue,
    withRepeat,
    withSpring,
} from 'react-native-reanimated'

interface LoaderProps {
    color?: ColorValue
    size?: number
}

const Loader = ({ color, size = 40 }: LoaderProps) => {
    const rotateValue = useSharedValue(0)

    const handleRotation = (value: number): string => {
        'worklet'
        return `${value * 4 * Math.PI}rad`
    }

    const rotateStyles = useAnimatedStyle(() => {
        return {
            transform: [
                { rotate: handleRotation(rotateValue.value) },
                { scale: rotateValue.value + 0.3 },
            ],
            opacity: rotateValue.value + 0.2,
            borderRadius: rotateValue.value * 20,
        }
    })

    useEffect(() => {
        rotateValue.value = withRepeat(withSpring(0.5), -1, true)
    }, [])

    return (
        <View
            style={{
                justifyContent: 'center',
                alignItems: 'center',
            }}
        >
            <Animated.View
                style={[
                    {
                        height: size,
                        width: size,
                        backgroundColor: color,
                        marginTop: 5,
                    },
                    rotateStyles,
                ]}
            />
        </View>
    )
}

const TestScreen = () => {
    return (
        <View>
            <Text>Test</Text>
            <Loader />
        </View>
    )
}

export default TestScreen

util.js:347 Uncaught ReferenceError: _WORKLET is not defined

@tjzel
Copy link
Collaborator

tjzel commented Nov 26, 2024

@abretonc7s When I run this snippet on a fresh Expo app and start web everything works well.

@vonSchweeee
Copy link

vonSchweeee commented Nov 26, 2024

Same happening here, web only works with 3.15.x but Android only works on 3.16.x. (RN 0.76)

@abretonc7s
Copy link
Author

abretonc7s commented Nov 27, 2024

I have the reverse issue... 3.15 works for web but then android conflicts... Anyway expo recommends 3.16.1 which has the web issue.
I am currently running @hirbod hack as a workaround

if (Platform.OS === 'web') {
  global._WORKLET = false
  // @ts-expect-error
  global._log = console.log
  // @ts-expect-error
  global._getAnimationTimestamp = () => performance.now()
}

@byCedric
Copy link

byCedric commented Dec 2, 2024

I'd love to take a look at this issue too, mostly to see if this is a Reanimated issue or an Expo issue. Unfortunately, I can't reproduce with none of the examples here, nor do I get _WORKLET being undefined on web. Not using Reanimated 3.6.1, 3.16.1, 3.16.2, 3.16.3, 3.15.5, with or without treeshaking enabled, not in dev mode (expo start) and not in production exports (expo export -p web && npx serve ./dist) -- all using SDK 52 ([email protected]).

If someone can provide a repro, using the blank or default Expo templates, I'd be more than happy to debug this too.

PS. The original monorepo posted also did not trigger this error for me.

@deeeed
Copy link

deeeed commented Dec 5, 2024

Hey @byCedric I pushed an update to https://deeeed.github.io/expo-audio-stream/playground/more where you can see the bug.

You can just pull this branch and run locally as well https://github.com/deeeed/expo-audio-stream/tree/docupdate

Currently there is a switch that enabled / disable the hack which is :

import { useToast } from '@siteed/design-system'
import { useCallback, useEffect, useState } from 'react'
import { Platform } from 'react-native'

import { baseLogger } from '../config'

const logger = baseLogger.extend('useReanimatedWebHack')

export function useReanimatedWebHack() {
    const [isHackEnabled, setIsHackEnabled] = useState(false)
    const { show } = useToast()

    useEffect(() => {
        if (Platform.OS === 'web') {
            // Initialize state based on existing global._WORKLET
            const initialValue = !!global._WORKLET
            logger.log('initialValue', initialValue)
            setIsHackEnabled(initialValue)
        }
    }, [])

    const handleHackToggle = useCallback((value: boolean) => {
        logger.log('handleHackToggle', value)

        if (Platform.OS === 'web') {
            setIsHackEnabled(value)
            if (value) {
                global._WORKLET = false
                // @ts-expect-error
                global._log = console.log
                // @ts-expect-error
                global._getAnimationTimestamp = () => performance.now()
                show({
                    type: 'success',
                    iconVisible: true,
                    message: 'Reanimated Web Hack Enabled',
                })
            } else {
                delete global._WORKLET
                // @ts-expect-error
                delete global._log
                // @ts-expect-error
                delete global._getAnimationTimestamp
                show({
                    type: 'warning',
                    iconVisible: true,
                    message: 'Reanimated Web Hack Disabled',
                })
            }
        }
    }, [])

    return {
        isHackEnabled,
        handleHackToggle,
    }
}

image

To see the issue, just go to the main page and start recording, without the hack you will get the error:
image

This deployed page runs with "react-native-reanimated": "3.17.0-nightly-20241204-5ffa47792",

@github-actions github-actions bot added Repro provided A reproduction with a snippet of code, snack or repo is provided and removed Missing repro This issue need minimum repro scenario labels Dec 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Platform: Android This issue is specific to Android Platform: iOS This issue is specific to iOS Platform: Web This issue is specific to web Repro provided A reproduction with a snippet of code, snack or repo is provided
Projects
None yet
Development

No branches or pull requests

7 participants