I am working in a monorepo, using bolt to manage package installation. I also use preconstruct
in order to build exports which are compatible with both module and common js.
With preconstruct
I am using also babel
. The monorepo folder structure looks a little something like this:
root
├─apps
│ ├─someApp1
│ │ └─index.ts
│ └─someApp2
│ └─index.ts
└─packages
├─ui
│ ├─src
│ │ ├─components
│ │ ├─pages
│ │ │ └─index.tsx
│ │ └─index.ts
│ ├─package.json
│ └─tsconfig.json
└─utils
├─src
│ └─index.ts
├─package.json
└─tsconfig.json
I am building a package with several utility functions built around the fs
module in node.js.
In another package in the same monorepo I am building React components and using Next to build the app.
If I use fs
in the index.tsx
file of a somePage
in the Next folder within the component library, everything is fine.
If I import the modules I am building it gives me an error: can't resolve fs..
I think it has to do with Next trying to pull the dependency from the package while it shall be imported from the client node_modules
.
probably there is some configuration settings or something to be done.
I will try to make a minimal reproducible example:
The file package.json
in the root folder looks like this:
/package.json
// package
{
"name": "somename",
"version": "0.0.1",
"private": true,
"bolt": {
"workspaces": [
"apps/*",
"packages/*"
]
},
"scripts": {
"postinstall": "manypkg check",
"clean": "bolt ws clean",
"build": "sh bin/build.working.sh",
"typecheck": "bolt ws typecheck"
},
}...
then I have 2 packages in the packages folder : /packages/utils
and /packages/ui
. These are packages meant to be consumed in front end applications (browser and CLI) which sit in the /apps
workspaces folder.
The utils package is meant to be a library for commonly used functions (arrays, string, file-treatment).
The ui
package is meant to be a library of React
components and, for ease of testing, I am running a Next
application within that project. This applications is not exported with the library files of the package, as it can be noted in the tsconfig
file.
they both inherit from a common tsconfig
file which sits in the root
of the package:
/tsconfig.base.json
{
"compilerOptions": {
"allowJs": false,
"allowSyntheticDefaultImports": true,
"downlevelIteration": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"jsx": "react-jsx",
"lib": ["DOM", "DOM.Iterable", "ES2019"],
"module": "CommonJS",
"moduleResolution": "node",
"noUncheckedIndexedAccess": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"preserveConstEnums": true,
"removeComments": false,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"target": "ES2017"
},
"exclude": ["node_modules"]
}
their respective package.json
s and tsconfig
files look like this:
/packages/utils/package.json
{
"name": "@somename/utils",
"version": "0.0.1",
"private": true,
"description": "Somename utils",
"source": "src/index.ts",
"main": "dist/somename-utils.cjs.js",
"module": "dist/somename-utils.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"preconstruct": {
"entrypoint": [
"src/index.ts"
]
},
"scripts": {
"clean": "rm -rf dist",
"build": "yarn preconstruct build && run-p build:*",
"build:types": "tsc --declaration --emitDeclarationOnly --outDir dist",
"typecheck": "tsc --noEmit"
},
} ....
/packages/utils/tsconfig.json
{
"extends": "../../tsconfig.base.json",
"include": ["src"],
"exclude": ["dist", "node_modules"]
}
/packags/ui/package.json
{
"name": "@somename/ui",
"version": "0.0.1",
"private": true,
"source": "src/index.ts",
"main": "dist/somename-ui.cjs.js",
"module": "dist/somename-ui.esm.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"clean": "rm -rf dist",
"build": "yarn preconstruct build && run-p build:*",
"build:types": "tsc --declaration --emitDeclarationOnly --outDir dist",
"typecheck": "tsc --noEmit",
"next_dev": "next dev",
"next_build": "next build",
"next_prod": "next start"
},
} ....
/packages/ui/tsconfig.json
{
"extends": "../../tsconfig.base.json",
"include": ["src"],
"exclude": ["dist", "src/pages", "src/somefolder"],
"compilerOptions": {
"incremental": true,
"jsx": "preserve",
"isolatedModules": true,
"noEmit": true
}
}
note that in this ts config I exclude the src/pages
folder as this package is meant to be exporting only the components, not the application which is built within it which is meant for testing purposes.
Then I have a function which sits in the utils
package which looks something like this.
/packages/utils/index.ts
import fs from "fs"
// node/readDirSync.ts
export const readDirSync(...path:string[]){
return fs.readdirsync(...path)
}
that I wish to use in the ui
package, like this:
/packages/ui/pages/index.tsx
import { readDirSync } from "@somename/utils"; // my package
...
// Next getStatic
export async function getStaticProps() {
const path = process.cwd();
// retrieves a list of .md files
console.log(readDirSync(path));
return { props: { result: "should go here" } };
}
...
ps. I wrote this snippets here, I didn't actually test it myself, I hope it is enough to clearify the issue I am facing. If needed I can do a repo which reproduces the issue.
So, it seems clear to me that has something to do with the transpiler, or the Next compiler which needs to be told to grab the fs
module from the node_modules
folder within the ui
package.
Anyone knows what to do? =)