从 javascript 包的子文件夹导入

Importing from subfolders for a javascript package

我有一个包含多个文件夹的打字稿库。每个文件夹都包含一个 index.ts 文件,该文件导出一些业务逻辑。我正在尝试将其与汇总捆绑在一起以在呼叫站点上实现此行为:

import { Button, ButtonProps } from 'my-lib/button'
import { Input, Textarea } from 'my-lib/input'
import { Row, Column } from 'my-lib/grid'

这是目录结构:

我在 src/ 下有一个主要 index.ts,其中包含:

export * from './button';
export * from './input';
export * from './grid';

有了这个风格,我可以做到:

import { Button, Input, InputProps, Row, Column } from 'my-lib'

但我不想要这个。我想通过它们的命名空间访问每个模块。如果我从 index.ts 文件中删除导出,我所能做的就是:

import { Button } from 'my-lib/dist/button'

这是我以前没见过的。添加 dist/ 到 import 语句意味着我通过相对路径访问模块。我想要 my-lib/Button.

我正在使用汇总。我尝试使用 alias 插件但没有用。下面是我的汇总配置:

const customResolver = resolve({
  extensions: ['ts'],
});

export default {
  input: `src/index.ts`,
  output: [
    {
      file: pkg.main,
      format: 'cjs',
      sourcemap: true,
      // plugins: [terser()],
    },
    {
      file: pkg.module,
      format: 'es',
      sourcemap: true,
      plugins: [terser()],
    },
  ],
  // Indicate here external modules you don't wanna include in your bundle (i.e.: 'lodash')
  external: [],
  watch: {
    include: 'src/**',
  },
  plugins: [
    // Allow json resolution
    json(),
    // Compile TypeScript files
    typescript({ useTsconfigDeclarationDir: true }),
    // Allow bundling cjs modules (unlike webpack, rollup doesn't understand cjs)
    commonjs(),
    // Allow node_modules resolution, so you can use 'external' to control
    // which external modules to include in the bundle
    // https://github.com/rollup/rollup-plugin-node-resolve#usage
    resolve(),

    // Resolve source maps to the original source
    sourceMaps(),
    alias({
      entries: [
        { find: 'my-lib/button', replacement: './dist/button' },
        { find: 'my-lib/input', replacement: './dist/input' },
        { find: 'my-lib/grid', replacement: './dist/grid' },
      ],
      customResolver,
    }),
  ],
};

这是 tsconfig 文件:

{
  "compilerOptions": {
    "target": "es5",
    "module": "ES6",
    "lib": ["ES2017", "ES7", "ES6", "DOM"],
    "declaration": true,
    "declarationDir": "dist",
    "outDir": "dist",
    "sourceMap": true,
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "allowJs": false,
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "baseUrl": "./src",
    "paths": {
      "my-lib/button": ["./src/button"],
      "my-lib/input": ["./src/input"],
      "my-lib/grid": ["./src/grid"]
    }
  },
  "exclude": ["node_modules", "dist", "**/*.test.ts"],
  "include": ["src/**/*.ts"]
}

我不知道如何使用汇总实现与 lodash/xxxmaterial-ui/yyy 相同的结构。

人们建议使用别名或命名导出,但我做不到。

最接近我的问题的是下面的问题:

我想实现同样的事情,但使用 typescriptrollup

我想我漏掉了什么,谢谢。

首先,两者的唯一区别

import { Button } from 'my-lib/dist/button'

import { Button } from 'my-lib/button'

只是多了一层目录。

曾经说过,在 tsconfig.json 文件中包含 "outDir": "dist", 之前,您需要将 dist/ 添加到 import 语句中。

确实,您举的两个库都随根目录中的文件一起分发:lodash directly has js files in the root, while material-ui 在其 tsconfig.json 文件中没有 outDir 选项(这意味着写入输出文件到根目录)。

希望对您有所帮助。

