2

I've been working on a website which is a collection of single-page applications. I have a monorepo consisting of my applications in separate directories, and each app has it's own package.json. In addition to this, each application contains one or more git submodules, where I place my core libraries (ex. one for the "common" lib, one for SVG, etc.). I'm overall happy with this setup. It works well with tooling, since the submodule is directly within the app directory, and makes it easy to version the code.

EDIT: An example directory structure, where "common" is the git submodule:

frontend/app1/common
frontend/app2/common

That said, the biggest flaw has been dealing with dependencies, as sometimes there are dependencies I would like to have across all applications. Since every app has its own package.json, this means that I have to manually install that dependency across all my apps, should I ever use that dependency in my common lib.

What I'm looking for is a way to split a package.json, such that I could (for example), point the app's package.json at the common lib's (hypothetical) package.json, and inherit its dependencies. I'm aware that this is not possible with package.json, but I can't help but feel this is common enough an alternative might exist.

I know Yarn workspaces provides the ability to create local packages, but this wreaks havoc with the project tooling and makes it more difficult to make quick code changes.

Are there any good workarounds that don't involve building some hacky templating system? My stack is:

  • Vite
  • Svelte
  • Yarn (with workspaces)

1 Answer 1

1

Let's say you have these folders:

- app1
- app2
- common

And in common folder you have package.json with node-fetch package, for example.

Also, in common you have index.js with something like this:

import fetch from "node-fetch";

export const getPage = async (page) => await fetch(page);

Then in app1 you have app.js with:

import { getPage } from "../common"

const data = await getPage("http://x.com");

Now all you have to do is to run npm install inside of your common folder.

It can also be a git submodule, doesn't matter. You don't need to add node-fetch into your app1 to get this working.

You might also face another issue: too many package.jsons. For which I wrote a script based on listr that finds all of them recursively and runs npm install or npm test for all of them in parallel. It's not published yet, but I can share some snippets if you're interested.

Sign up to request clarification or add additional context in comments.

5 Comments

Ah I should specify, the git submodule is WITHIN the app (ex. app1/common and app2/common). This has a couple advantages: 1) The tooling sees it as a regular subdirectory, so nothing breaks. 2) You can be on a different commit of the common lib in different apps, which makes updates safer in a single app (doesn't affect other apps).
Mm, can you add package.json into the common and run npm install there? You'll have to do it twice tho in your example.
Most likely, though I was really hoping to avoid this. It wouldn't play nice with my automated Heroku deployment, might cause weirdness with PNP and workspaces, and I would probably prefer to write a tool to just insert the data into JSON.
Also, I don't understand what kind of havoc would there be if you make common a package. And it'll probably be the best thing to do... Otherwise, you might want to check out Deno - you can import specific dependencies by URL, so you don't need pacakge.json, instead the code in common itself will describe what it needs, like import "https://deno.land/x/[email protected]/dist/lodash.js"; etc.
Thank you, I don't recall the specifics but I gave it a solid try, and ran into all sorts of issues with svelte-check not working right, the IDE being incapable of picking up TypeScript types, and more I forgot. Eventually I tried the submodule approach and honestly do like it, since during development it's right in the app directory, so it's quick to make changes without having to constantly bump version numbers. I'll check out Deno.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.