-
Notifications
You must be signed in to change notification settings - Fork 522
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support yarn/npm7 workspaces #266
Comments
@clydin from our team has been looking at yarn workspaces. As I understand it, we have the same features as yarn workspaces without actually using it. You can have multiple directories with a |
@alexeagle I think you'll still run into problem supporting both yarn workspaces (e.g. for interactive development with livereload) and Bazel. To support a local yarn install, you need the subpackages in your package.json, but this will break the yarn_install in WORKSPACE since those private subpackages won't be published to npm. Do you have advice on how to support both a native yarn workflow and Bazel workflow from a monorepo with multiple packages? |
@tristanz I think the idea here is that you don't isntall your sub packages with a |
If bazel supports yarn workspaces, could that be used to solve the following issue: Assume a monorepo has two 'top-level' projects that are separately deploy able, e.g. 'app1' and 'app2' and they both depend upon a library 'lib1'. Lib1 is typescript library with a package.json that has a dependency on a third party library, e.g. lodash. Each of the applications also have package.json files with lodash but they also add another dependency, e.g. angular. The two apps must have a consistent version for lodash but they may want to have different versions for angular at times, e.g. so they can upgrade independently. Bazel supports supports multiple yarn_install/npm_install calls to create the workspaces but ts_library from app1 would prevent a dependency on lib1 because it will throw the 'All npm dependencies need to come from a single workspace" error and I don't think a single npm_install/yarn_install' workspace can contain two versions of angular so we can't use one package.json? Is there some other solution to this or would we need the yarn workspace capability? Thanks. |
There's probably a lot of people using Lerna / Yarn workspaces currently that would be interested in Bazel but need to keep workspaces working while using Bazel for some things. |
Assuming Bazel is delegating to Yarn how it says it is Yarn handles doing a symlink for packages within the monorepo instead of trying to download them. |
It looks like currently Bazel doesn't blow up when using Yarn workspaces, but the generated
|
Could the Node linker be reworked so that instead of having a single node_modules in the runfiles, it has one per package? I guess this is what it would mean to "add Yarn workspaces support". It would be nice if rules_nodejs could do this by itself and use of Yarn workspaces wasn't required. Delegating to the package manager, in this case Yarn, seems more Bazel "native" though, since Bazel stays away from having multiple versions of dependencies. @alexeagle, if there's a need for contributors I'll gladly help with getting Yarn workspaces support. My team is trying to move from Lerna + Yarn workspaces to Bazel but it's imperative that if two different apps in our repo have two different versions of some transitive dependency, it resolves properly. There's two reasons for this. First, because it would break the application if the wrong version is used of course. And second, because while keeping the same version of a shared library the same across a monorepo is definitely ideal, specially if the library is in the monorepo itself, it's sometimes not possible to make a change across the entire repo. I more or less understand the source so I might be able to experiment with it if I'm pointed in the right direction. |
I looked more into this. It seems the current rules are pretty close. # WORKSPACE
# ... prior setup snipped
yarn_install(
name = "npm",
package_json = "//:package.json",
yarn_lock = "//:yarn.lock",
) When using the repository rule above, one can depend on dependencies as follows... # packages/lib/BUILD.bazel
ts_library(
name = "lib",
srcs = ["index.ts"],
module_name = "lib",
deps = [
"@npm//lodash",
],
) # packages/app/BUILD.bazel
nodejs_binary(
name = "bin",
deps = [
"//packages/lib",
"@npm//lodash",
],
entry_point = "index.ts",
) If the Yarn workspace "app" depends on lodash@4 but "lib" dependes on lodash@3, both packages will get v4. That being said, the runfiles at Before coming to this conclusion, I tried some things. I tried making following change to # packages/app/BUILD.bazel
nodejs_binary(
name = "bin",
deps = [
+ "@npm//lib",
"@npm//lodash",
],
entry_point = "index.ts",
) Also, I played with the generated BUILD file's visibility to expose the # packages/lib/BUILD.bazel
ts_library(
name = "lib",
srcs = ["index.ts"],
module_name = "lib",
deps = [
- "@npm//lodash",
+ "@npm//lib:lib__contents",
],
) This will properly add the desired contents to One more thing, you can always get to the right lodash version from "lib" by doing something like this: console.log(require.resolve('../../..')) // resolves to "bin.sh.runfiles"
require('../../../npm/node_modules/lib/node_modules/lodash') |
@alexeagle @clydin do you have any news on that topic? I have a pretty similar use case to the one mentioned by @migueloller and considering what he described in his findings it looks like what we currently have is only some step ways from what is needed. It would be really nice to finally have support for this 😃 |
Sorry, no update. We support multiple nested package.json but they each
need to be self-contained right now. We don't even have any design thoughts
yet for how we would do yarn workspaces, and it might need changes in Bazel
to support properly (like with the managed_directories feature)
…On Mon, Jun 15, 2020 at 1:47 PM Tiago Costa ***@***.***> wrote:
@alexeagle <https://github.com/alexeagle> do you have any news on that
topic? I have a pretty similar use case to the one mentioned by
@migueloller <https://github.com/migueloller> and considering what he
described in his findings it looks like what we currently have is only some
step ways from what is needed. It would be really nice to finally have
support for this 😃
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#266 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAALSI2XJVP7YCHSR2LH3Z3RW2CGJANCNFSM4FNOURJQ>
.
|
@alexeagle do you have a link to an example? |
Sure, this repo is an example. Multiple calls to |
I've spent a very long time attempting to implement a workspace rule for Yarn workspaces. My conclusion is that because with Bazel we want to be explicit about dependencies (i.e., fine-grained deps), and a # //foo/BUILD
js_library(
name = "foo",
srcs = ["index.js", "package.json"],
entry_point = "index.js",
deps = ["@npm//foo/lodash"],
)
# //bar/BUILD
js_library(
name = "bar",
srcs = ["index.js", "package.json"],
entry_point = "index.js",
deps = ["@npm//bar/lodash"],
) It is necessary to namespace
EDIT: @alexeagle, did you have any ideas yet for the design of a potential implementation? |
Hi @migueloller I don't think we want to get into the business of understanding multiple versions nor the node APIs needed to resolve them. Rather, we want to be 100% mechanical about:
So this means our responsibility should just be about locations on disk where the packages go, first making them different from node idiom (external repo rather than in the source tree) and then making them the same again (linker). My theory is that if the linker should not always link a single node_modules tree into the $pwd/node_modules. Instead we should remember what subdirectory of your project had the package.json file, and link the node_modules there. Does that make sense? It feels doable but it's a pretty tricky area of the code. |
@alexeagle, yeah that makes sense. If I'm understanding correctly: option 1 would be to patch Node.js require so that I agree with you that option 2 is probably the best way to go about this. I took another look at the linker, and if I'm understanding it correctly, does it do the filesystem changes when the binary is executed? Or said a different way, when running a Also, regarding the ability to reference npm/yarn dependencies from multiple external repositories, this would in a way solve the same problem that Yarn workspaces solves and is something that I personally prefer even over Yarn workspaces. It makes sense that if support for multiple Would you say that these are two separate features, though? One is adding support for Yarn workspaces and the other is adding support for referencing different external repositories for the |
You understand the linker right. It adapts from Bazel semantics of separate sources/outputs/external repo back to node semantics of those all being together. Yarn workspaces is a special case of multiple repositories and should be done second. The hard part is calling yarn install and then getting the layout in the right places for Bazel. We should discuss in the next team meeting, ping me on slack if you want to attend |
Closes bazel-contrib#266 PiperOrigin-RevId: 221465479
Closes bazel-contrib#266 PiperOrigin-RevId: 221465479
This issue has been automatically marked as stale because it has not had any activity for 90 days. It will be closed if no further activity occurs in two weeks. Collaborators can add a "cleanup" or "need: discussion" label to keep it open indefinitely. Thanks for your contributions to rules_nodejs! |
Now that Workspaces in npm has shipped it's more clear that this is a standard and we should understand it better, probably implement support via a new |
@adam-thomas-privitar I'll discuss with @gregmagolan on monday and see what we can put out since technically it's company code at the moment 😛 |
I have started working on a change to support this by updating the require patch, but I see that the linker is the suggested way to manage modules now. I would like to support both options, so I'm working on this now. I would like to clarify a couple things here around the design prior to moving to far along with the implementation. How would you see module resolution working with multiple ExampleFor an example. Let's say we want to define a test target to use Stencil. You could have the following in your # setup stencil spec test dependencies
yarn_install(
name = "npm_stencil",
exports_directories_only = True,
frozen_lockfile = True,
package_json = "//tools//stencil:dependencies/package.json",
package_path = "sub_node_modules/stencil",
yarn_lock = "//tools/stencil:dependencies/yarn.lock",
)
yarn_install(
name = "npm",
data = ["//:.npmrc"],
exports_directories_only = True,
frozen_lockfile = True,
package_json = "//:package.json",
yarn_lock = "//:yarn.lock",
) And the following in your BUILD file to define a test using the Stencil CLI: nodejs_test(
name = "test",
args = ["test", "--spec"],
chdir = native.package_name(),
data = [
"@npm//rxjs",
"@npm_stencil//@stencil/core",
"@npm_stencil//jest",
"@npm_stencil//jest-cli",
"@npm_stencil//@types/jest",
"@npm_stencil//yargs",
":src",
":stencil.config.ts",
],
entry_point = stencil_cli_path,
) Here, we will need to pull in certain libraries to test with the Stencil CLI. However, the rest of my project may be standardized on a different version of DesignIn this example scenario, I would expect either the No DuplicatesSo long as there aren't duplicates, the solution is fairly straightforward. For the module linker: Link each of the targets modules into a single root regardless of separate workspaces (which is currently checked for a For the require patch: The DuplicatesWith duplicates, the design must make certain decisions which will have impacts to the reproducibility of a build. Supposing that we have defined a dependency, e.g. If duplicates are allowed, in order to be reproducible the operation to link these must be a bijective function, and some manner of defining order of precedence will be required. This could be inferred by order of declaration, e.g. the last dependency always wins ( This is somewhat implicit with those using rules that may provide certain dependencies on their own, but reproducible nonetheless, based on the order of modules as given in the Another option is to simply disallow duplicates, which may be a more destructive or limiting approach in the case of child dependencies. FeedbackI'm hoping to get feedback on what logic would be preferred for this. Let me know what you think of the handling of duplicates. |
@Aghassi and @gregmagolan, thank you for the all the tips. Will start exploring the possibilities. |
This issue has been automatically marked as stale because it has not had any activity for 6 months. It will be closed if no further activity occurs in 30 days. Collaborators can add a "cleanup" or "need: discussion" label to keep it open indefinitely. Thanks for your contributions to rules_nodejs! |
Still humbly hoping for workspaces support and that this doesn't get auto closed after 4 years. |
So my previous comment about copying back to the source tree still stands as how we do things. I'm still working with @gregmagolan @alexeagle and @joeljeske about next steps, but there is a strong possibility my team will not remain on yarn long term as we pursue things like pnpm. I'm not sure how that changes the equation, but the concept of workspaces doesn't really apply under the bazel graph it's mostly a source tree concept while you are in an in-between state as far as I know. For now, our preinstall script method has served us well, it's just cumbersome to use unfortunately. |
Upgrading to Bazel's rules_nodejs 5.x exposed a flaw in our previous Bazel integration: because rules_nodejs explicitly doesn't support yarn's "workspaces" feature [1] (in which common dependencies are hoisted to the lowest common parent directory), any NPM dependencies with different major versions between db-console and cluster-ui would get flattened to a single version. This left one of those packages using an unsupported (and un-requested) version of a dependency. Removing the yarn workspace layout and using separate Bazel repositories for each JS project ensured each project received the correct dependencies, but revealed incompatibilities with the requested versions. Upgrade rules_nodejs to the latest released version, remove yarn workspaces from the pkg/ui/ tree, and fix all revealed compatibility issues. [1] bazel-contrib/rules_nodejs#266
Upgrading to Bazel's rules_nodejs 5.x exposed a flaw in our previous Bazel integration: because rules_nodejs explicitly doesn't support yarn's "workspaces" feature [1] (in which common dependencies are hoisted to the lowest common parent directory), any NPM dependencies with different major versions between db-console and cluster-ui would get flattened to a single version. This left one of those packages using an unsupported (and un-requested) version of a dependency. Removing the yarn workspace layout and using separate Bazel repositories for each JS project ensured each project received the correct dependencies, but revealed incompatibilities with the requested versions. Upgrade rules_nodejs to the latest released version, remove yarn workspaces from the pkg/ui/ tree, and fix all revealed compatibility issues. [1] bazel-contrib/rules_nodejs#266
Upgrading to Bazel's rules_nodejs 5.x exposed a flaw in our previous Bazel integration: because rules_nodejs explicitly doesn't support yarn's "workspaces" feature [1] (in which common dependencies are hoisted to the lowest common parent directory), any NPM dependencies with different major versions between db-console and cluster-ui would get flattened to a single version. This left one of those packages using an unsupported (and un-requested) version of a dependency. Removing the yarn workspace layout and using separate Bazel repositories for each JS project ensured each project received the correct dependencies, but revealed incompatibilities with the requested versions. Upgrade rules_nodejs to the latest released version, remove yarn workspaces from the pkg/ui/ tree, and fix all revealed compatibility issues. [1] bazel-contrib/rules_nodejs#266
Upgrading to Bazel's rules_nodejs 5.x exposed a flaw in our previous Bazel integration: because rules_nodejs explicitly doesn't support yarn's "workspaces" feature [1] (in which common dependencies are hoisted to the lowest common parent directory), any NPM dependencies with different major versions between db-console and cluster-ui would get flattened to a single version. This left one of those packages using an unsupported (and un-requested) version of a dependency. Removing the yarn workspace layout and using separate Bazel repositories for each JS project ensured each project received the correct dependencies, but revealed incompatibilities with the requested versions. Upgrade rules_nodejs to the latest released version, remove yarn workspaces from the pkg/ui/ tree, and fix all revealed compatibility issues. [1] bazel-contrib/rules_nodejs#266
Upgrading to Bazel's rules_nodejs 5.x exposed a flaw in our previous Bazel integration: because rules_nodejs explicitly doesn't support yarn's "workspaces" feature [1] (in which common dependencies are hoisted to the lowest common parent directory), any NPM dependencies with different major versions between db-console and cluster-ui would get flattened to a single version. This left one of those packages using an unsupported (and un-requested) version of a dependency. Removing the yarn workspace layout and using separate Bazel repositories for each JS project ensured each project received the correct dependencies, but revealed incompatibilities with the requested versions. Upgrade rules_nodejs to the latest released version, remove yarn workspaces from the pkg/ui/ tree, and fix all revealed compatibility issues. [1] bazel-contrib/rules_nodejs#266
Upgrading to Bazel's rules_nodejs 5.x exposed a flaw in our previous Bazel integration: because rules_nodejs explicitly doesn't support yarn's "workspaces" feature [1] (in which common dependencies are hoisted to the lowest common parent directory), any NPM dependencies with different major versions between db-console and cluster-ui would get flattened to a single version. This left one of those packages using an unsupported (and un-requested) version of a dependency. Removing the yarn workspace layout and using separate Bazel repositories for each JS project ensured each project received the correct dependencies, but revealed incompatibilities with the requested versions. Upgrade rules_nodejs to the latest released version, remove yarn workspaces from the pkg/ui/ tree, and fix all revealed compatibility issues. [1] bazel-contrib/rules_nodejs#266
Upgrading to Bazel's rules_nodejs 5.x exposed a flaw in our previous Bazel integration: because rules_nodejs explicitly doesn't support yarn's "workspaces" feature [1] (in which common dependencies are hoisted to the lowest common parent directory), any NPM dependencies with different major versions between db-console and cluster-ui would get flattened to a single version. This left one of those packages using an unsupported (and un-requested) version of a dependency. Removing the yarn workspace layout and using separate Bazel repositories for each JS project ensured each project received the correct dependencies, but revealed incompatibilities with the requested versions. Upgrade rules_nodejs to the latest released version, remove yarn workspaces from the pkg/ui/ tree, and fix all revealed compatibility issues. [1] bazel-contrib/rules_nodejs#266
Upgrading to Bazel's rules_nodejs 5.x exposed a flaw in our previous Bazel integration: because rules_nodejs explicitly doesn't support yarn's "workspaces" feature [1] (in which common dependencies are hoisted to the lowest common parent directory), any NPM dependencies with different major versions between db-console and cluster-ui would get flattened to a single version. This left one of those packages using an unsupported (and un-requested) version of a dependency. Removing the yarn workspace layout and using separate Bazel repositories for each JS project ensured each project received the correct dependencies, but revealed incompatibilities with the requested versions. Upgrade rules_nodejs to the latest released version, remove yarn workspaces from the pkg/ui/ tree, and fix all revealed compatibility issues. [1] bazel-contrib/rules_nodejs#266
This issue has been automatically marked as stale because it has not had any activity for 6 months. It will be closed if no further activity occurs in 30 days. Collaborators can add a "cleanup" or "need: discussion" label to keep it open indefinitely. Thanks for your contributions to rules_nodejs! |
This issue was automatically closed because it went 30 days without any activity since it was labeled "Can Close?" |
this is available in https://github.com/aspect-build/rules_js |
Yep! And just as one data point, I switched over and it resolved everything mentioned in this thread perfectly. I would encourage everyone to switch. |
Would yarn workspaces work with this rule?
I was playing around with 0.10.0 recently but didn't get very far in trying to setup yarn_install. Would a future version support this?
The text was updated successfully, but these errors were encountered: