polymer: Yarn Flat Mode Attribute in Package.json breaks projects

I fully understand the desire for flat dependencies and I think Polymer can be opinionated about requiring flat mode for apps. However, when a dependency has the flat: true in it’s package.json, it forces any project which uses it into flat mode. This breaks all my existing projects.

my-app
 |- dep-1
 |- dep-2 // flat: true here forces the entire project into flat mode
 |- dep-3

This parameter is already ignored by npm so effectively what this parameter does is prevent developers from using yarn unless they use it exactly how the Polymer Project intends. And since flat mode and separate client/server dep folders is extremely non-standard, the end result is this may very well fracture the development space and be every bit as divisive as bower was.

With flat: true specified in Polymer core or in any other dependency, my choices are:

1 . Abandon yarn and go back to npm so that my projects can bypass the flat mode requirement. 2. Republish every dependency I use to an internal npm repository. This is a maintenance nightmare.

As I understand it the problems flat is attempting to solve are:

  • Attempting to register a custom-element which is always defined throws an exception. Define calls can be guarded by an if to work around this.
  • Being able to properly calculate paths to other components which nesting breaks. This is solved by the node module resolution algorithm but would require a build step.

I recommend documenting the flat mode requirement and having the Polymer provided build tooling check for it, but removing the flat: true property from any npm-published library intended to be used as a dependency.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 7
  • Comments: 16 (9 by maintainers)

Most upvoted comments

hi~

we’ve got a thread going over at https://github.com/package-community/discussions/issues/2 about this issue.

For those who don’t want to read through the Dostoyevsky book that thread’s become, here’s the tl;dr of what my team’s planning on implementing:

  1. a new type of dependency, called an asset dependency, which will install into an assets/ directory, distinct from node_modules
  2. assets are guaranteed maximally flat, and existing separate means node tooling isn’t broken by spurious forced flattening that it was never developed to support in the first place
  3. we’re going to port Bundler’s tree-flattening algorithm, which is pretty good at finding flat trees without requiring manual resolution. This is probably going to be much better than bower’s algorithm (and, tbh, probably Yarn’s) at finding flat trees without user involvement
  4. when all else fails, we’re going to have a bower-style (but not bower-identical) resolutions definition in package.json so you can force a package into a version
  5. assets will be additionally written into package-lock.json, so you’ll have reproducible builds
  6. all of this will be built in to npm itself, with the same stuff that’s shipped out by default with node.js (once it lands)

tl;dr:

$ npm i --save-asset @polymer/example
$ echo '<script type="module" src="/assets/@polymer/example/example.js"></script><example></example>' \
  > index.html
$ npx serve
...(open http://localhost:5000/index.html and play with <example>)

Note: I’ve popped into the polymer slack if anyone wants more back-and-forth questions, and we’ve also got conversations going on about this in the Discord for https://package.community. I probably won’t say much more in this thread, specifically, but I figured this’d be useful. ❤️

But aren’t peer dependencies essentially what Polymer 3 elements are trying to accomplish in the npm ecosystem? Elements don’t import '@polymer/paper-button', they import '../@polymer/paper-button'

To me that’s the element asserting that it’s requesting a dependency that it does not have control of. It’s expecting a sibling dependency and not a child dependency right?

For all front-end polymer elements, yes their dependencies should be peer dependencies since the convention is to require by path up to a sibling folder. However, this doesn’t mean that all dependencies in the node_modules tree have to be peer. We can still get the benefit of nested dependency trees for other modules that are not importing each other by path.

Say for example, we have build tool that uses moment for dates, and our element is also using moment, but a different version. The packages would be

build-tool package.json

{
  "name": "build-tool",
  "dependencies": {
    "moment": "^1.0.0"
  }
}

build-tool.js

const moment = require('moment'); // Version 1

my-element package.json

{
  "name": "my-element",
  "peerDependencies": {
    "@polymer/polymer": "^3.0.0",
    "moment": "^2.0.0"
  }
}

my-element.js

import '../@polymer/polymer.html';
import '../moment/moment.min.js'; // Version 2

The node_modules tree would be

├── @polymer/poylmer@3.0.0
├── moment@2.0.0
├── my-element@1.0.0
├── build-tool@1.0.0
  └── moment@1.0.0

Using yarn with --flat is essentially forcing the entire node_modules tree to be “peer dependencies” instead of nested dependencies, so what’s the real difference?

@FredKSchott could you give an update about the status of yarn --flat? I found https://github.com/Polymer/polymer-modulizer/issues/254 but not sure what the latest status is.

I’m all for discussions on this type of front, but in the short term the flat attribute still needs removed from any package designed to be a dependency. It’s breaking yarn today.