Skip to content
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

Add e2e tests/examples of transitive npm deps for ts_library - nodejs_binary interop #612

Closed

Conversation

Globegitter
Copy link
Contributor

@Globegitter Globegitter commented Mar 11, 2019

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature (please, look at the "Scope of the project" section in the README.md file)
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Other... Please describe:

Tests for odd behaviour of ts_library <-> nodejs_binary (and rollup_bundle) interaction discussed and tested here: #283 (comment)

What is the current behavior?

It seems that under certain (or all?) circumstances nodejs_binary as well as rollup_bundle is not collecting transitive npm dependencies.

Issue Number: N/A

What is the new behavior?

For now this PR just adds tests but is not fixing the behaviour yet. I will also have a look at fixing the behaviour.

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

cc @gregmagolan I was not sure where to best test this and if there is a better way of maybe using nodejs_test for this rather than nodejs_binary but let me know and happy to move this, clean this up etc.

@Globegitter
Copy link
Contributor Author

Related #560

@Globegitter
Copy link
Contributor Author

Should fix #560 as well as the issue discussed here: #283 (comment)

@gregmagolan would love some feedback on this.

# TODO(alexeagle): turn on strict deps checking when we have a real
# provider for JS/DTS inputs to ts_library.
deps = [d for d in ctx.attr.deps if not NodeModuleInfo in d],
deps = [d for d in ctx.attr.deps if not NodeModuleInfo in d or (NodeModuleInfo in d and d[NodeModuleInfo].transitive == True)],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note, this line needs to go away anyway because it's causing bazelbuild/rules_typescript#381

I'll rebase around this though, glad you've added tests so I know I don't break it

@@ -35,7 +36,13 @@ def _collect_node_modules_aspect_impl(target, ctx):