经过多次试验和错误后,我能够通过输入列表、使用 preserveModules and preserveModulesRoot 选项和一个简单的安装后脚本来实现此功能。

这是我的 rollup.config.js

const options = {
  input: [
    'src/index.ts',
    'src/api/index.ts',
    'src/components/index.ts',
    'src/contexts/index.ts',
    'src/hooks/index.ts',
    'src/lib/index.ts',
    'src/types/index.ts',
    'src/utils/index.ts',
    'src/UI/index.ts',
  ],
  output: [
    {
      format: 'cjs',
      dir: 'dist',
      exports: 'auto',
      preserveModules: true,
      preserveModulesRoot: 'src',
      sourcemap: true,
    },
  ],
  plugins: [
    // Preferably set as first plugin.
    peerDepsExternal(),
    typescript({
      tsconfig: './tsconfig.rollup.json',
    }),
    postcss({
      extract: false,
      modules: true,
      use: ['sass'],
    }),
  ],
};

export default options;

scripts/postinstall.sh

#!/usr/bin/env bash
set -e;

# skip postinstall if npm install for development
# rollup.config.js is not included in dist
if [ -f "rollup.config.js" ]; then
  echo "skipping your package's postinstall routine.";
  exit 0;
fi

echo 'Copying files from dist folder into root project folder...'
cp -r dist/* ./ && rm -rf dist
echo 'Postinstall done!'

package.json

"scripts": {
    "postinstall": "./scripts/postinstall.sh",
  },

这将编译所有文件并将其输出到 dist 文件夹。安装后脚本会将 dist 中的所有文件复制到根项目文件夹中。

注意*:当 运行 npm 在本地安装时,应该跳过安装后脚本。这是通过检查 rollup.config.js 是否存在来完成的。

这是可能的,但需要一些额外的步骤。上面提到过,这是Material-UI.

采取的做法

诀窍是发布一个精选的 dist 文件夹,而不是您的存储库的根文件夹。

建筑

首先,让我们明确一点,您的库是使用 CommonJS 还是 ESM 构建的并不重要。这是关于模块分辨率

我们假设项目名为 my-package

现在大多数项目,在我们构建 src/dist/ 之后都会有

my-package
  package.json
  src/
    index.js
  dist/
    index.js

并在 package.json

"main": "dist/index.js"

或 esm

"module": "dist/index.js"

发布

大多数项目只是添加 .npmignore 并发布项目的根目录,因此安装后项目最终在 node_modules 中,如下所示:

node_modules
  my-package/
    package.json
    dist/
      index.js

正在解决

安装后,考虑导入:

import myProject from "my-project";

模块解析器将执行此操作(大大简化,因为 full algorithm 与此处无关):

  • 转到node_modules
  • 找到my-project
  • 加载package.json
  • Return mainmodule
  • 中的文件

这会起作用,因为我们有

node_modules
  my-package/
    package.json
    dist/
      index.js

正在解析子路径

import something from "my-project/something";

分辨率算法将适用于

node_modules
  my-project/
    somthing.js

还有

node_modules
  my-project/
    something/
      index.js

并与

node_modules
  my-project/
    something/
      package.json

在后一种情况下,它将再次查看 mainmodule

但是我们有:

node_modules
  my-package/
    package.json
    dist/
      index.js

绝招

诀窍是,不要使用 dist 文件夹发布项目根目录,而是“frank”dist 文件夹并使用 npm publish dist 发布 dist 文件夹相反。

Frank(如 frank a letter)表示您需要在 dist 文件夹中创建一个 package.json;添加 README.md LICENSE

可以找到关于如何完成此操作的一个相当简短的示例 here

所以,鉴于我们在构建之后有:

node_modules
  my-package/
    package.json
    dist/
      index.js
      something.js

发布后我们得到

node_modules
  my-project/
    package.json
    index.js
    something.js

其中 package.json 是精选的。