I want to let users import from the subfolders of my TypeScript NPM package. For example, if the directory structure of the TypeScript code is as follows,
- lib
- src
- server
- react
users of my package should be able to import from subfolders as package-name/react
, package-name/server
etc.
My tsconfig.json is as follows.
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"declaration": true,
"outDir": "./lib",
"strict": true,
"jsx": "react",
"esModuleInterop": true
},
"include": ["src"],
"exclude": ["node_modules", "**/__tests__/*"]
}
I could do this when "outDir" was set to the project root, but then the file structure is messy. Can someone point me a way out to do this (importing from submodules) while preserving "outDir": "./lib"
? Helpful answers are highly appreciated. Thanks in advance.
You can use https://www.npmjs.com/package/npm-dependents to find dependents that are not installed. In the meantime, you may want to just use the "Dependents" tab on the individual npm project pages.
That is possible with an entry in the package.json file called exports
:
"exports": {
"./server": "./lib/server",
"./react": "./lib/react"
},
You can read more about it here: https://nodejs.org/api/packages.html#packages_package_entry_points
But be careful:
Warning: Introducing the "exports" field prevents consumers of a package from using any entry points that are not defined, including the package.json (e.g. require('your-package/package.json'). This will likely be a breaking change.
EDIT: It seems like TypeScript ignores the field, maybe it helps when you add types like this:
// server.d.ts
export * from "./lib/server";
// react.d.ts
export * from "./lib/react";
What I did
I copied your project setup and changed something:
src/
server.ts
react.ts
lib/
(generated output)
server.d.ts
server.js
react.d.ts
react.js
package.json
tsconfig.json
react.d.ts
server.d.ts
Add this to package.json:
"exports": {
"./server": "./lib/server",
"./react": "./lib/react"
},
react.d.ts
export * from "./lib/react";
server.d.ts
export * from "./lib/server";
That worked for me. Now I could import "mypackage/server" for example somewhere else. Maybe you didn't split up the definition files to multiple files, but try to apply these changes and see if it works.
You can copy your package.json file into your dist/lib folder as part of the publish process to avoid a messy repository structure. See here for an example. As a downside, yarn link might be more complicated and this approach might not work for yarn workspaces.
Alternatively, you can use the exports
key in package.json once TypeScript implements support for it.
Add below exports
entry in package.json
"exports": {
"./": "./lib/"
},
After the entry you can import from within lib subfolder or file within lib folder but for subfolder within lib folder there need to be index.js
file which would be imported.
Structure after typescript compilation that would work:
- lib
- src
- server.js
- react.js
- lib
- src
- server
- index.js
- react
- index.js
Note: slash(/)
at the end of the entry are important for subpath export.
Example Steps:
mkdir -p mod1/src/api mod2/src
cd mod1
npm init -y
mod1/tsconfig.json
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"declaration": true,
"outDir": "./lib",
"strict": true,
"jsx": "react",
"esModuleInterop": true
},
"include": ["src"],
"exclude": ["node_modules", "**/__tests__/*"]
}
mod1/package.json
{
"name": "mod1",
"version": "1.0.0",
"description": "",
"exports": {
"./": "./lib/"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "MIT"
}
mod1/src/api/index.ts
export const api = function() : void {
console.log('api');
}
mod1/src/react.ts
export const react = function() : void {
console.log('react');
}
mod1/src/server.ts
export const server = function() : void {
console.log('server');
}
change to mod2
directory
cd ../mod2
npm init -y
npm install ../mod1
mod2/src/index.js
const lib = require('mod1/server');
const { react } = require('mod1/react');
const { api } = require('mod1/api');
lib.server();
react();
api();
Note: I used node
version 14.4.0 and tsc
version 4.2.4
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With