Package.json 使用 webpack 5 导出 - 未找到动态导入的模块

Package.json exports with webpack 5 - dynamically imported module not found

我在协调国际化语言环境的动态导入路径时遇到了一些麻烦。这是相关代码-

function getLoader(
  lang: SupportedLanguage,
  ns: SupportedNamespace
): NamespaceLoader | undefined {
  const matrixToCheck = UNSUPPORTED_MATRIX[ns];
  const isSupported = matrixToCheck && matrixToCheck.indexOf(lang) === -1;
  if (isSupported) {
    const path = `./locales/${lang}/${ns}.json`;
    const name = `${lang}_${ns}`;
    const named = {
      [name]: () => import(`${path}`),
    };
    return named[name];
  }
}
...
// eventual output
const SUPPORTED_LANGUAGES = {en: {namespace1: () => import('./locales/en/namespace1.json')}

我的目标是在单个 npm 包中管理所有相关翻译,在构建时处理所有动态导入设置,然后消费者可以调用 getter(getTranslation在这种情况下)在他们各自的应用程序中选择他们选择的语言和命名空间以在运行时获取有效负载。

Based on this GH thread,我想通过 package.json

协调语言环境 dist 路径
 ...
 "exports": {
    ".": "./dist/src/main.js",
    "./": "./dist/"
  },
 ...

例如当我发布包时,基于 exports 配置,消费者会知道如何在调用 getter 时协调路径,无论是相对路径还是包名称前缀

const fn = () => import('./locales/fr/myNamespace.json')  /// doesn't work
const anotherFn = () => import('@examplePackageName/locales/fr/myNamespace.json') /// doesn't work

由于一切都是动态的,我使用 CopyWebpackPlugin 将语言环境包含在 dist 文件夹中。

这在本地按预期工作,但是当我创建 dist 时,出现错误 Error: Module not found ./relative/path/to/the/json/I/want.json

我的问题:

我错过了什么?有没有一种简单的方法来公开这些翻译,以便其他应用程序可以通过 npm 安装的包将它们包含在它们的包中?

这是我的 Webpack 配置,很乐意根据需要提供其他信息

const path = require("path");
const CopyPlugin = require("copy-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");

const getPlugins = () => {
  return [
    new CleanWebpackPlugin(),
    new CopyPlugin({
      patterns: [{ from: "locales", to: "locales" }],
    }),
  ];
};

module.exports = {
  mode: "production",
  entry: {
    main: "./src/main.ts",
  },
  output: {
    path: path.join(__dirname, "dist"),
    filename: "src/[name].js",
    chunkFilename: "chunk.[name].js",
    libraryTarget: "commonjs2",
  },

  resolve: {
    extensions: [".json", ".ts", ".js"],
    alias: {
      "@locales": path.resolve(__dirname, "locales/*"),
    },
  },
  plugins: getPlugins(),
  module: {
    rules: [
      {
        test: /\.ts$/,
        exclude: [/\.test\.ts$/],
        include: path.join(__dirname, "src"),
        loader: "ts-loader",
      },
    ],
  },
};

Exports 指令规定定义允许显式导入的所有文件 (documentation)。它允许开发人员隐藏内部包文件结构。该指令未导出的内容只能在包内导入,而不能在包外导入。它旨在简化维护。它允许开发人员重命名文件或更改文件结构,而不必担心破坏依赖包和应用程序。

因此,如果您想让内部文件在导入时可见,您应该使用 exports 指令显式导出它们,如下所示:

{
  "exports": {
      ".": "./dist/esm/src/main.js",
      "./dist/shared/locale/fr_fr.json": "./dist/shared/locale/fr_fr.json"
  }
}

我不确定 Webpack 是否处理这种情况,因为它是一个实验性功能。但这就是 Node.js 现在的工作方式。

为什么会这样

更改您的应用程序文件结构在 semver 术语中是一项重大更改,因此您需要在每次重命名或删除文件时升级一个版本。为避免它,您可以指定哪些文件是包的 public 接口的一部分。