if hasattr(ctx.rule.attr, "tags") and "NODE_MODULE_MARKER" in ctx.rule.attr.tags:
nm_wksp = target.label.workspace_root.split("/")[1] if target.label.workspace_root else ctx.workspace_name
return [NodeModuleInfo(workspace = nm_wksp)]
return [NodeModuleInfo(workspace = nm_wksp, transitive = False)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect transitive to have a similar meaning to how a depset has a transitive argument (the depsets to hang off this one in the tree)
Can we find another name for this attribute? Really it's like a NodeModuleInfo for something that's not a node_module. Maybe it should just be a different provider instead of overloading this one?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah maybe it does make sense to have a different provider as the attribute thing did feel a bit awkard. I'll have a bit of a think and another go at it.

@alexeagle
Copy link
Collaborator

Does this mean users no longer have to repeat deps on their rollup_bundle rule if a transitively included ts_library had the dep? That sounds great! We'll need to clean up stuff downstream.

@Globegitter
Copy link
Contributor Author

Yep exactly this is what this is aimed at fixing, as it is also necessary for a correct implementation of #283

@@ -26,6 +26,7 @@
NodeModuleInfo = provider(
doc = "This provider contains information about npm dependencies installed with yarn_install and npm_install rules",
fields = {
"transitive": "If true this dependency has transitive npm dependencies but is not and npm package itself",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"transitive": "If true this dependency has transitive npm dependencies but is not and npm package itself",
"transitive": "If true this dependency has transitive npm dependencies but is not an npm package itself",

@gregmagolan
Copy link
Collaborator

Nice. I did some initial debugging and this doesn't seem quite right and may not be hermetic. I'll do some more work on this later this evening.

@Globegitter
Copy link
Contributor Author

Yes, I have not done very extensive testing and was looking for some input first, but will also start testing this with #283 as well as with our apps. Though which part are you referring to that might not be hermetic?

@gregmagolan
Copy link
Collaborator

gregmagolan commented Mar 29, 2019

Yes, I have not done very extensive testing and was looking for some input first, but will also start testing this with #283 as well as with our apps. Though which part are you referring to that might not be hermetic?

From an initial look it seemed like the transitive npm deps like date-fns are not added to the rollup action inputs but they are still resolved from their non-sandboxed location.

The code in rollup_bundle.bzl ends up adding the .d.ts files from ts_library deps that have NodeModuleInfo with transitive = true but not the transitive npm deps themselves..

    # Also include files from npm fine grained deps as inputs.
    # These deps are identified by the NodeModuleInfo provider.
    for d in ctx.attr.deps:
        if NodeModuleInfo in d:
            direct_inputs += _filter_js_inputs(d.files.to_list())

I'm going to play with it some more today as this would be a good one to get in and would unblock your #283 as well.

@Globegitter
Copy link
Contributor Author

Globegitter commented Mar 29, 2019

Aahh yes, to be honest I was actually surprised that it already worked by just adding the transitive NodeModuleInfo. So I suppose it somehow follows out a symlink somewhere? I have noticed that as well sometimes in our apps, that there can be different behaviour if node_modules exist in the developer's workspace or not. And so far I am assuming that some things somehow are not preserving symlinks.

@Globegitter
Copy link
Contributor Author

Globegitter commented Apr 3, 2019

Started debugging and it does indeed not seem to be hermetic. I do not find any trace of date-fns in the sandbox for the rollup action and the debug logs of rollup bundling show:

Rollup: resolving 'date-fns' from /home/markus/.cache/bazel/_bazel_markus/8464573ded3a95b161445c575d9af429/sandbox/linux-sandbox/1/execroot/e2e_typescript_3_1/bazel-out/k8-fastbuild/bin/bundle.es6/lib.js
Rollup: try to resolve 'date-fns' at '/home/markus/.cache/bazel/_bazel_markus/8464573ded3a95b161445c575d9af429/sandbox/linux-sandbox/1/execroot/e2e_typescript_3_1/bazel-out/k8-fastbuild/bin/bundle.es6/date-fns'
Rollup: allowing rollup to resolve 'date-fns' with node module resolution
Rollup: resolving './add_days/index.js' from /home/markus/.cache/bazel/_bazel_markus/8464573ded3a95b161445c575d9af429/external/npm/node_modules/date-fns/index.js

The last path is outside the sandbox. But need to look further into this to understand what exactly is happening.

@Globegitter
Copy link
Contributor Author

Some further progress: I found rollup itself has a preserveSymlinks option which defaults to false so I set that and I also added the --preserve-symlinks-main just to make sure there is nothing related to symlinks. But that has not changed anything. I have found that the node-resolve plugin has a jail option, which is to limit module resolution just to a specific path. That seems like a sensible safeguard to me and setting this now the build is failing indeed. Still more work to be done.

],
)

rollup_bundle(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should change the test script in package.json to bazel build ... && bazel test ... so that these targets are built

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am pretty sure bazel test ... implicitly also builds all targets (unless --build_tests_only) is also specified. Let me verify this though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep just verified. I had a failing rollup_bundle and bazel test ... failed on building it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahhhh. Good to know. Thanks for verifying.

@@ -193,6 +194,7 @@ const config = {
banner,
format: 'TMPL_output_format',
},
preserveSymlinks: true,
Copy link
Collaborator

@gregmagolan gregmagolan Apr 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. Do these preserve symlinks & jail changes work as intended to keep the resolve within the cwd()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, in this particular case it was really the jail attribute that brought the non-hermetic build to fail.

@@ -22,13 +22,36 @@ NodeModuleInfo = provider(
},
)

NodeModuleSources = provider(
Copy link
Collaborator

@gregmagolan gregmagolan Apr 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect this is over complicating things here with two different node_modules providers and a NODE_MODULE_MARKER tag. This may be a good opportunity to remove the tag and create a single rule that is used instead of filegroup in generate_build_file.js so we can avoid the marker and have a single provider.

@kyliau recently added the ng_apf_library() rule which is used instead of filegroup when an angular package format is detected. We consolidate this work into a single rule and solve the transitive deps problem as well.

@gregmagolan
Copy link
Collaborator

Closing in favor of #675. Subset of changes from this PR will be ported over.

@gregmagolan gregmagolan closed this Apr 6, 2019
@Globegitter Globegitter deleted the mp-ts-nodejs-npm-example branch April 16, 2019 09:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants