Skip to content
This repository has been archived by the owner on Aug 11, 2022. It is now read-only.

Allow to specify a parent package.json #8112

Closed
mantoni opened this issue Apr 28, 2015 · 29 comments
Closed

Allow to specify a parent package.json #8112

mantoni opened this issue Apr 28, 2015 · 29 comments

Comments

@mantoni
Copy link
Contributor

mantoni commented Apr 28, 2015

The idea is to borrow Mavens parent.pom concept to allow specifying common dependencies, devDependencies, scripts, configs or any other property.

This would be extremely helpful when using npm as a build tool for dozens of modules following the same approach, e.g. within an organization.

Currently, I find myself repeating the same scripts and devDependency lists in a lot of modules. Every time I like to bump a dependency or tweek a script, this has to be applied in each module separately.

It would be nice to have a versioned parent package.json file that can be refered to using an expreasion like ^1.0.0.

I also use the same author and license values and most packages follow a naming convention to relate the npm module name with the git repository name. If those could be inherited from a parent definition as well, my package.json files would be a lot shorter.

Thoughts?

@smikes
Copy link
Contributor

smikes commented Apr 29, 2015

I think this is an interesting feature request. I can see how that would improve your ability to use npm for maintaining a lot of modules with common behavior.

One concern that I have is that when publishing the module, either the parent file would have to be included in the module tarball, or the parent data would have to be merged into the package.json of the module tarball, in order for the scripts (etc.) to be present.

Recently npm has been moving in the direction of making fewer changes in the package.json file than it used to, so this goes a little against the grain.

I'm sure some of the npm team will weigh in when they have a chance.

@mantoni
Copy link
Contributor Author

mantoni commented Apr 29, 2015

@smikes I thought about potential package.json incompatibilities too. This could be solved by merging the parent.json and the package.json during npm publish. I consider this a module maintainers convenience feature. The resulting package.json does not need to retain the parent package information.

@othiym23 othiym23 changed the title Feature request: Allow to specify a parent package.json Allow to specify a parent package.json Jul 8, 2015
@othiym23
Copy link
Contributor

othiym23 commented Jul 8, 2015

This is a fraught suggestion, because it means that package manifests are no longer self-contained. I get the impulse towards DRY, but I feel like the explicitness of having everything included in a package trumps the savings of typing. Would making it easier to put shared dependencies into a template project created by npm init be enough? As it stands, I'm weakly -1 on this suggestion, because my experiences with this feature in Maven are one of the two main reasons I became disenchanted with it.

@mantoni
Copy link
Contributor Author

mantoni commented Jul 8, 2015

I do see your point. The main thing that I'd actually want to share is npm run scripts. That is because we use npm as a build tool and have conventions in the team how they are layed out. If we decide to change the convention, it means that we have to change all the projects as we go, ending up in an inconsistent world. It's not really bad, but it would be super convenient to have this kind of "config" into a common place and apply semantic versioning to it.

@ghost
Copy link

ghost commented Dec 6, 2015

+1. We are using npm with our private nexus and we have to copy and paste publishConfig in all projects. It's not so hard, but also not DRY

@kevinSuttle
Copy link

Would it be more valuable to specify a stub with default values populated for a custom npm init template? #10832

@kevinSuttle
Copy link

Seems @isaacs already did this: https://github.com/npm/init-package-json

@dsebastien
Copy link

I'm in favor of having an officially supported way to inherit properties/scripts/dependencies (or at least a part of those :p)

Having used Maven very extensively over the years, I see huge added value to being able to create a parent configuration, providing me with dependencies, dependency versions/version ranges, ...

At work, this helps us really a LOT to keep our projects on par with each other and it saves a lot of trouble (dependency hell and reinventing the wheel).

With npm, I actually feel like going back in time to a world where I need to re-define everything in each and every project, which is not a concern until you have to start updating/fixing things, at which point you always forget something and waste a lot of time along the way.

A good example of this issue is the number of yeoman generators that just provide you with a bunch of scripts and a set of gulp tasks. it's nice to get started, but when you have many projects, there's no way to keep generated projects up to date and in line with each other.

In my project (https://github.com/dsebastien/modernWebDevBuild), I've partly worked around this externalizing the gulp tasks and by providing client apps with a way to depend on my project without having to copy files around (i.e., they can upgrade a single dependency and get a fully updated build).

Maybe a first improvement could be to have the ability inherit scripts somehow (not necessarily through a parent package.json file).

For example it could already be nice to add a dependency to your project and have a way to import scripts from that dependency or allow that dependency to inject scripts that you can use on the command line as if they were part of your package.json

Of course there are always workarounds (e.g., provide a CLI as a dependency and have a single script pointing to the CLI in the client project), but I don't think it's the correct answer :)

@kevinSuttle
Copy link

If npm init and init-package-json had better docs, we might be closer to solving this, because as of right now, I couldn't tell you how to provide custom pre-filled values using either.

@sindresorhus
Copy link

👎 to the initial request. You're asking for something that goes against the core of npm. It's built on the idea of self-contained independent packages. Which is a great thing! Your problem could be solved by creating a master package and having other packages consume that one or use tooling to sync package.json contents. I don't think this is something npm should solve.

