如何通过webpack在CRA(create-react-app)和craco中设置别名路径?

9

我在使用create-react-appcraco时,设置webpack别名路径出现了问题,已经搜索过但无法解决。

每次使用命令yarn start运行应用程序时,都会收到错误消息:Module not found: Can't resolve '@app/App' in 'C:\ReactSandbox\my-project\src

重现步骤:

  1. create-react-app my-project
  2. cd my-project
  3. yarn add @craco/craco
  4. cat > craco.config.js (请参见下面的配置)
  5. 将package.json中的“script”部分中的“react-scripts”替换为“craco”(例如:craco start、craco build等)
  6. 编辑文件src/index.js(请参见下面的代码)
  7. yarn start

craco.config.js

const path = require("path");

module.exports = {
  webpack: {
    resolve: { 
      alias: {
        "@app": path.resolve(__dirname, "src/"),
      }
    }    
  }
};

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from '@app/App'; //replace './App' into '@app/App'
import * as serviceWorker from './serviceWorker';

ReactDOM.render(<App />, document.getElementById('root'));

serviceWorker.unregister();

当前结果

模块未找到:无法解析'C:\ReactSandbox\my-project\src'中的'@app / App'

期望结果

我避免使用冗长的相对路径,而是像这样导入模块:@app/FilterComment.js,这样会更加清晰明了,而不是像这样:../../../../FilterComment.js


去掉 "resolve: { }" 对我有用。 - user14140381
8个回答

11

针对carco的解决方案:

您需要安装craco-alias,然后在craco.config.js文件中编写代码。

    const CracoAlias = require('craco-alias')

    module.exports = {
      plugins: [
        {
          plugin: CracoAlias,
          options: {
            source: 'tsconfig',
            baseUrl: '.',
            tsConfigPath: './tsconfig.path.json',
          },
        },
      ],
    }

tsconfig.path.json

    {
      "compilerOptions": {
        "baseUrl": ".",
        "paths": {
          "@/*": ["src/*"],
          "@svg/*": ["src/assets/svg/*"],
          "@img/*": ["src/assets/images/*"],
          "@icons/*": ["src/assets/icons/*"],
          "@shared/*": ["src/shared/*"],
          "@components/*": ["src/components/*"],
          "@hooks/*": ["src/hooks/*"],
          "@constants/*": ["src/constants/*"],
          "@layout/*": ["src/layout/*"],
          "@services/*": ["src/services/*"]
        }
      }
    }

tsconfig.json

    {
      "extends": "./tsconfig.path.json",
      "compilerOptions": {
        "target": "es5",
        "lib": [
          "dom",
          "dom.iterable",
          "esnext"
        ],
        "allowJs": true,
        "checkJs": false,
        "skipLibCheck": true,
        "esModuleInterop": true,
        "allowSyntheticDefaultImports": true,
        "declaration": false,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "strict": true,
        "forceConsistentCasingInFileNames": true,
        "module": "esnext",
        "moduleResolution": "node",
        "resolveJsonModule": true,
        "isolatedModules": true,
        "noEmit": true,
        "jsx": "react-jsx",
        "noFallthroughCasesInSwitch": true,
        "removeComments": true
      },
      "include": [
        "src",
        "src/configs",
        "react-app-env.d.ts"
      ]
    }


这是正确的。已点赞。终于解决了我的问题。谢谢! - Jay-R Joseph Gabunada
如何使用?import myhooks from @hooks/hooks.tsx - ANimator120

6

第一步 - 在 tsconfig.json 中告诉 IDE 别名:

创建独立的文件 tsconfig.paths.json 并添加别名:

{
   "compilerOptions": {
      "baseUrl": "./src",
      "paths": {
         "@utils/*": ["utils/*"]
      }
   }
}

将创建的tsconfig.paths.json添加到主要的tsconfig.json文件中。
{
   "extends": "./tsconfig.paths.json",
   ... other staff ...
}

第二步 - 告诉webpack如何使用别名:

config-overrides.js中添加别名。

const {
   override,
   addWebpackAlias
} = require('customize-cra');

const path = require("path");

module.exports = override(
   addWebpackAlias({
      "@utils": path.resolve(__dirname, "./src/utils"),
   }),
);

4

我的craco.config.js文件如下所示,它可以正常工作:

const path = require('path');

module.exports = {
    // ...
    webpack: {
        alias: {
            '@': path.join(path.resolve(__dirname, './src')),
        }
    }
}

