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

Error: Module name "react" has not been loaded yet for context try to reproduce included threejs-fiber example #59

Open
cpbotha opened this issue Mar 16, 2024 · 4 comments

Comments

@cpbotha
Copy link

cpbotha commented Mar 16, 2024

I can successfully run the threejs-fiber.ipynb with the included threejs-fiber.bundle.js without any issues.

Let's try and build the bundle by ourselves:

cp -r threejs-fiber /tmp && cd /tmp/threejs-fiber
python3.11 -m venv ~/.virtualenvs/ipyreact-threejs
source ~/.virtualenvs/ipyreact-threejs/bin/activate
# ipyreact 0.4.1
pip install ipyreact notebook
# esbuild 0.20.2
npm install --global esbuild
npm install @react-three/[email protected] @react-three/[email protected]
esbuild ./threejs-fiber.js --bundle --outfile=./threejs-fiber.bundle.js --format=esm --external:react --external:react-dom --external:react-reconciler --external:react-reconciler/constants --target=esnext

With fixed drei and fiber versions, this gives us the error below.

Let's try with unset versions, i.e. latest:

# remove outputs from previous esbuild attempt
rm -rf node_modules package package-lock.json
# now we get 9.102.5 and 8.15.19
npm install @react-three/drei @react-three/fiber
esbuild ./threejs-fiber.js --bundle --outfile=./threejs-fiber.bundle.js --format=esm --external:react --external:react-dom --external:react-reconciler --external:react-reconciler/constants --target=esnext

This builds successfully, with one warning, see below.

However, now when I run the threejs-fiber.ipynb notebook cell with ipyreact.define_module(), I see the following error:

threejs-fiber status: Error loading module: Error: Module name "react" has not been loaded yet for context: _. Use require([]) https://requirejs.org/docs/errors.html#notloaded

If I run esbuild without the --external:... params to exclude react (just to check!), the define_module() is successful, but the cell that's supposed to show the BoxWidget gives the following eror: "Cannot read properties of null (reading 'useMemo')"

I would be super grateful for any help with this. These symptoms are the similar to what I'm seeing trying to wrap a reactflow example with ipyreact.

Based on the fact that esbuild fails with versions that were known to be good, I am suspecting that some change in esbuild is causing these issues. (although I have now also tried out esbuild 0.19.12 and it yields exactly the same behaviour)

error with first esbuild attempt with fixed drei and fiber versions

✘ [ERROR] No matching export in "node_modules/three/build/three.module.js" for import "sRGBEncoding"

    node_modules/@react-three/drei/core/useEnvironment.js:2:66:
      2 │ import { CubeReflectionMapping, EquirectangularReflectionMapping, sRGBEncoding, LinearEncoding, CubeTextureLoader } from 'three';
        ╵                                                                   ~~~~~~~~~~~~

✘ [ERROR] No matching export in "node_modules/three/build/three.module.js" for import "LinearEncoding"

    node_modules/@react-three/drei/core/useEnvironment.js:2:80:
      2 │ import { CubeReflectionMapping, EquirectangularReflectionMapping, sRGBEncoding, LinearEncoding, CubeTextureLoader } from 'three';
        ╵                                                                                 ~~~~~~~~~~~~~~

✘ [ERROR] No matching export in "node_modules/three/build/three.module.js" for import "LinearEncoding"

    node_modules/@react-three/drei/core/SpotLight.js:3:76:
      3 │ ...rt { Vector3, CylinderGeometry, Matrix4, WebGLRenderTarget, RGBAFormat, LinearEncoding, ShaderMaterial, DoubleSide, RepeatWrapping } from 'three';
        ╵                                                                            ~~~~~~~~~~~~~~

3 errors

warning with second esbuild attempt

▲ [WARNING] Constructing "StatsImpl" will crash at run-time because it's an import namespace object, not a constructor [call-import-namespace]

    node_modules/@react-three/drei/core/Stats.js:11:44:
      11 │   const stats = useEffectfulState(() => new StatsImpl(), []);
         ╵                                             ~~~~~~~~~

  Consider changing "StatsImpl" to a default import instead:

    node_modules/@react-three/drei/core/Stats.js:3:7:
      3 │ import * as StatsImpl from 'stats.js';
        │        ~~~~~~~~~~~~~~
        ╵        StatsImpl

1 warning

  threejs-fiber.bundle.js  3.6mb ⚠️