@sindresorhus
Copy link

Would it be more valuable to specify a stub with default values populated for a custom npm init template?

Could maybe be useful, but it's a slippery slope towards people demanding more and more features of init, which is just meant to be a simple way to get started. For more advanced usage, I would rather recommend using a scaffolder/generator, where there are lots of option both for ready made generators and creating a custom one:

@kevinSuttle
Copy link

@sindresorhus That's what #11137 aimed to solve.

@mantoni
Copy link
Contributor Author

mantoni commented Feb 25, 2016

@sindresorhus I don't understand why this goes against the core of npm. If the parent package is treated like any other dependency with semantic versioning, it's pulling in scripts like you're pulling in any other tool today.

I mean, my primary interest are npm scripts here. If those could be inherited from a common package, it would be enough to pull the parent package scripts in on the top level package, like devDependencies.

@othiym23
Copy link
Contributor

othiym23 commented Mar 4, 2016

I mean, my primary interest are npm scripts here.

Speaking strictly to this point, this goes to the heart of the design of package scripts. That design has happened after the fact, at least a little, but right now it helpfully balances simplicity and flexibility. I believe that it’s entirely appropriate to preserve that simplicity by requiring at least a little duplication / boilerplate here. Also, I’ve suffered through the consequences of multiple levels of hierarchically-dependent configuration files for build tools, and don’t want to impose the costs that come with that on our user bases.

The team thinks @sindresorhus is right here; this is a problem better solved by external tooling, either by abstracting common, shared tasks into standalone tools that can be simply invoked in many projects, or using a more sophisticated task runner like gulp to create template workflows that can be shared between projects. As such, I’m going to close this issue. I do appreciate the time that everybody’s put into discussing this, and the team is interested in continuing to make package scripts more powerful, but as much as possible, we’re going to try to do so without compromising their simplicity, which we believe to be a large part of their power. Thanks for your time!

@othiym23 othiym23 closed this as completed Mar 4, 2016
@ghost
Copy link

ghost commented Mar 7, 2016

So, codegen. Ok.

@kof
Copy link

kof commented Sep 10, 2016

So what current external solutions do we have?

@brettstack
Copy link

It would be useful if you had a recommendation on an external tool that fills this need. My primary use-case for this is inherited config and scripts.

@mbrevda
Copy link

mbrevda commented Feb 2, 2017

I wonder if a compromise here might be to a "post parse" hook?

When setting a pre script (i.e. pre everything), an external script can return the contents of package.json modified/augmented. This would leave the onus on the script implementor to address all the sticky issues such as inheritance and merging hierarchical objects, whilst keeping the npm side of things relatively clean.

Is that something that might fit more with npm?

@brianmhunt
Copy link

There's an opportunity, especially with the growing popularity of monorepos, to make lives quite a lot simpler with this suggestion.

One example would be sharing of the scripts property of a parent package.json across all of a monorepo's children. Without being able to specify the scripts of a parent, one must either painstakingly reproduce and maintain the 'scripts' properties in every package.json, or use something other than npm scripts (which may otherwise be needless).

While it's only one example of the benefit here, it has and continues to influence my choices about whether to or not to use npm/package.json – even though it otherwise feels like the correct choice.

@neal-eiger
Copy link

I agree with the original post and request, that package.json like maven should be able to specify a parent package it extends. It wouldn't be hard to implement this feature, those who don't want it don't need to use it, but for those of us who want to avoid maintaining similar configurations for say, the web and mobile version of a site, we would have this ability.

@reda-alaoui
Copy link

reda-alaoui commented Jun 11, 2017

I agree too with the original request.
We should not have to duplicate every single attribute across all organization projects.
Yeoman is not a solution either since it doesn't allow to upgrade existing projects (no automatic merge included) efficiently.

Meanwhile I do not see any workaround allowing to merge external package.json without breaking at least one part of the development workflow :/

@bschaepper
Copy link

This would be really helpful and also pretty simple. Just doing a deep merge when reading the package.json file and before publish is enough.

At npm@3 this was not really an issue, as the node_modules folder contained transitive dependencies flattened. But now this behavior is changed again, and either there is an official or some hackish standalone solution. For the time being we're stuck on npm@3, or yarn for that matter.

@DeividasK
Copy link

For anyone coming to this discussion at a later date - https://github.com/FormidableLabs/builder might be the external tool that could potentially solve the OPs problems.

@nicodewet
Copy link

Agree with the original request.

Loved multi module Maven builds with a parent pom - just made sense. Otherwise just an organisational parent pom. I need this feature right now, but this thread has me convinced I can't do a multi-module setup with npm, so here comes some duplication .... in the same repo ... makes me want to bang my head against a wall, but only little bangs, not end of the world material.

brianmhunt added a commit to knockout/tko that referenced this issue Dec 18, 2017
@reda-alaoui
Copy link

reda-alaoui commented Jan 27, 2018

I released https://github.com/Cosium/dry-dry.
Its only purpose is to add package.json inheritance capability.

The documentation is still in early stage, but it works.

