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

fix(ng-dev): yarnpkg lockfile package cannot be bundled with ESM #615

Merged
merged 2 commits into from
Jun 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions bazel/esbuild/index.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,33 @@ def esbuild(
**kwargs
)

def esbuild_esm_bundle(name, **kwargs):
"""ESBuild macro supports an ESM/CJS interop.

Args:
name: Name of the target
**kwargs: Other arguments passed to the `esbuild` rule.
"""

args = dict(
resolveExtensions = [".mjs", ".js"],
outExtension = {".js": ".mjs"},
# Workaround for: https://github.com/evanw/esbuild/issues/1921.
banner = {
"js": """
import {createRequire as __cjsCompatRequire} from 'module';
const require = __cjsCompatRequire(import.meta.url);
""",
},
)

esbuild(
name = name,
format = "esm",
args = args,
**kwargs
)

def esbuild_amd(name, entry_point, module_name, testonly = False, config = None, deps = [], **kwargs):
"""Generates an AMD bundle for the specified entry-point with the given AMD module name."""
expand_template(
Expand Down Expand Up @@ -47,6 +74,7 @@ def esbuild_amd(name, entry_point, module_name, testonly = False, config = None,
testonly = testonly,
deps = deps,
entry_point = entry_point,
format = "iife",
config = "%s_config_lib" % name,
**kwargs
)
3 changes: 0 additions & 3 deletions bazel/spec-bundling/esbuild.config-tmpl.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,5 @@ export default {
conditions: ['es2020', 'es2015', 'module'],
// This ensures that we prioritize ES2020. RxJS would otherwise use the ESM5 output.
mainFields: ['es2020', 'es2015', 'module', 'main'],
// Use the `iife` format for the test entry-point as tests should run immediately.
// For browser tests which are wrapped in an AMD header and footer, this works as well.
format: 'iife',
plugins,
};
6 changes: 3 additions & 3 deletions bazel/spec-bundling/index.bzl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
load("//bazel/esbuild:index.bzl", "esbuild", "esbuild_amd", "esbuild_config")
load("//bazel/esbuild:index.bzl", "esbuild_amd", "esbuild_config", "esbuild_esm_bundle")
load("//bazel/spec-bundling:spec-entrypoint.bzl", "spec_entrypoint")
load("//bazel/spec-bundling:bundle-config.bzl", "spec_bundle_config_file")

Expand Down Expand Up @@ -63,16 +63,16 @@ def spec_bundle(

# Browser tests (Karma) need named AMD modules to load.
# TODO(devversion): consider updating `@bazel/concatjs` to support loading JS files directly.
esbuild_rule = esbuild_amd if is_browser_test else esbuild
esbuild_rule = esbuild_amd if is_browser_test else esbuild_esm_bundle
amd_name = "%s/%s/%s" % (workspace_name, package_name, name + "_spec") if is_browser_test else None

esbuild_rule(
name = "%s_bundle" % name,
testonly = True,
config = ":%s_config" % name,
output = "%s_spec.%s" % (name, "js" if is_browser_test else "mjs"),
entry_point = ":%s_spec_entrypoint" % name,
module_name = amd_name,
output = "%s_spec.js" % name,
target = target,
platform = platform,
deps = deps + [":%s_spec_entrypoint" % name],
Expand Down
7 changes: 5 additions & 2 deletions bazel/spec-bundling/test/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# NOTE: We need to test with the raw jasmine rule here because our default
# repo rule uses spec-bundling as well, with some additional defaults.
load("@npm//@bazel/jasmine:index.bzl", "jasmine_node_test")
load("//bazel/spec-bundling:index.bzl", "spec_bundle")
load("//tools:defaults.bzl", "jasmine_node_test", "ts_library")
load("//tools:defaults.bzl", "ts_library")

ts_library(
name = "test_lib",
Expand All @@ -19,7 +22,7 @@ spec_bundle(

jasmine_node_test(
name = "test",
specs = [
deps = [
":test_bundle",
],
)
3 changes: 3 additions & 0 deletions ng-dev/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ NG_DEV_EXTERNALS = [
# `typescript` is external because we want the project to provide a TypeScript version.
# TODO: Figure out how we want to manage dependencies for the dev-infra tool.
"typescript",
# Package uses `__filename` and `__dirname` and cannot be bundled in ESM. We do not
# intend to provide interop globals for this as it could hide other significant issues.
"@yarnpkg/lockfile",
]

ts_library(
Expand Down
4 changes: 2 additions & 2 deletions ng-dev/utils/resolve-yarn-bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import * as path from 'path';
import which from 'which';

import {isNodeJSWrappedError} from './nodejs-errors.js';
import {parse as parseLockfile} from '@yarnpkg/lockfile';
import lockfile from '@yarnpkg/lockfile';
import {parse as parseYaml} from 'yaml';
import {ChildProcess} from './child-process.js';
import {Log} from './logging.js';
Expand All @@ -33,7 +33,7 @@ export interface YarnCommandInfo {

/** List of Yarn configuration files and their parsing mechanisms. */
export const yarnConfigFiles: ConfigWithParser[] = [
{fileName: '.yarnrc', parse: (c) => parseLockfile(c).object},
{fileName: '.yarnrc', parse: (c) => lockfile.parse(c).object},
{fileName: '.yarnrc.yml', parse: (c) => parseYaml(c)},
];

Expand Down
3 changes: 3 additions & 0 deletions ng-dev/utils/test/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,8 @@ ts_library(

jasmine_node_test(
name = "test",
data = ["@npm//@yarnpkg/lockfile"],
# Same reasoning as in "ng-dev/BUILD.bazel". This package cannot be bundled.
external = ["@yarnpkg/lockfile"],
specs = [":test_lib"],
)
6 changes: 3 additions & 3 deletions ng-dev/utils/version-check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import * as path from 'path';
import * as fs from 'fs';
import {LockFileObject, parse as parseYarnLockfile} from '@yarnpkg/lockfile';
import lockfile from '@yarnpkg/lockfile';
import {
ngDevNpmPackageName,
workspaceRelativePackageJsonPath,
Expand All @@ -34,7 +34,7 @@ export async function verifyNgDevToolIsUpToDate(workspacePath: string): Promise<
try {
const lockFileContent = fs.readFileSync(workspaceDirLockFile, 'utf8');
const packageJson = JSON.parse(fs.readFileSync(workspacePackageJsonFile, 'utf8')) as any;
const lockFile = parseYarnLockfile(lockFileContent);
const lockFile = lockfile.parse(lockFileContent);

if (lockFile.type !== 'success') {
throw Error('Unable to parse workspace lock file. Please ensure the file is valid.');
Expand All @@ -45,7 +45,7 @@ export async function verifyNgDevToolIsUpToDate(workspacePath: string): Promise<
return true;
}

const lockFileObject = lockFile.object as LockFileObject;
const lockFileObject = lockFile.object as lockfile.LockFileObject;
const devInfraPkgVersion =
packageJson?.dependencies?.[ngDevNpmPackageName] ??
packageJson?.devDependencies?.[ngDevNpmPackageName] ??
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"@types/tmp": "^0.2.1",
"@types/uuid": "^8.3.1",
"@types/yargs": "^17.0.0",
"@yarnpkg/lockfile": "^1.1.0",
"browser-sync": "^2.27.7",
"clang-format": "1.8.0",
"prettier": "2.6.2",
Expand Down Expand Up @@ -105,7 +106,6 @@
"@types/wait-on": "^5.3.1",
"@types/which": "^2.0.1",
"@types/yarnpkg__lockfile": "^1.1.5",
"@yarnpkg/lockfile": "^1.1.0",
"chalk": "^5.0.1",
"cli-progress": "^3.7.0",
"conventional-commits-parser": "^3.2.1",
Expand Down
47 changes: 21 additions & 26 deletions tools/esbuild.bzl
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
load("//bazel/esbuild:index.bzl", _esbuild = "esbuild", _esbuild_config = "esbuild_config")
load(
"//bazel/esbuild:index.bzl",
_esbuild = "esbuild",
_esbuild_config = "esbuild_config",
_esbuild_esm_bundle = "esbuild_esm_bundle",
)
load("//bazel:extract_js_module_output.bzl", "extract_js_module_output")
load("@build_bazel_rules_nodejs//:index.bzl", "generated_file_test")

esbuild_config = _esbuild_config

def esbuild(name, platform = "node", target = "node14", deps = [], **kwargs):
def _esbuild_devmode_prioritize(
esbuild_rule,
name,
platform = "node",
target = "node14",
deps = [],
**kwargs):
# TODO: Rename once devmode and prodmode have been combined.
# This helps speeding up building as ESBuild (used internally by the rule) would
# request both devmode and prodmode output flavor (resulting in 2x TS compilations).
Expand All @@ -19,39 +30,23 @@ def esbuild(name, platform = "node", target = "node14", deps = [], **kwargs):
include_declarations = False,
)

_esbuild(
esbuild_rule(
name = name,
platform = platform,
target = target,
deps = [":%s_devmode_deps" % name],
**kwargs
)

def esbuild_esm_bundle(name, **kwargs):
"""ESBuild macro that prioritizes ESM output and supports an ESM/CJS interop.

Args:
name: Name of the target
deps: List of dependencies
**kwargs: Other arguments passed to the `esbuild` rule.
"""

args = dict(
resolveExtensions = [".mjs", ".js"],
outExtension = {".js": ".mjs"},
# Workaround for: https://github.com/evanw/esbuild/issues/1921.
banner = {
"js": """
import {createRequire as __cjsCompatRequire} from 'module';
const require = __cjsCompatRequire(import.meta.url);
""",
},
def esbuild(**kwargs):
_esbuild_devmode_prioritize(
_esbuild,
**kwargs
)

esbuild(
name = name,
format = "esm",
args = args,
def esbuild_esm_bundle(**kwargs):
_esbuild_devmode_prioritize(
_esbuild_esm_bundle,
**kwargs
)

Expand Down
1 change: 1 addition & 0 deletions tslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
true,
{
"noNamedExports": [
"@yarnpkg/lockfile",
"typescript",
"multimatch",
"semver",
Expand Down