Importing from subfolders for a javascript package

拜拜、爱过 提交于 2020-12-13 03:27:57

问题


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:

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.


回答1:


First of all, the only difference between

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

and

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

is just one more directory level.

Once said that, until you have "outDir": "dist", in your tsconfig.json file you need to add dist/ to your import statements.

Indeed, both the libraries you taken as example are distributed with files in the root directory: lodash directly has js files in the root, while material-ui has not outDir option in its tsconfig.json file (which means to write output files to root directory).

Hope this helps.




回答2:


After numerous trials and errors, I was able to get this working by passing in a list of inputs, using the preserveModules and preserveModulesRoot options, and a simple postinstall script.

Here's my 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",
  },

This will compile and output all files to dist folder. The postinstall script will copy all files from dist into the root project folder.

Note*: The postinstall script should be skipped when running npm install locally. This is done by checking if rollup.config.js exists or not.



来源:https://stackoverflow.com/questions/62518396/importing-from-subfolders-for-a-javascript-package

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!