⚡ Done in 135ms
@maartenbreddels
Copy link
Contributor

Hi Charl,

sharing how I debugged this:
I opened the bundle file and searched for require("react
Which gave me:
image

This tell me that this is a dead end. if esbuild includes a commonjs module (which calls require(...)), it will not try to rewrite/transpile that code. (Althought I might be possible looking at evanw/esbuild#946 (comment) )

This is when I switched to rollup, going over several error iterations like:

[!] RollupError: "unstable_scheduleCallback" is not exported by "node_modules/scheduler/index.js", imported by "node_modules/@react-three/fiber/dist/index-e6b5343a.esm.js".
https://rollupjs.org/troubleshooting/#error-name-is-not-exported-by-module
node_modules/@react-three/fiber/dist/index-e6b5343a.esm.js (6:9)
4: import create from 'zustand';

Which led me to pmndrs/react-three-fiber#221

And rollup/rollup#487

I eventually got the following script:

// rollup.config.mjs
import { nodeResolve } from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import replace from '@rollup/plugin-replace';

export default {
	input: './threejs-fiber.js',
	output: [
		{
			file: 'threejs-fiber.bundle.js',
			inlineDynamicImports: true,
			format: 'es'
		}
	],
	external: ["react", "react-dom", "react-reconciler", "react-reconciler/constant"],
	plugins: [
		replace({
			'process.env.NODE_ENV': JSON.stringify('production')
		}),
		nodeResolve({
			browser: true,
		}),
		commonjs({
			namedExports: {
				scheduler: [
					'unstable_runWithPriority',
					'unstable_IdlePriority',
					'unstable_now',
					'unstable_scheduleCallback',
					'unstable_cancelCallback',
				],
			}
		})
	],
};

running it like

$ npm install rollup @rollup/plugin-replace @rollup/plugin-commonjs @rollup/plugin-node-resolve
$ npx rollup -c rollup.config.mjs  

Which made it work for me.

Could you check if this works for you? Maybe if it does, you could update the docs on this? Or possibly add a section in the notebook at the end to describe this.

@maartenbreddels
Copy link
Contributor

If I run esbuild without the --external:... params to exclude react (just to check!), the define_module() is successful, but the cell that's supposed to show the BoxWidget gives the following eror: "Cannot read properties of null (reading 'useMemo')"

Btw, when you do this, you have a new react for your ESM, while ipyreact already ships react. Two reacts in the same react tree do not work together.

@cpbotha
Copy link
Author

cpbotha commented Mar 18, 2024

If I run esbuild without the --external:... params to exclude react (just to check!), the define_module() is successful, but the cell that's supposed to show the BoxWidget gives the following eror: "Cannot read properties of null (reading 'useMemo')"

Btw, when you do this, you have a new react for your ESM, while ipyreact already ships react. Two reacts in the same react tree do not work together.

Totally get this (and it's documented), but had to try something because the documented method was failing with a react-related issue. :)

@cpbotha
Copy link
Author

cpbotha commented Mar 18, 2024

Thank you very much for looking into this Maarten!

running it like

$ npm install rollup @rollup/plugin-replace @rollup/plugin-commonjs @rollup/plugin-node-resolve
$ npx rollup -c rollup.config.mjs  

Which made it work for me.

Could you check if this works for you? Maybe if it does, you could update the docs on this? Or possibly add a section in the notebook at the end to describe this.

Do you mean that I should replace the esbuild invocation on https://github.com/widgetti/ipyreact/blob/master/examples/threejs-fiber/threejs-fiber.ipynb with your suggested rollup invocation?

Do you have any idea why it always used to work with esbuild, and now suddenly not?

Looking at the rollup/rollup#487 you found, they say that "This happens because React uses process.env to determine whether you're in a development or production environment." ... but why does this break the build? -- urk, now I see that the process error is a purely rollup one, not related to esbuild breaking for us here.

I'm asking all these questions, because as someone with a fair bit of frontend experience, having to fine-tune rollup.config.mjs would be a bit of a trip.

P.S.

https://esbuild.github.io/api/#platform has the following to say about NODE_ENV and React:

When using the build API, all process.env.NODE_ENV expressions are automatically defined to "production" if all minification options are enabled and "development" otherwise. This only happens if process, process.env, and process.env.NODE_ENV are not already defined. This substitution is necessary to avoid React-based code crashing instantly (since process is a node API, not a web API).

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

2 participants