@estyh
Copy link

estyh commented Mar 19, 2018

I'm sad this issue was closed... just spent a good amount of time researching how to do this (inherit parent scripts) and looks like other need it too!

@zmoshansky
Copy link

Currently we are proceeding with @reda-alaoui solution and will slowly work towards a PR with yarn support and address compatibility issues with other external tooling.

To the JS community, managing multiple applications that share common code is painful without some notion of dependency-list inheritance. I really hope you re-consider this feature in light of all the advancements over the past couple years and evolving use cases. As demonstrated by dry-dry there's not a tremendous amount of code to make this happen and seems like a very valuable and welcome addition to the package.json spec.

@othiym23

This is a fraught suggestion, because it means that package manifests are no longer self-contained.

While I can appreciate this for library style projects, this approach hasn't scaled well to managing multiple production applications. Of notable example, the Typescript team has opted to include an "extends" feature in their tsconfig.json to help solve these challenges.

I get the impulse towards DRY, but I feel like the explicitness of having everything included in a package trumps the savings of typing.

Again, scaling this up to 5+ applications with 50+ common dependencies and this starts to become inconvenient and error prone. In addition, having versioned common dependencies allows for QA to have more confidence that a feature change in one repo will not need to be thoroughly vetted for each individual application that relies on those common libs and features (To protect against the aforementioned error prone process of manually replicating common deps across repos).

Would making it easier to put shared dependencies into a template project created by npm init be enough?

No, the dependencies will be updated over time and need to propogate those changes to projects created from those templates.

@sindresorhus

👎 to the initial request. You're asking for something that goes against the core of npm. It's built on the idea of self-contained independent packages. Which is a great thing! Your problem could be solved by creating a master package and having other packages consume that one or use tooling to sync package.json contents. I don't think this is something npm should solve.

First, I'd respectfully disagree that this FR doesn't work towards the goal of self-contained independent packages; I'd argue that the amount of extra work/tooling to solve this common issue outside of package.json pretty much eliminates any notion of building a self contained package. From the perspective of the dependency graph, I fail to see how adding dependencies from an external list (this FR) or package.json is any different as it applies to npm's goals [Managing dependencies]. I want this feature so I can clone a project, invoke the package manager, and go.

We created a master package that others consume and it still falls short (TS already gets quite unhappy when comparing types that have been sourced from different copies of the "same" package). This only gets harder when the complexities start adding up with TS, Babel, Webpack, and other build steps. Regardless, we still can't transitively use sub-dependencies from a dependency so this doesn't solve the core problem.

A challenge with using external tooling (Like dry-dry) is that it creates incompatibilities with other external tooling. For example, Cordova frequently interacts with the package.json and since dry-dry won't be invoked by that tool, or any scripts it calls upon, there will be problems. Furthermore, I can't even version dry-dry as part of my package.json without some way of bootstrapping the process; This results in project devDependencies that don't even live in my package.json despite being JS libraries.

My personal feeling is that dependency management (including common shared dependencies) should be far closer to core npm principles than running scripts within package.json.

@bschaepper
Copy link

@zmoshansky is absolutely right, repeating the same dependencies simply does not scale in such a scenario. In addition to beeing tedious, it's also ver error prone. Think keeping 50, what should be transitive, dependencies in sync in a few dozen projects. No fun. This should really be solved by the dependency management tool itself.

@Nefcanto
Copy link

When Node and then NPM came out, I remember that many of my friends migrated towards it, mocking me as a .NET developer not to migrate. Now after many years, I have a successful company and they're stuck in managing 5 apps.

The thing is, for a huge amount of applications out there, reduction of costs is the number one priority in industry. It matters if you can create AND MAINTAIN an app by $1000 over 6 months, or by $7000 in the same period. In the context of a real business, multiply that to 50 applications per year, and you realize that npm without inheritance IS A HELL.

Yep, .NET is slower compared to many platforms. .NET is not that fashionable and classy. A .NET developer might not be able to argue with an old friend in another company who boasts about Node and NPM, but hell .NET is industrial.

We managed to create a lightweight framework for our company in .NET technology stack, that is SQL Server, EF Core, VS 2017, MSBuild and Windows, and we successfully managed to create and maintain more than 100 apps per year, reducing costs up to 80%. Now that's a value. Because customers are happy (huge advantage in time-to-market and support thanks to DRY, lower costs thanks to engineering). Developers are happy, because they get paid well because we don't have to spend our money on things that should work out of the box. And we're happy too. SEE? That's the value a library/framework/tool should bring to industry. Not boasting about being explicit and self-contained. There is nothing wrong with inheritance, and it does not stand in front of being explicit and self-contained. It can even be an option.

As a developer who became entrepreneur and a businessman, I vote down npm for not having such a simple, yet practical solution, in spite of all the shouts from community. Shame on you guys. Go learn from MSBuild XML configuration and Nuget. I'm sure you'll learn a lot. Now I can upgrade my EF Core in more than 500 applications across 10 companies without even one developer noticing it, without even breaking a single line of code. If we were using NPM, we had to spend a week for upgrading to a bug-fix, let alone a major version.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests