Skip to content

Commit 022acf8

Browse files
devversionjelbourn
authored andcommitted
build: enable bazel node modules symlinking (#17675)
Enables bazel managed node modules symlinking (similar to what framework does). We benefit from: * Easier way to make manual changes to debug issues * Less disk size since we do not need to maintain two instances of `node_modules` * Caching of node modules in CI. Bazel previously discarded the whole node modules folder if the lock file changed.
1 parent d77d668 commit 022acf8

File tree

4 files changed

+56
-26
lines changed

4 files changed

+56
-26
lines changed

.circleci/config.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ var_2: &docker-firefox-image circleci/node:12.9.1-browsers
1313
# **Note**: When updating the beginning of the cache key, also update the cache key to match
1414
# the new cache key prefix. This allows us to take advantage of CircleCI's fallback caching.
1515
# Read more here: https://circleci.com/docs/2.0/caching/#restoring-cache.
16-
var_3: &cache_key v4-ng-mat-{{ checksum "WORKSPACE" }}-{{ checksum "yarn.lock" }}
17-
var_4: &cache_fallback_key v4-ng-mat-
16+
var_3: &cache_key v4-ng-mat-{{ checksum "tools/bazel/postinstall-patches.js" }}-{{ checksum "WORKSPACE" }}-{{ checksum "yarn.lock" }}
17+
# We want to invalidate the cache if the postinstall patches change. In order to apply new
18+
# patches, a clean version of the node modules is needed.
19+
var_4: &cache_fallback_key v4-ng-mat-{{ checksum "tools/bazel/postinstall-patches.js" }}-
1820

1921
# Settings common to each job
2022
var_5: &job_defaults

WORKSPACE

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
workspace(name = "angular_material")
1+
workspace(
2+
name = "angular_material",
3+
managed_directories = {"@npm": ["node_modules"]},
4+
)
25

36
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
47

@@ -42,20 +45,10 @@ node_repositories(
4245

4346
yarn_install(
4447
name = "npm",
45-
# Ensure that all resources are available when the "postinstall" or "preinstall" scripts
46-
# are executed in the Bazel sandbox.
47-
data = [
48-
"//:angular-tsconfig.json",
49-
"//:tools/bazel/flat_module_factory_resolution.patch",
50-
"//:tools/bazel/manifest_externs_hermeticity.patch",
51-
"//:tools/bazel/postinstall-patches.js",
52-
"//:tools/npm/check-npm.js",
53-
],
48+
# We add the postinstall patches file here so that Yarn will rerun whenever
49+
# the patches script changes.
50+
data = ["//:tools/bazel/postinstall-patches.js"],
5451
package_json = "//:package.json",
55-
# Temporarily disable node_modules symlinking until the fix for
56-
# https://github.com/bazelbuild/bazel/issues/8487 makes it into a
57-
# future Bazel release
58-
symlink_node_modules = False,
5952
yarn_lock = "//:yarn.lock",
6053
)
6154

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"yarn": ">= 1.19.1"
1414
},
1515
"scripts": {
16-
"postinstall": "node --preserve-symlinks --preserve-symlinks-main tools/bazel/postinstall-patches.js && ngcc --properties main --create-ivy-entry-points",
16+
"postinstall": "node tools/bazel/postinstall-patches.js && ngcc --properties main --create-ivy-entry-points",
1717
"build": "bash ./scripts/build-packages-dist.sh",
1818
"bazel:buildifier": "find . -type f \\( -name \"*.bzl\" -or -name WORKSPACE -or -name BUILD -or -name BUILD.bazel \\) ! -path \"*/node_modules/*\" | xargs buildifier -v --warnings=attr-cfg,attr-license,attr-non-empty,attr-output-default,attr-single-file,constant-glob,ctx-args,depset-iteration,depset-union,dict-concatenation,duplicated-name,filetype,git-repository,http-archive,integer-division,load,load-on-top,native-build,native-package,output-group,package-name,package-on-top,redefined-variable,repository-name,same-origin-load,string-iteration,unused-variable,unsorted-dict-items,out-of-order-load",
1919
"bazel:format-lint": "yarn -s bazel:buildifier --lint=warn --mode=check",

tools/bazel/postinstall-patches.js

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,18 @@ const shelljs = require('shelljs');
88
const path = require('path');
99
const fs = require('fs');
1010

11+
/**
12+
* Version of the post install patch. Needs to be incremented when patches
13+
* have been added or removed.
14+
*/
15+
const PATCH_VERSION = 1;
16+
1117
/** Path to the project directory. */
1218
const projectDir = path.join(__dirname, '../..');
1319

1420
shelljs.set('-e');
1521
shelljs.cd(projectDir);
1622

17-
// Do not apply postinstall patches when running "postinstall" outside. The
18-
// "generate_build_file.js" file indicates that we run in Bazel managed node modules.
19-
if (!shelljs.test('-e', 'generate_build_file.js')) {
20-
return;
21-
}
22-
2323
// Workaround for https://github.com/angular/angular/issues/18810.
2424
shelljs.exec('ngc -p angular-tsconfig.json');
2525

@@ -69,7 +69,7 @@ searchAndReplace(
6969
const hasFlatModuleBundle = fs.existsSync(filePath.replace('.d.ts', '.metadata.json'));
7070
if ((filePath.includes('node_modules/') || !hasFlatModuleBundle) && $1`,
7171
'node_modules/@angular/compiler-cli/src/transformers/compiler_host.js');
72-
shelljs.cat(path.join(__dirname, './flat_module_factory_resolution.patch')).exec('patch -p0');
72+
applyPatch(path.join(__dirname, './flat_module_factory_resolution.patch'));
7373
// The three replacements below ensure that metadata files can be read by NGC and
7474
// that metadata files are collected as Bazel action inputs.
7575
searchAndReplace(
@@ -90,7 +90,7 @@ searchAndReplace(
9090
'node_modules/@angular/bazel/src/ng_module.bzl');
9191

9292
// Workaround for: https://github.com/bazelbuild/rules_nodejs/issues/1208.
93-
shelljs.cat(path.join(__dirname, './manifest_externs_hermeticity.patch')).exec('patch -p0');
93+
applyPatch(path.join(__dirname, './manifest_externs_hermeticity.patch'));
9494

9595
// Workaround for using Ngcc with "--create-ivy-entry-points". This is a special
9696
// issue for our repository since we want to run Ivy by default in the module resolution,
@@ -136,18 +136,53 @@ shelljs.rm('-rf', [
136136
'node_modules/rxjs/Subscription.*',
137137
]);
138138

139+
/**
140+
* Applies the given patch if not done already. Throws if the patch does
141+
* not apply cleanly.
142+
*/
143+
function applyPatch(patchFile) {
144+
const patchMarkerFileName = `${path.basename(patchFile)}.patch_marker`;
145+
const patchMarkerPath = path.join(projectDir, 'node_modules/', patchMarkerFileName);
146+
147+
if (hasFileBeenPatched(patchMarkerPath)) {
148+
return;
149+
}
150+
151+
writePatchMarker(patchMarkerPath);
152+
shelljs.cat(patchFile).exec('patch -p0');
153+
}
154+
139155
/**
140156
* Reads the specified file and replaces matches of the search expression
141-
* with the given replacement. Throws if no changes were made.
157+
* with the given replacement. Throws if no changes were made and the
158+
* patch has not been applied yet.
142159
*/
143160
function searchAndReplace(search, replacement, relativeFilePath) {
144161
const filePath = path.join(projectDir, relativeFilePath);
162+
163+
if (hasFileBeenPatched(filePath)) {
164+
return;
165+
}
166+
145167
const originalContent = fs.readFileSync(filePath, 'utf8');
146168
const newFileContent = originalContent.replace(search, replacement);
147169

148170
if (originalContent === newFileContent) {
149171
throw Error(`Could not perform replacement in: ${filePath}.`);
150172
}
151173

174+
writePatchMarker(filePath);
152175
fs.writeFileSync(filePath, newFileContent, 'utf8');
153176
}
177+
178+
/** Marks the specified file as patched. */
179+
function writePatchMarker(filePath) {
180+
shelljs.echo(PATCH_VERSION).to(`${filePath}.patch_marker`);
181+
}
182+
183+
/** Checks if the given file has been patched. */
184+
function hasFileBeenPatched(filePath) {
185+
const markerFilePath = `${filePath}.patch_marker`;
186+
return shelljs.test('-e', markerFilePath) &&
187+
shelljs.cat(markerFilePath).toString().trim() === `${PATCH_VERSION}`;
188+
}

0 commit comments

Comments
 (0)