Skip to content

Commit

Permalink
Revert "Revert "js_run_devserver symlinks scoped node_modules to baze… (
Browse files Browse the repository at this point in the history
#1233)

* Revert "Revert "js_run_devserver symlinks scoped node_modules to bazel-out instead of runfiles (unscoped node_modules are already linked to bazel-out) (#1210)" (#1230)"

Roll-forward #1210 with fixes.
This reverts commit 06ad186.

* chore: tag devserver test as no-remote-exec
  • Loading branch information
alexeagle authored Aug 29, 2023
1 parent 198ec6f commit 7a3852f
Show file tree
Hide file tree
Showing 13 changed files with 813 additions and 81 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
# Input hashes for repository rule npm_translate_lock(name = "npm", pnpm_lock = "//:pnpm-lock.yaml").
# This file should be checked into version control along with the pnpm-lock.yaml file.
.npmrc=-2065072158
pnpm-lock.yaml=754060271
pnpm-lock.yaml=1169067734
examples/npm_deps/patches/meaning-of-life@1.0.0-pnpm.patch=-442666336
package.json=965846805
pnpm-workspace.yaml=1536402859
pnpm-workspace.yaml=116986059
examples/js_binary/package.json=-41174383
examples/macro/package.json=857146175
examples/npm_deps/package.json=283109008
Expand All @@ -16,6 +16,7 @@ examples/webpack_cli/package.json=1911342006
js/private/coverage/bundle/package.json=-1543718929
js/private/image/package.json=-1260474848
js/private/test/image/package.json=1295393035
js/private/test/js_run_devserver/package.json=-260856079
js/private/worker/src/package.json=1608383745
npm/private/test/package.json=1424344949
npm/private/test/vendored/lodash-4.17.21.tgz=-1206623349
Expand Down
1 change: 1 addition & 0 deletions .bazelignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ examples/webpack_cli/node_modules/
js/private/coverage/bundle/node_modules
js/private/image/node_modules
js/private/test/image/node_modules
js/private/test/js_run_devserver/node_modules
js/private/worker/src/node_modules
node_modules/
npm/private/test/node_modules/
Expand Down
1 change: 1 addition & 0 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ npm_translate_lock(
"//js/private/coverage/bundle:package.json",
"//js/private/image:package.json",
"//js/private/test/image:package.json",
"//js/private/test/js_run_devserver:package.json",
"//js/private/worker/src:package.json",
"//npm/private/test:package.json",
"//npm/private/test:vendored/lodash-4.17.21.tgz",
Expand Down
1 change: 1 addition & 0 deletions docs/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ stardoc_with_diff_test(
stardoc_with_diff_test(
name = "js_run_devserver",
bzl_library_target = "//js/private:js_run_devserver",
symbol_names = ["js_run_devserver"],
)

stardoc_with_diff_test(
Expand Down
13 changes: 11 additions & 2 deletions js/private/js_run_devserver.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,16 @@ def _impl(ctx):
),
]

_js_run_devserver = rule(
js_run_devserver_lib = struct(
attrs = _attrs,
implementation = _impl,
toolchains = js_binary_lib.toolchains,
)

_js_run_devserver = rule(
attrs = js_run_devserver_lib.attrs,
implementation = js_run_devserver_lib.implementation,
toolchains = js_run_devserver_lib.toolchains,
executable = True,
)

Expand Down Expand Up @@ -237,7 +243,10 @@ def js_run_devserver(
if kwargs.get("entry_point", None):
fail("`entry_point` is set implicitly by `js_run_devserver` and cannot be overridden.")

_js_run_devserver(
# Allow the js_run_devserver rule to execute to be overridden for tests
rule_to_execute = kwargs.pop("rule_to_execute", _js_run_devserver)

rule_to_execute(
name = name,
enable_runfiles = select({
"@aspect_rules_js//js:enable_runfiles": True,
Expand Down
23 changes: 22 additions & 1 deletion js/private/js_run_devserver.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,27 @@ function mkdirpSync(p) {
mkdirs.add(p)
}

// Determines if a file path refers to a node module.
//
// Examples:
// isNodeModulePath('/private/var/.../node_modules/@babel/core') // true
// isNodeModulePath('/private/var/.../node_modules/lodash') // true
// isNodeModulePath('/private/var/.../some-file.js') // false
function isNodeModulePath(srcPath) {
const parentDir = path.dirname(srcPath);
const parentDirName = path.basename(parentDir);

if (parentDirName === 'node_modules') {
// unscoped module like 'lodash'
return true;
} else if (parentDirName.startsWith('@')) {
// scoped module like '@babel/core'
const parentParentDir = path.dirname(parentDir);
return path.basename(parentParentDir) === 'node_modules';
}
return false;
}

// Recursively copies a file, symlink or directory to a destination. If the file has been previously
// synced it is only re-copied if the file's last modified time has changed since the last time that
// file was copied. Symlinks are not copied but instead a symlink is created under the destination
Expand All @@ -52,7 +73,7 @@ async function syncRecursive(src, dst, writePerm) {
if (process.env.JS_BINARY__LOG_DEBUG) {
console.error(`Syncing symlink ${srcWorkspacePath}`)
}
if (path.basename(path.dirname(src)) == 'node_modules') {
if (isNodeModulePath(src)) {
// Special case for node_modules symlinks where we should _not_ symlink to the runfiles but rather
// the bin copy of the symlink to avoid finding npm packages in multiple node_modules trees
const maybeBinSrc = path.join(
Expand Down
34 changes: 34 additions & 0 deletions js/private/test/js_run_devserver/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
load("@npm//:defs.bzl", "npm_link_all_packages")
load("@npm//js/private/test/js_run_devserver:jasmine/package_json.bzl", jasmine_bin = "bin")
load(":js_run_devserver_test.bzl", "js_run_devserver_test")

npm_link_all_packages(name = "node_modules")

# Checks node_modules symlinks that they refer to exec root (instead of runfiles)
# in order to make sure bundlers see exactly one node_modules tree. Checks:
# - https://github.com/aspect-build/rules_js/pull/1043
# - https://github.com/aspect-build/rules_js/issues/1204
js_run_devserver_test(
name = "node_modules_symlink_to_execroot_test",
args = ["node_modules_symlink_to_execroot.test.mjs"],
chdir = "js/private/test/js_run_devserver",
data = [
"node_modules_symlink_to_execroot.test.mjs",

# Some packages to link back to the exec root for the tests for
# https://github.com/aspect-build/rules_js/issues/1204 (and need jasmine
# anyway for the runner)
":node_modules/@types/node",
":node_modules/jasmine",
],
tags = [
# devserver is meant to be `bazel run` locally.
# See https://github.com/aspect-build/rules_js/pull/1233
"no-remote-exec",
],
tool = ":jasmine",
)

jasmine_bin.jasmine_binary(
name = "jasmine",
)
41 changes: 41 additions & 0 deletions js/private/test/js_run_devserver/js_run_devserver_test.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"Implementation of the js_run_devserver_test rule (the 'test' version of js_run_devserver)"

load("//js/private:js_run_devserver.bzl", "js_run_devserver", "js_run_devserver_lib")

# 'test' version of the _js_run_devserver` rule
_js_run_devserver_test = rule(
attrs = js_run_devserver_lib.attrs,
implementation = js_run_devserver_lib.implementation,
toolchains = js_run_devserver_lib.toolchains,
test = True,
)

def js_run_devserver_test(
name,
tags = [],
**kwargs):
"""
'Test' version of the `js_run_devserver` macro.
Provides the test rule to the macro, along with the 'no-sandbox' tag in
order to properly simulate the js_run_devserver environment of 'bazel run'.
Args:
name: A unique name for this target.
tags: Additional Bazel tags to supply to the rule.
**kwargs: All other args for `js_run_devserver`.
See https://docs.aspect.build/rules/aspect_rules_js/docs/js_run_devserver
"""
js_run_devserver(
name,
# Override the rule to execute
rule_to_execute = _js_run_devserver_test,
# 'no-sandbox' needed to simulate 'bazel run' command - normally tests
# are sandboxed, but sandboxing doesn't exhibit the issue in
# https://github.com/aspect-build/rules_js/issues/1204
tags = tags + ["no-sandbox"],
**kwargs
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import fs from 'fs'

describe('node_modules symlinks >', () => {
const execRootDir = process.env.JS_BINARY__EXECROOT
const runfilesDir = process.env.JS_BINARY__RUNFILES

beforeAll(() => {
// first ensure that the environment variables are strings with some value
if (typeof execRootDir !== 'string' || execRootDir.length === 0) {
throw new Error(`process.env.JS_BINARY__EXECROOT is empty - can't run tests which rely on it`)
}
if (typeof runfilesDir !== 'string' || runfilesDir.length === 0) {
throw new Error(`process.env.JS_BINARY__RUNFILES is empty - can't run tests which rely on it`)
}
})

it(`symlinks non-scoped node_modules (e.g. 'jasmine') to the exec root instead of runfiles to ensure bundlers see a single node_modules tree (https://github.com/aspect-build/rules_js/pull/1043)`, () => {
const jasmineSymlink = fs.readlinkSync('./node_modules/jasmine')

expect(jasmineSymlink).toContain(execRootDir)
expect(jasmineSymlink).not.toContain(runfilesDir)
})

it(`symlinks scoped node_modules (e.g. '@types/node') to the exec root instead of runfiles to ensure bundlers see a single node_modules tree (https://github.com/aspect-build/rules_js/issues/1204)`, () => {
const typesNodeSymlink = fs.readlinkSync('./node_modules/@types/node')

expect(typesNodeSymlink).toContain(execRootDir)
expect(typesNodeSymlink).not.toContain(runfilesDir)
})
})
9 changes: 9 additions & 0 deletions js/private/test/js_run_devserver/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "js_run_devserver_test",
"version": "0.0.0",
"private": true,
"dependencies": {
"@types/node": "16.18.11",
"jasmine": "5.1.0"
}
}
Loading

0 comments on commit 7a3852f

Please sign in to comment.