Hacker News new | ask | show | jobs
by wildpeaks 2836 days ago
Thing is, node_modules isn't just thirdparty modules.

It's just what the Node path resolution standard uses, which is also how Local Modules (the "/src/node_modules" structure) allows you to import other files with clean paths, without having to add a config in every tool of the toolchain, post-install symlinks, or any other non-crossplatform tricks. It just works because it's literally what Node uses to resolve paths, and all build tools are based on Node, so when you stick to the standard resolution, you can add new tools to the toolchain without needing a bunch of configs for them to find your files. For example, it's now also the default resolution in Typescript as well.

The only time /src/node_modules doesn't work is when tool goes out of its way to break it, and wrongly assumes that node_modules can only ever be used for external thirdparty code (e.g. Jest).

So best of luck to make Node + NPM + Yarn to agree on a new path resolution syntax, but I hope we won't end up with another tool-specific resolution that only works in Yarn.

1 comments

This doesn't break that, it specifically says it will fall back to Node's module resolution algorithm when the module you're looking isn't in the static resolutions table. That means you can keep using that technique as you have bee.

As an aside, you can also use lerna[1], yarn workspaces[2] or pnpm workspaces[3] to achieve the same effect, depending on your package manager of choice. You might get additional boosts to code organization/productivity, it's explained in the links.

[1]: https://lernajs.io [2]: https://yarnpkg.com/lang/en/docs/workspaces/ [3]: https://pnpm.js.org/docs/en/workspace.html

> when the module you're looking isn't in the static resolutions table

The fallback will kick in when the package that makes the request isn't in the static resolution table. Since those packages aren't part of the dependency tree we assume their dependencies have been installed independently, hence the fallback.

That said, I think the use case described by the parent post is neatly solved by the `link:` protocol, which basically 'aliases' a module to a specific name.

I think that approach is really good. If a package doesn't fit into the static resolution table it could cause a lot of problems to point its dependencies in that direction, especially since node has no issue allowing you to override local modules and reuse the same names when you're deeper.

On that note though, it seems at first glance like there'd be no way for Yarn to tell if a require is overriding another, since (maybe I'm reading the paper wrong) the require speed improvements come from skipping the native module resolution.

Let's say I have a package and my source is set up with the following files:

----

/-->package.json

/-->src--->node_modules--->leftpad.js

/-->src--->main.js

----

And let's say I then install leftpad through the proposed system.

If I call ``require('leftpad');`` from main.js, what will get returned? Will Yarn know to use the local version of leftpad instead of the installed one?

If I'm understanding you correctly, this would break, but I'd use the Yarn-specific "link" system to fix it?

Since we're doing an aside, what advantages do those "monorepo" things have over git submodules?
I don't maintain any monorepos, I've always used Git sub-modules; not just for Node.js, but for all sorts of stuff.

However, I'm increasingly finding that sub-modules are a bit of a pain. If I patch a sub-module, I have to move into every single project that depends on the sub-module and pull the latest version. Additionally, if the sub-module is large it's a real waste of storage on my computer.

That said, monorepos have annoyances of their own e.g. many modern package managers will happily check-out dependencies directly from Git. However, that's simply not going to work unless there's some standardisation in monorepo structure that the package manager is able to interpret.

Here's a good article. https://danluu.com/monorepo/ It cites simplified organization, simplified dependencies, superior tooling, and easier cross-project changes.

https://blog.ffwll.ch/2017/08/github-why-cant-host-the-kerne... is another good one. You can build issue/PR tools treating a monotree as containing multiple repositories; that's how Google and Facebook do their work (including checked-in OWNERS/MAINTAINERS files).

Monorepos are excellent if you have a group of related projects, especially if they depend on each other. Instead of opening a series of PRs for each project in a specific dependent order, you can open a single PR and move everything forward in lock-step, ensuring that every commit / tag has all projects in the monorepo working together.

The biggest downsides are really around tooling: we've had tons of issues with our continuous integration environment (Travis CI) and build times trying to build only specific sub-projects using Lerna. The Github Pull Reviews and Issues pages can get pretty messy too, though we have a process to automatically add Github tags based on changes via Lerna.

I suspect this is why bigger companies seem to be more successful with monorepos than smaller ones, because they have the resources to invest in building their own tooling.

Excellent question! I use both regularly so are qualified to answer:

- monorepo. Versioning over entire repo. node modules are used for granularity, separation of concerns, etc.

- git submodules. Versioning over individual node modules. node modules are used for sharing code.

Nothing stopping you from using both.

Also, silly semi-technical point: I have never, ever, had a bad experience using git submodules, but many others have. I like submodules, but often work in teams where otherwise technically good people really hate them due to bad prior experiences.

I've been using Yarn workspaces for a year now and love it.

I use the 'monorepo' pattern.

- /packages is my own modules - it's entirely full of interesting project-relevant things.

- /node_modules is third party modules installed by yarn, and symlinks added to your own modules by yarn. I leave it collapsed.

It works well.