This was written based off of https://docs.npmjs.com/cli/v7/using-npm/workspaces and using node v14.17.3 and npm 7.19.1.
I'm gonna use an example that's structured in a familiar way:
- Create React App in /src
- Backend server in /server
- Shared code in /myproj-lib
Except using npm workspaces, we can make the "shared" code (which we've so far only shared between various backend programs) accessible to the frontend too!
myproj
+-- package.json
+-- myproj-lib (shared)
| +-- package.json
| `-- index.js
+-- server (backend)
| `-- index.js
`-- src (frontend)
+-- package.json
`-- App.js
The main package.json is the same as our usual with only one difference - the workspaces
entry that contains the name of the directory that will hold our shared code.
{
"name": "myproj",
"type": "module",
"workspaces": ["myproj-lib"],
"dependencies": {
"depsForBackend": "here",
"depsForSharedLib": "here",
"frontendCanUseTheseLibsToo": "sure I guess"
},
"devDependencies": {
"frontendOnlyDependencies": "here"
}
}
This should be familiar. It's required in order to let us write the backend in module syntax while still compiling the frontend with CRA's regular build command.
{
"type": "commonjs"
}
This file plus the workspaces
entry in the top-level package.json are the magic sauce. This file turns this directory myproj-lib into a "standalone" npm module. The private
flag ensures that this module isn't publishable or anything; it's purely for use within the scope of this one project.
{
"name": "myproj-lib",
"private": true,
"type": "module",
"main": "index.js"
}
And after an npm install
that's all the config necessary! Now you can write shared code in /myproj-lib. Since index.js
is the "main" file, you'll have to export anything you want to use out of there. Obviously you could write code right in index.js, but if you put it in other files in that directory, it shouldn't be that bad to use re-exports to get it exported out of index.js.
The last thing to know: when you want to import the shared code, do NOT import it as a directory, like import * from '../myproj-lib/index.js'
. Instead, import it like a module, like:
import * as lib from "myproj-lib";
And that will work in both the frontend and backend!