Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.4k views
in Technique[技术] by (71.8m points)

typescript - Importing from subfolders for a javascript package

I have a typescript library consists of multiple folders. Each folder contains an index.ts file which exports some business logic. I am trying to bundle this with rollup to achieve this behavior on the call site:

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

This is the directory structure:

enter image description here

I have a main index.ts under src/ which contains:

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

With this style, I can do:

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

But I don't want this. I want to access to each module by their namespaces. If I remove exports from the index.ts file, all I can do is:

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

which is something I didn't see before. Adding dist/ to the import statement means I am accessing the modules via a relative path. I want my-lib/Button.

I am using rollup. I tried to use alias plugin but didn't work. Below is my rollup config:

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,
    }),
  ],
};

And this is the tsconfig file:

{
  "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"]
}

I don't know how to achieve the same structure as lodash/xxx or material-ui/yyy with rollup.

People suggest aliases or named exports but I couldn't make it work.

The closest thing to my problem is below question:

Import from subfolder of npm package

I want to achieve the same thing but with typescript and rollup.

I think I am missing something, thanks.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This is possible, but requires some extra steps. A mentioned above, this is the approach taken by Material-UI.

The trick is to publish a curated dist folder, rather the root folder of your repo.

Building

To begin with, let's just be clear that it doesn't matter whether your library is built using CommonJS or ESM. This is about module resolution.

Let's assume the project is called my-package.

Now most projects, after we have built src/ to dist/ will have

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

and in package.json

"main": "dist/index.js"

or for esm

"module": "dist/index.js"

Publishing

Most projects just add .npmignore and publish the root of the project, so when installed the project ends up in node_modules like so:

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

Resolving

Once installed, consider this import:

import myProject from "my-project";

The module resolver will do this (simplifying greatly, as the full algorithm is irrelevant here):

  • Go to node_modules
  • Find my-project
  • Load package.json
  • Return the file in main or module

Which will work because we have

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

Resolving subpaths

import something from "my-project/something";

The resolution algorithm will work with

node_modules
  my-project/
    somthing.js

also with

node_modules
  my-project/
    something/
      index.js

and with

node_modules
  my-project/
    something/
      package.json

where in the latter case it will again look at main or module.

But we have:

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

The Trick

The trick is, instead of publishing your project root with its dist folder, to "frank" the dist folder and publish the dist folder using npm publish dist instead.

Frank (as in frank a letter) means you need to create a package.json in your dist folder; add README.md LICENSE etc.

A fairly short example of how this is done can be found here.

So, given we had after build:

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

Once published we get

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

Where package.json is the curated one.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...