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

create-react-app + jsconfig.json paths: modules/scripts not found #7205

Closed
ppalmeida opened this issue Jun 26, 2019 · 7 comments
Closed

create-react-app + jsconfig.json paths: modules/scripts not found #7205

ppalmeida opened this issue Jun 26, 2019 · 7 comments
Assignees
Labels
cra Prioritize create-react-app compatibility

Comments

@ppalmeida
Copy link

Describe the bug
When using CRA and "jsconfig.json": if I set "path" property to solve imports alias, the app works as expected running CRA, but Storybook crashes saying it can't resolve imports.

To Reproduce
Steps to reproduce the behavior:

  1. Start a new CRA app
  2. Create some containers and import them using aliases.
  3. Fill jsconfig.json file with paths/alias and make sure it works ok when building using CRA
  4. Try running Storybook: it crashes
  5. See modules not found error

Expected behavior
Shouldn't Storybook take the paths from jsconfig.json file - or solve it someway with full control mode, where I could solve the imports using "resolve" with Webpack?

Code snippets

This is my current jsconfig.json file (Using it with Create React App it works perfectly and the app builds with no errors):

// jsconfig.json
{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@mycompany/app/*": ["./packages/app/*"],
      "@mycompany/http/*": ["./packages/http/*"],
      "@mycompany/icons/*": ["./packages/icons/*"],
      "@mycompany/ui/*": ["./packages/ui/*"]
      // etc...
    }
  },
  "exclude": ["node_modules", "build", "coverage", "dist", "lib"]
}

This is the .storybook/config.js file.

// .storybook/config.json
import { addDecorator, configure } from '@storybook/react';
import { withKnobs } from '@storybook/addon-knobs/react';
import JssProvider from 'react-jss/lib/JssProvider';
import MuiThemeProvider from '@material-ui/core/styles/MuiThemeProvider';
import React from 'react';

import TooltipProvider from '../src/packages/ui/src/Tooltip/TooltipProvider';
import theme from '../src/packages/app/src/theme';

addDecorator(withKnobs);

const generateClassName = (rule, styleSheet) =>
  `${styleSheet.options.classNamePrefix}-${rule.key}`;

addDecorator(story => (
  <JssProvider generateClassName={generateClassName}>
    <MuiThemeProvider theme={theme}>
      <TooltipProvider>
        <div
          style={{
            position: 'absolute',
            top: 0,
            right: 0,
            bottom: 0,
            left: 0,
            width: '100%',
            height: '100%'
          }}
        >
          {story()}
        </div>
      </TooltipProvider>
    </MuiThemeProvider>
  </JssProvider>
));

const req = require.context('../src', true, /.*.stories.js$/);

const loadStories = () => {
  req.keys().forEach(filename => req(filename));
};

configure(loadStories, module);

Also, I've tried to use the full control mode, with this config:

// .storybook/webpack.config.js
const path = require('path');

module.exports = async ({ config }) => {

  config.resolve = Object.assign(config.resolve, {
    alias: {
      "@mycompany/app": path.resolve(__dirname, "../src/packages/app/"),
      "@mycompany/http": path.resolve(__dirname, "../src/packages/http"),
      "@mycompany/icons": path.resolve(__dirname, "../src/packages/icons"),
      // etc...
    }
  });

  return config;
}

System:

  • OS: MacOS 10.14.5
  • Version: "@storybook/react": "^5.0.10"
@CodeByAlex CodeByAlex added the cra Prioritize create-react-app compatibility label Jun 26, 2019
@mrmckeb
Copy link
Member

mrmckeb commented Jul 1, 2019

Hey @ppalmeida, sorry you're facing this issue. Could you try updating your Storybook version to the latest stable versions - if that doesn't help, please let me know.

Also, keep in mind that Create React App doesn't support paths officially, and we've not tested that in Storybook.

Can you also share a test repository that I could have a look at? A basic reproduction only.

@mrmckeb
Copy link
Member

mrmckeb commented Jul 1, 2019

PS: Sorry for the slow reply, I've been away.

@mrmckeb mrmckeb self-assigned this Jul 1, 2019
@ppalmeida
Copy link
Author

Hey, @mrmckeb.
Thank you for your reply.

Actually I have to say I was completely WRONG when said that CRA was assuming jsconfig.json file and using it to resolve the paths/alias. No no. Not, at least, not YET

So, I think we can close this issue.

For those who is interested in having CRA working with paths (or, if you prefer alias) to your folders/packages, here it is what I did to make it work (without eject CRA)

Step 1

I prefer not to eject CRA, so I went with some plugin: I used the well known create-react-app-rewired

Step 2

After install it, I created a config-overrides.js in the root of the app and put this inside:

const path = require("path");

const resolve = dir => path.resolve(__dirname, dir);

module.exports = function(config, env) {
  config.resolve.alias = Object.assign(config.resolve.alias, {
    "@mycompany/app": resolve("src/packages/app"),
    "@mycompany/core": resolve("src/packages/core"),
    "@mycompany/http": resolve("src/packages/http"),
    // etc...
  });

  return config;
};

Step 3

Then, I created the jsconfig.json file with these lines:

{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@mycompany/app/*": ["packages/app/*"],
      "@mycompany/core/*": ["packages/core/*"],
      "@mycompany/http/*": ["packages/http/*"],
      // etc... you got the idea...
    }
  },
  "exclude": ["node_modules", "build", "coverage", "dist", "lib"]
}

And then you would ask: "But why use this file if you already did the rewired webpack in step 2?". Because jsconfig.json file helps your IDE to find your modules and files, etc. At least, my VSCode works better on this way.

Step 4: JEST

JEST: now, you must run your tests, right? So, add these lines to your package.json also:

// etc...
"jest": {
    "moduleNameMapper": {
      "^@mycompany/app(/?)(.*?)$": "packages/app$1$2",
      "^@mycompany/core(/?)(.*?)$": "packages/core$1$2",
      "^@mycompany/http(/?)(.*?)$": "packages/http$1$2",
    }
  },

Pretty nasty, ahn? The keys are RegExp that Jest uses to find your files. And "Why did you use 2 groups in your regex, if they are at the end of the string anyway?". Well, this is how Webpack (or Jest, I'm not sure) will match your files:

So, these both will work:

import MyAwesomeModule from '@mycompany/app'
import MyOtherAwesomeModule from '@mycompany/app/folder1/folder2/MyOtherAwesomeModule';

Step 5: Storybook

Well, let's put Storybook in full-control mode, so we can apply the same concepts to Storybook as well. To do that, you must create a webpack.config.js file inside .storybook folder and add there your packages "binds" too:

const path = require("path");

const resolve = dir => path.resolve(__dirname, dir);

module.exports = async ({ config }) => {
  config.resolve = Object.assign(config.resolve, {
    alias: {
      "@mycompany/app": resolve("../src/packages/app"),
      "@mycompany/core": resolve("../src/packages/core"),
      "@mycompany/http": resolve("../src/packages/http"),
    }
  });

  return config;
};

Note that, since this file is inside .storybook folder, the path needs the ../ before all src/etc folder.

Bottom Line:

I don't know if there is a better strategy here. Maybe there is a really better way. Keep NODE_PATH in .env file and ignore the CRA warning? Maybe eject CRA? Maybe use NextJS?

As I put in the link in the beginning, I think CRA will soon have it's "way" of offering path out of the box. But, for now, I don't think it's worth to do all these configurations. For me, it's too much effort. Anyway, maybe it can help someone.

cheers

@yairEO
Copy link
Contributor

yairEO commented May 14, 2020

@ppalmeida - what about ESLINT?
what about globbing paths (**) for importing deeply nested files in those aliases?

@xppalmeida
Copy link

Hey, @yairEO.

About the **, they are not much useful I think. Since all alias just ends up with packages/app/* (a single * will do the trick). Maybe on Jest aliases, that uses those two matching groups like this one:

"^@mycompany/app(/?)(.*?)$": "packages/app$1$2",

But I'm not sure. didn't test it. I'll take a look.

Talking about ESLint, what's the problem you're facing? Because the ESLint works well here without any other additional configuration. Do you want to share some particular problem you're facing at?

@yairEO
Copy link
Contributor

yairEO commented May 18, 2020

@xppalmeida - I was facing problems where eslint complained about not being able to resolve my absolute paths but I've managed to fix them!

Using this resolver: eslint-import-resolver-node

eslint configuration file (relevant part)

settings: {
    'import/resolver': {
        'node': {
            'paths': ['./', './src']
    }
}

.env

...
NODE_PATH=./

jsconfig.json

{
    "compilerOptions": {
        "jsx": "react",
        "baseUrl": "./",
        "paths": {
            "stories/*": ["stories/*"],
            "shared/*": ["src/shared/*"],
        },
    },
    "include": ["src/**/*", "stories/**/*"]
}

only with 'paths': ['./', './src'] in my eslint config things the linter worked resolving the paths correctly.

Storybook seems to work well with the above configuration and nothing else.

@ppalmeida
Copy link
Author

Really good to know! Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cra Prioritize create-react-app compatibility
Projects
None yet
Development

No branches or pull requests

5 participants