Coder Social home page Coder Social logo

Comments (9)

ovidiuch avatar ovidiuch commented on May 28, 2024

This doesn't seem to be webpack related since the error originates on the Node server side.

This probably has to do with the fact that react-cosmos-core has a single entry point that is imported either on the server or on the client side, and it also includes modules exports that contain react imports.

export * from './utils/react/ClassStateMock.js';
export * from './utils/react/DelayRender.js';
export * from './utils/react/areNodesEqual.js';
export * from './utils/react/getComponentName.js';
export * from './utils/react/isReactElement.js';

One potential solution is to decouple the main react-cosmos-core entry point from react and have a separate react-cosmos-core/react entry point that is only imported once already in a React context. But I'm not sure what the implications are at the moment.

Also there are some react-is imports outside the utils/react folder in the core package:

image

from react-cosmos.

birtles avatar birtles commented on May 28, 2024

Thanks for looking into this. I guess converting every place that imports react to a dynamic import would complicate things too much?

I had a quick look at how to set up import aliases with node and it looks like it might be possible with imports in package.json but I couldn't find a way to override that from the command-line. Maybe symlinks?

from react-cosmos.

birtles avatar birtles commented on May 28, 2024

I tried getting this to work today by using tsconfig-paths and also using bun's path mapping but didn't have any luck with either yet.

from react-cosmos.

birtles avatar birtles commented on May 28, 2024

I also tried using module-alias and a cosmos-bootstrap.js file like the following but it didn't work:

#!/usr/bin/env node

import moduleAlias from 'module-alias';

moduleAlias.addAliases({
  react: 'preact/compat',
  'react-dom': 'preact/compat',
});

await import('react-cosmos/bin/cosmos.js');

I just get:

$ node cosmos-bootstrap.js
node:internal/process/esm_loader:97
    internalBinding('errors').triggerUncaughtException(
                              ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'react' imported from C:\Users\Brian\10ten-ja-reader\node_modules\react-cosmos-core\dist\utils\react\ClassStateMock.js
Did you mean to import react/compat/dist/compat.js?
    at new NodeError (node:internal/errors:399:5)
    at packageResolve (node:internal/modules/esm/resolve:889:9)
    at moduleResolve (node:internal/modules/esm/resolve:938:20)
    at defaultResolve (node:internal/modules/esm/resolve:1153:11)
    at nextResolve (node:internal/modules/esm/loader:163:28)
    at ESMLoader.resolve (node:internal/modules/esm/loader:838:30)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:424:18)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:77:40)
    at link (node:internal/modules/esm/module_job:76:36) {
  code: 'ERR_MODULE_NOT_FOUND'
}

from react-cosmos.

birtles avatar birtles commented on May 28, 2024

I got a bit closer today using Node's module-based permissions to emulate import maps.

policy.json

{
  "dependencies": true,
  "scopes": {
    "": {
      "cascade": true,
      "integrity": true,
      "dependencies": {
        "react": "./node_modules/preact/compat/dist/compat.mjs"
      }
    }
  }
}

(It might be necessary to use compat.js instead of compat.mjs on non-ESM projects.)

Then run:

node --experimental-policy=policy.json node_modules/react-cosmos/bin/cosmos.js

I now hit a different error though:

$ node --experimental-policy=policy.json node_modules/react-cosmos/bin/cosmos.js
(node:35104) ExperimentalWarning: Policies are experimental.
(Use `node --trace-warnings ...` to show where the warning was created)
[Cosmos] Using cosmos config found at cosmos.config.json
[Cosmos] Found 1 plugin: Webpack
[Cosmos] See you at http://localhost:5000
[Cosmos] Using webpack config found at webpack.config.js
[Cosmos] Learn how to override webpack config for cosmos: https://github.com/react-cosmos/react-cosmos/tree/main/docs#webpac
k-config-override
[Cosmos][plugin:webpack] Dev server init failed
[Cosmos] Server crashed...

  (╯°□°)╯︵ ┻━┻