不需要使用 craco 弹出。我使用相同的 craco.config.js 别名设置,但没有使用 path.join,这样就可以正常工作了。 - Ahmed Rafik Ibrahim
不需要使用 path.join 包装 path.resolve 的结果。 - Parzh from Ukraine
如果我们有带作用域的节点包,比如 @sentry/react,那么这会是怎样的情况呢? - Murtaza Hussain
根据某些Node.js文档,他们建议使用#而不是@,这也是我所做的...虽然有点奇怪,但它确实有效...并且Node.js也建议这样做。我感觉还有更明确的建议,但是在这里隐含地提到了。这避免了与@的冲突。 - wongz

2

只需保持你的文件craco.config.js不变,你需要再添加一个名为jsconfig.json的文件。

它的内容如下:

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es2016",
    "jsx": "preserve",
    "checkJs": true,
    "baseUrl": "./src/",
    "paths": {
      "@app/*": ["./*"]
    }
  },
  "exclude": ["node_modules", "**/node_modules/*"]
}

那么你可以像这样从绝对路径导入:@app/FilterComment.js

这也适用于VSCode(编辑器现在理解@app指向哪里)。 但是,如果你希望VSCode自动进行导入,则应该为其添加更多配置,以强制它始终从绝对路径进行导入。

文件.vscode/settings.json 内容:

Original Answer翻译成"最初的回答"

{
  "javascript.preferences.importModuleSpecifier": "non-relative"
}

4
React脚本不允许您将“paths”放入tsconfig.json中,它会自动为您删除。 - Pedro Soares
为了防止 react-script 脚本从 tsconfig.json 中删除 paths,请创建 _tsconfig.path.json_(例如),添加 paths 设置并在 tsconfig.json 中进行扩展。 - darkziul

1

使用react-app-alias

  • 安装cracoreact-app-alias,并创建 craco 配置文件:
// craco.config.js
const {CracoAliasPlugin} = require('react-app-alias')

module.exports = {
  plugins: [
    {
      plugin: CracoAliasPlugin,
      options: {}
    }
  ]
}

在 package.json 中将 react-scripts 替换为 craco

创建类型定义配置和别名,可以像这样分开写成两个独立的配置文件:

// tsconfig.paths.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "example/*": ["example/src/*"],
      "@app/*": ["app/src/*"]
    }
  }
}

// tsconfig.json
{
  "extends": "./tsconfig.paths.json",
  // ...
}

现在你可以这样导入:
   import App from '@app/App'

你的 react-app-rewire-alias 和另一个有什么区别?你会支持哪一个? - wongz

1

一个没有使用依赖项的示例(我正在使用):

//craco.config.js
const path = require('path')

const tsconfig = require('./tsconfig.base.json')

const removeAsterisk = path => path.replace('/*', '')

const aliasProps = Object.entries(tsconfig.compilerOptions.paths).map(([key, value]) => {
  const newKey = removeAsterisk(key)
  let newValue = removeAsterisk(value[0])
  newValue = path.resolve(__dirname, newValue)
  return [newKey, newValue]
})

const alias = Object.fromEntries(aliasProps)

module.exports = {
  webpack: {
    alias,
  },
}


//tsconfig.base.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "~/*": ["./src/*"],
      //...
    }
  }
}


// tsconfig.json
{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {/*...*/}
}


0

我正在使用craco-alias插件自动生成Webpack和Jest的别名。 (我只是一名实习生,但这就是我们公司的高级开发人员在React中使用绝对导入的方式)

安装

yarn add @craco/craco
yarn add craco-alias

craco.config.js

const CracoAlias = require('craco-alias');

module.exports = {
  plugins: [
    {
      plugin: CracoAlias,
      options: {
        source: 'tsconfig',
        baseUrl: './src',
        tsConfigPath: './tsconfig.paths.json', // or wherever you have defined your paths
      },
    },
  ],
};

请确保您的 package.json 文件中的脚本如下所示

"scripts": {
    "start": "craco start",
    "build": "craco build",
    "test": "craco test",
    "eject": "craco eject",
    ...
  },

然后它将按照tsconfig.json中指定的方式工作。

顺便说一下,我有以下这些依赖, "react-scripts": "4.0.3" "@craco/craco": "^6.3.0" "craco-alias": "^3.0.1"


0
也许原帖作者使用的是不同版本的React/Webpack(我使用的是最新版本),但是将alias对象直接放在webpack对象内部(而不是嵌套在resolve对象中)对我来说起到了作用:
const path = require("path");

module.exports = {
  webpack: {
    alias: {
      "@app": path.resolve(__dirname, "src"),
    }
  }
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接