Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Import from subfolder of npm package

I've been working on creating a small library of React components for use in several other projects. I am publishing the package internally (using a private GitHub repository) and then including in another project. However, when I go to import from a subdirectory of the package I am not able to do so as the paths don't match.

The projects using the package all utilize webpack to bundle/transpile code as I am trying to avoid doing any building in the component library if possible.

Directory Structure

- package.json - src/   - index.js   - Button/     - index.js     - Button.jsx     - ButtonGroup.jsx   - Header/     - index.js     - Header.jsx (default export) 

package.json

... "main": "./src/index.js", "scripts": "", ... 

src/Button/index.js

import Button from './Button'; import ButtonGroup from './ButtonGroup';  export default Button;  export { Button, ButtonGroup}; 

src/index.js

Is this file actually necessary if only importing from subdirectories?

import Button from './Button'; import ButtonGroup from './Button/ButtonGroup'; import Header from './Header';  export { Button, ButtonGroup, Header }; 

Other Project

// This project is responsible for building/transpiling after importing import { Button, ButtonGroup } from 'components-library/Button'; 

Example

Material-UI is a library of React components that is used by requiring in the following fashion: import { RadioButtonGroup } from 'material-ui/RadioButton. I've tried to figure out how this works for them but to no avail yet.

Similar Questions

  • How would I import a module within an npm package subfolder with webpack?
    • This is very nearly the correct approach I require, except that the import path used there involved the src/ directory, which I am trying to avoid (should be component-library/item, not component-library/src/item (which does work currently though))
  • Publishing Flat NPM Packages
    • This is exactly what I want except that I was hoping to not have a "build" phase in the package (rely on importing locations to build/transpile)

Questions

  1. Can I skip the src/ directory somehow in the import path?
  2. Can I skip any type of build phase in the package (so developers don't have to build before committing)?
  3. How does a package similar to material-ui handle this?
like image 398
Kendall Avatar asked Jun 03 '17 14:06

Kendall


People also ask

What is a package in Node Js?

What is a Package? A package in Node. js contains all the files you need for a module. Modules are JavaScript libraries you can include in your project.


2 Answers

The answer may depend on how you installed your components library. If you did it via either npm install <git-host>:<git-user>/<repo-name> or npm install <git repo url>,

  1. You should be able to import {Button} from 'component-library/Button' as is, according to your first linked question. Similar to Node's require() resolution, Webpack should resolve subdirectories within component-library relative to component-library's entry point. You can find the docs on customizing the resolution behavior via the webpack.config.resolve property. material-ui seems to rely on resolving subdirectory imports from the module entry directory.

  2. To distribute an ES module library, there's no need for building before distribution. However, projects such as create-react-app may need a pre-transpiled version.

Alternately, you can write import {Button} from 'components-library'. Webpack will trace the dependencies back through each index without a fuss.

like image 37
Steven Kalt Avatar answered Sep 17 '22 14:09

Steven Kalt


Can I skip the src/ directory somehow in the import path?

Yes. Using the package.json "exports" field, which should be supported by Webpack in a near future (see this issue), but has already been supported by Node since Node 12 LTS following the Bare Module Specifier Resolution proposal:

package.json

... "main": "./src/index.js", "type": "module", ... "exports": {   "./Button": "./src/Button/index.js",   "./Header": "./src/Header/index.js" }, ... 

Now, the following code:

// This project is responsible for building/transpiling after importing import { Button, ButtonGroup } from 'components-library/Button'; 

should be translated to:

import { Button, ButtonGroup } from 'components-library/src/Button/index.js'; 

which should correctly import the requested modules.

Caveat

Now, it would certainly be tempting to try a simpler version like:

... "exports": {   "./Button": "./src/Button/",   "./Header": "./src/Header/" }, ... 

so as the usual import statement

import { ... } from 'components-library/Button'; 

gets translated to

import { ... } from 'components-library/src/Button'; 

This looks nice, but it will not work in this case, because your submodules don't have each their own package.json file but rely on their index.js file to be found.

/!\ Unlike in CommonJS, there is no automatic searching for index.js or index.mjs or for file extensions.


src/index.js - Is this file actually necessary if only importing from subdirectories?

I don't think so, but you can keep it if you want.


Can I skip any type of build phase in the package?

Using the "exports" field does not require you to transpile your code.

like image 98
Luc125 Avatar answered Sep 17 '22 14:09

Luc125