Error: [Cosmos] Local dependency not found: react
    at resolveLocalReactDeps (file:///C:/Users/Brian/10ten-ja-reader/node_modules/react-cosmos-plugin-webpack/dist/server/webpackConfig/getWebpackConfigResolve.js:31:19)
    at getWebpackConfigResolve (file:///C:/Users/Brian/10ten-ja-reader/node_modules/react-cosmos-plugin-webpack/dist/server/webpackConfig/getWebpackConfigResolve.js:4:36)
    at getDevWebpackConfig (file:///C:/Users/Brian/10ten-ja-reader/node_modules/react-cosmos-plugin-webpack/dist/server/webpackConfig/getDevWebpackConfig.js:18:18)
    at Object.webpackDevServerPlugin [as devServer] (file:///C:/Users/Brian/10ten-ja-reader/node_modules/react-cosmos-plugin-webpack/dist/server/webpackDevServerPlugin.js:13:28)
    at startDevServer (file:///C:/Users/Brian/10ten-ja-reader/node_modules/react-cosmos/dist/devServer/startDevServer.js:48:34)

That might just be because my webpack config is very complicated and the aliases for react there are not being picked up correctly.

from react-cosmos.

ovidiuch avatar ovidiuch commented on May 28, 2024

@birtles Thanks for posting these updates!

FYI the Local dependency not found exception is thrown here when React aliases aren't defined.

throw new Error(`[Cosmos] Local dependency not found: react`);

And this is how aliases are checked:

function hasAlias(alias: webpack.ResolveOptions['alias'], name: string) {
if (!alias) return false;
const exactName = `${name}$`;
if (Array.isArray(alias)) {
return alias.some(a => a.name === name || a.name === exactName);
} else {
const keys = Object.keys(alias);
return keys.includes(name) || keys.includes(exactName);
}
}

Also as a general idea. Not sure if this works but couldn't you point react to preact straight from package.json? I don't know if the APIs are identical but maybe you could create a dummy React package that exports Preact. Maybe use local paths in the react version string.

from react-cosmos.

birtles avatar birtles commented on May 28, 2024

Thank you!

I tried the local paths approach and that works too. That might be better than using Node's module-based permissions since they're still experimental.

I haven't debugged why React Cosmos can't find the aliases in my current webpack config but I've confirmed that if I make a separate webpack config for cosmos everything seems to work. I'll probably try to debug that later.

For reference, for the local paths approach I used the following package.json

{
  "name": "react-polyfill",
  "version": "4.0.0",
  "private": true,
  "description": "A wrapper around preact-compat so react-cosmos will load Preact instead of React",
  "main": "../node_modules/preact/compat/dist/compat.js",
  "module": "../node_modules/preact/compat/dist/compat.module.js",
  "umd:main": "../node_modules/preact/compat/dist/compat.umd.js",
  "source": "../node_modules/preact/compat/src/index.js",
  "types": "../node_modules/preact/compat/src/index.d.ts",
  "peerDependencies": {
    "preact": "^10.0.0"
  }
}

And referenced it from the root package.json like so:

    "react": "file:./react-polyfill/",
    "react-cosmos": "6.0.0-beta.6",
    "react-cosmos-plugin-webpack": "6.0.0-beta.6",
    "react-dom": "file:./react-polyfill/",

Regarding this issue, I guess the resolution is to add something to the docs about how to use Preact.

from react-cosmos.

birtles avatar birtles commented on May 28, 2024

I went back to this today but after rebasing my work somehow the local paths approach stopped working.

As best I can tell, node initially wants to require react using CJS when running react-cosmos on startup (despite my project and react-cosmos being ESM) so I can't just make the wrapper expose only the ESM version.

When it gets to react-cosmos-renderer, however, it seems to prefer loading as ESM when available but I can't make it available without adding "exports" to package.json and "exports" requires a relative path to a subdirectory so I can't do it from a wrapper (which refers to a parent directory).

i.e. node will reject something like the following:

{
  "name": "react-polyfill",
  "version": "4.0.0",
  "private": true,
  "description": "A wrapper around preact-compat so react-cosmos will load Preact instead of React",
  "main": "../preact/compat/dist/compat.js",
  "module": "../preact/compat/dist/compat.module.js",
  "umd:main": "../preact/compat/dist/compat.umd.js",
  "source": "../preact/compat/src/index.js",
  "types": "../preact/compat/src/index.d.ts",
  "exports": {
    ".": {
      "types": "../preact/compat/src/index.d.ts",
      "browser": "../preact/compat/dist/preact.module.js",
      "umd": "../preact/compat/dist/preact.umd.js",
      "import": "../preact/compat/dist/preact.mjs",
      "require": "../preact/compat/dist/preact.js"
    }
  },
  "peerDependencies": {
    "preact": "^10.0.0"
  }
}

I might have to go back to the policy approach after all.

from react-cosmos.

birtles avatar birtles commented on May 28, 2024

The module-based approach seems to work fine so I'll stick with that. It basically boils down to:

  1. Add a file, e.g. cosmos-policy.json
{
  "dependencies": true,
  "scopes": {
    "": {
      "cascade": true,
      "integrity": true,
      "dependencies": {
        "react": "./node_modules/preact/compat/dist/compat.mjs"
      }
    }
  }
}
  1. Update package.json to include:
{
  "scripts": {
    "cosmos": "node --experimental-policy=cosmos-policy.json node_modules/react-cosmos/bin/cosmos.js",
    "cosmos-export": "node --experimental-policy=cosmos-policy.json node_modules/react-cosmos/bin/cosmos-export.js"
  }
}

Also, I debugged why react-cosmos-plugin-webpack wasn't handling my webpack.config.js and it appears to be because it doesn't handle multiple configurations.

from react-cosmos.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.