oklas / react-app-alias

:label: Alias and multiple src directory for craco or rewired create-react-app
MIT License
173 stars 18 forks source link

Rewire alias from outside of root folder? #3

Closed Elyx0 closed 2 years ago

Elyx0 commented 4 years ago
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@libcommon/*": ["../../shared/common/*"]
    }
  }
}

Is there a way of making it work for imports outside of the current folder? It works on the node side with ts-nodebut in cra not yet..

oklas commented 4 years ago

Thanks for clarification that it is not works by default (it will be cool otherwise as that was with alias inside src). Seems, as far as I remember there additional restrictions to imports outside of project root in react scripts, but I did not analyze that carefully due to it was not necessary that time. I definitely interesting in this question and I would like to see. But currently there is no time for that absolutely. I hope this week make it possible to see.

JollyGoodHolly commented 4 years ago

@Elyx0 Is your project written in TypeScript? I had the same issue that ESLint could not process my files in an outside directory. I believe the root cause is CRA's ESLint configuration, which has the this override for TypeScript files: ['**/*.ts?(x)']. Because this matches only sub-files of the compiling project, TypeScript files from the other project are interpreted with the standard JavaScript linter, which fails (and is then cached, leading to pollution).

To solve this issue, I tried overriding this override, but ESLint does not support external files and gives this error: Invalid override pattern (expected relative path not containing '..')

Instead, I excluded the external library from the ESLint rule altogether by changing expandRulesInclude like this:

function expandRulesInclude(rules, include, ignoreForEslint) {
  rules.forEach(function (rule) {
    if (rule.include === paths.appSrc && !ignoreForEslint)
      rule.include = include.concat(rule.include)
    if (rule.oneOf)
      expandRulesInclude(rule.oneOf, include, false)
  })
}

My project now works, the only downside is that the external project is now excluded from lint-checking, which probably cannot be fixed.

@oklas Do you think you can implement these changes? To not break the existing behaviour, I also altered the alias function like this:

function alias(aliasMap, ignoreForEslint = false) {
  const aliasLocal = Object.keys(aliasMap).reduce((a, i) => {
    a[i] = path.resolve(paths.appPath, aliasMap[i])
    return a
  }, {})
  return function (config) {
    expandResolveAlias(config.resolve, aliasLocal)
    expandRulesInclude(config.module.rules, Object.values(aliasLocal), ignoreForEslint)
    expandPluginsScope(config.resolve.plugins, Object.values(aliasLocal))
    return config
  }
}

I then called the function in my config-overrides.js with true as the second parameter to fix my problem.

oklas commented 4 years ago

@JollyGoodHolly, Some how I can not reproduce the problem with ts source outside of project root dir. Try to use aliasDangerous instead of alias from 0.1.5.

const {aliasDangerous} = require('react-app-rewire-alias/lib/aliasDangerous')

Let me know if the problem is solved or create repo with minimal reproducible example otherwise so I can see with details.

JollyGoodHolly commented 4 years ago

@oklas This almost works, but there is one bug:

- if(rule.use && 0 < rule.use.filter(isRuleOfEslint)) return true
+ if(rule.use && 0 < rule.use.filter(isRuleOfEslint).length) return true

Otherwise, this function always returns false. You can easily test it like this:

module.exports = function override(config) {
    const configCopy = JSON.parse(JSON.stringify(config));

    aliasDangerous({
        ...configPaths('tsconfig.paths.json')
    })(config);

    console.log("These should be equivalent:")
    console.log(configCopy.module.rules[1].include);
    console.log(config.module.rules[1].include);

    return config;
}

Also note that you might have cache pollution and need to delete the .cache folder in node_modules. I opened a new PR with the fix for the fix and some documentation.

oklas commented 4 years ago

I suggests introduce restriction to paths outside of root for base alias due to

So base alias will not supports aliases from outside of project root folder. To use aliases from outside of root folder (if possible) here will be special implementation alaisDangerous

Implmentation of alaisDangerous will use code from base alias but not vice versa. The base alias must not use and must not import or require code from alaisDangerous.

tobloef commented 4 years ago

Just for clarification, does this mean that the line "provided fully functional aliases and allows the use of Babel, JSX, etc. outside of src" in the README is false at the moment or am I misunderstanding?

For context, I'm trying to create an alias to a folder outside my React project folder in a monorepo and I can't seem to get it to work. What I would like to do is something like '@shared': '../shared/src' but my files inside shared still can't be resolved from the React app.

edolix commented 3 years ago

@tobloef were you be able to have React resolve the '@shared': '../shared/src' package? Thanks!

oklas commented 3 years ago

Hi, @tobloef, @edolix, if problem relevant create-react-app or react-scripts v4.0 please track or submit #9.

I rewrite and simplify docs to show what need to do for these days to make it worked (instead of which files and options are exists and its possible values). I also added an example project it works - check it 🚴‍♂️ (it uses temporary patch - read #9). Feel free to ask. Subscribe to twitter for a news.👍

diegoaraujolima commented 3 years ago

I try aliasDangerous, but, on require:

const {aliasDangerous} = require('react-app-rewire-alias/lib/aliasDangerous')

causes error:

function expandRulesInclude(rules, include) { ^

SyntaxError: Identifier 'expandRulesInclude' has already been declared at wrapSafe (internal/modules/cjs/loader.js:931:16) at Module._compile (internal/modules/cjs/loader.js:979:27) at Object.Module._extensions..js (internal/modules/cjs/loader.js:1035:10) at Module.load (internal/modules/cjs/loader.js:879:32) at Function.Module._load (internal/modules/cjs/loader.js:724:14) at Module.require (internal/modules/cjs/loader.js:903:19) at require (internal/modules/cjs/helpers.js:74:18) at Object. (C:\Desenvolvimento\Git\JavaScript\projetos\pdvsuite\web\node_modules\react-app-rewire-alias\lib\aliasDangerous.js:1:18) at Module._compile (internal/modules/cjs/loader.js:1015:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:1035:10)

diegoaraujolima commented 3 years ago

Ok, i remove the duplicate method aliasDangerous.js, but now the error returns:

Module not found: You attempted to import C:\Desenvolvimento\Git\JavaScript\projetos\pdvsuite\web\framework/Componentes/Botoes/BotaoAdicionar which falls outside of the project src/ directory. Relative imports outside of src/ are not supported.

"\framework" is a simbolic link (Windows), but if i try with the relative path de same error occour.

I use:

const {aliasDangerous} = require('react-app-rewire-alias/lib/aliasDangerous')
module.exports = function override(config) {
  return aliasDangerous({
    framework: 'framework',
  })(config)
}

The problem occour if i use a full or relative path to a outside directory of root.

oklas commented 2 years ago

Released v1.1.0 (available for craco and react-app-rewired)


image image