首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >模块在Next.js项目的类型记录单例中没有解析

模块在Next.js项目的类型记录单例中没有解析
EN

Stack Overflow用户
提问于 2022-02-07 16:04:50
回答 3查看 3K关注 0票数 6

我有一个使用纱线工作区的monorepo,它有2个Next.js项目。

代码语言:javascript
运行
复制
apps
 ┣ app-1
 ┗ app-2

app-1需要从app-2导入组件。为此,我将app-2项目添加为依赖项,并在app-1 tsconfig中设置路径,如下所示:

代码语言:javascript
运行
复制
app-1 package.json
{
  "name": "@apps/app-1",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@apps/app-2": "workspace:*",
  }
}
代码语言:javascript
运行
复制
app-1 tsconfig.json

{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@apps/app-2/*": ["../../app-2/src/*"],
      "@apps/app-2": ["../../app-2/src"]
    }
  }
}

但是,当app-2中的组件导入其他组件(如import Component from "components/Component" )时,问题就会发生。

app-1不知道如何解析它,并且正在它自己的src文件夹中寻找不存在的components/Components。如果像这个import Component from ../../Component一样导入相同的组件,它就会正确地解析。为了解决这个问题,我在app-1的tsconfig文件中设置了另一条路径来手动解析。

代码语言:javascript
运行
复制
app-1 tsconfig
{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "components/*": ["../../app-2/src/components/*"], // new path resolves absolute urls from app-2
      "@apps/app-2/*": ["../../app-2/src/*"],
      "@apps/app-2": ["../../app-2/src"]
    }
  }
}

如果没有这一行文本,尝试开发或构建app-1项目会呈现Type error: Cannot find module 'components/Component' or its corresponding type declarations.,我不想以这种方式手动解析它,因为app-1可能希望有一天它自己的components文件夹,并错误地解析到app-2的components文件夹。

这看起来像是一个基于错误的打印文本问题,但我无法判断它是否与webpack/babel有关,还是与我们node_modules中的符号链接有关?

理想的解决方案是使用配置或加载程序更改某些内容,并按照您的预期进行这些路径解析。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2022-03-30 15:48:04

我已经尝试了提供的答案,但不幸的是,它们对我不起作用。在阅读了一些文档之后,最终修复它的是app-1中的一个简单的tsconfig更改。

代码语言:javascript
运行
复制
{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "*": ["*", "../../app-2/src/*"], // try to resolve in the current baseUrl, if not use the fallback.
      "@apps/app-2/*": ["../../app-2/src/*"], // reference app-2 imports inside app-1 like "import X from '@apps/app-2/components'"
    }
  }
}

请注意,由于这两个项目都是共享代码的Next.js项目,所以我不得不使用next-transpile模块,并按照它们的文档中所概述的那样,将每个next.config.js封装在withTM函数中。

票数 0
EN

Stack Overflow用户

发布于 2022-02-22 07:37:51

next.jswebpackConfig.resolve加载tsconfig.json。请参见:

app-2中的组件导入其他组件(如import Component from "components/Component" )时,webpack根据app-1/tsconfig.json解析components/Component

解决方案:为resolve plugin添加一个app-2

  1. app-1/tsconfig.json
代码语言:javascript
运行
复制
{
  //...
  "compilerOptions":{
    //...
    "paths": {
      "@apps/*": ["../app-2/*"],
      "components/*": ["./components/*"]
    },
  }
}
  1. app-2/tsconfig.json
代码语言:javascript
运行
复制
{
  //...
  "compilerOptions":{
    //...
    "paths": {
      "components/*": ["./components/*"]
    },
  }
}
  1. app-1/next.config.js
代码语言:javascript
运行
复制
const path = require("path");

// fork from `@craco/craco/lib/loaders.js`
function getLoaderRecursively(rules, matcher) {
  let loader;

  rules.some((rule) => {
    if (rule) {
      if (matcher(rule)) {
        loader = rule;
      } else if (rule.use) {
        loader = getLoaderRecursively(rule.use, matcher);
      } else if (rule.oneOf) {
        loader = getLoaderRecursively(rule.oneOf, matcher);
      } else if (isArray(rule.loader)) {
        loader = getLoaderRecursively(rule.loader, matcher);
      }
    }

    return loader !== undefined;
  });

  return loader;
}


const MyJsConfigPathsPlugin = require("./MyJsConfigPathsPlugin");
const projectBBasePath = path.resolve("../app-2");
const projectBTsConfig = require(path.resolve(
  projectBBasePath,
  "tsconfig.json"
));

module.exports = {
  webpack(config) {
    const projectBJsConfigPathsPlugin = new MyJsConfigPathsPlugin(
      projectBTsConfig.compilerOptions.paths,
      projectBBasePath
    );

    config.resolve.plugins.unshift({
      apply(resolver) {
        resolver
          .getHook("described-resolve")
          .tapPromise(
            "ProjectBJsConfigPathsPlugin",
            async (request, resolveContext) => {
              if (request.descriptionFileRoot === projectBBasePath) {
                return await projectBJsConfigPathsPlugin.apply(
                  resolver,
                  request,
                  resolveContext
                );
              }
            }
          );
      },
    });

    // get babel-loader
    const tsLoader = getLoaderRecursively(config.module.rules, (rule) => {
      return rule.test?.source === "\\.(tsx|ts|js|mjs|jsx)$";
    });

    tsLoader.include.push(projectBBasePath);

    return config;
  },
};
  1. MyJsConfigPathsPlugin.js
代码语言:javascript
运行
复制
// fork from `packages/next/build/webpack/plugins/jsconfig-paths-plugin.ts`

const path = require("path");

const {
  // JsConfigPathsPlugin,
  pathIsRelative,
  matchPatternOrExact,
  isString,
  matchedText,
  patternText,
} = require("next/dist/build/webpack/plugins/jsconfig-paths-plugin");
const NODE_MODULES_REGEX = /node_modules/;

module.exports = class MyJsConfigPathsPlugin {
  constructor(paths, resolvedBaseUrl) {
    this.paths = paths;
    this.resolvedBaseUrl = resolvedBaseUrl;
  }

  async apply(resolver, request, resolveContext) {
    const paths = this.paths;
    const pathsKeys = Object.keys(paths);

    // If no aliases are added bail out
    if (pathsKeys.length === 0) {
      return;
    }

    const baseDirectory = this.resolvedBaseUrl;
    const target = resolver.ensureHook("resolve");

    const moduleName = request.request;

    // Exclude node_modules from paths support (speeds up resolving)
    if (request.path.match(NODE_MODULES_REGEX)) {
      return;
    }

    if (
      path.posix.isAbsolute(moduleName) ||
      (process.platform === "win32" && path.win32.isAbsolute(moduleName))
    ) {
      return;
    }

    if (pathIsRelative(moduleName)) {
      return;
    }

    // If the module name does not match any of the patterns in `paths` we hand off resolving to webpack
    const matchedPattern = matchPatternOrExact(pathsKeys, moduleName);
    if (!matchedPattern) {
      return;
    }

    const matchedStar = isString(matchedPattern)
      ? undefined
      : matchedText(matchedPattern, moduleName);
    const matchedPatternText = isString(matchedPattern)
      ? matchedPattern
      : patternText(matchedPattern);

    let triedPaths = [];

    for (const subst of paths[matchedPatternText]) {
      const curPath = matchedStar ? subst.replace("*", matchedStar) : subst;

      // Ensure .d.ts is not matched
      if (curPath.endsWith(".d.ts")) {
        continue;
      }

      const candidate = path.join(baseDirectory, curPath);
      const [err, result] = await new Promise((resolve) => {
        const obj = Object.assign({}, request, {
          request: candidate,
        });
        resolver.doResolve(
          target,
          obj,
          `Aliased with tsconfig.json or jsconfig.json ${matchedPatternText} to ${candidate}`,
          resolveContext,
          (resolverErr, resolverResult) => {
            resolve([resolverErr, resolverResult]);
          }
        );
      });

      // There's multiple paths values possible, so we first have to iterate them all first before throwing an error
      if (err || result === undefined) {
        triedPaths.push(candidate);
        continue;
      }

      return result;
    }
  }
};
票数 4
EN

Stack Overflow用户

发布于 2022-02-28 16:21:02

您可以使用babel配置,如下所示。

使用模块解析器插件。

安装:yarn add -D babel-plugin-module-resolver

然后遵循这个配置文件。

代码语言:javascript
运行
复制
module.exports = {
  presets: [], //Keep your preset as it is
  plugins: [
    [
      'module-resolver',
      {
        root: ['./src'],
        extensions: ['.js', '.jsx', '.json', '.svg', '.png', '.tsx'],
        // Note: you do not need to provide aliases for same-name paths immediately under root
        alias: {
          "@apps/app-2": '../../app-2/src',
        },
      },
    ],
    
  ],
};
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71021646

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档