diff --git a/bazel/esbuild/index.bzl b/bazel/esbuild/index.bzl index b8ea71cd2..8a9581d6e 100644 --- a/bazel/esbuild/index.bzl +++ b/bazel/esbuild/index.bzl @@ -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( @@ -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 ) diff --git a/bazel/spec-bundling/esbuild.config-tmpl.mjs b/bazel/spec-bundling/esbuild.config-tmpl.mjs index b2198a25b..b4702974f 100644 --- a/bazel/spec-bundling/esbuild.config-tmpl.mjs +++ b/bazel/spec-bundling/esbuild.config-tmpl.mjs @@ -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, }; diff --git a/bazel/spec-bundling/index.bzl b/bazel/spec-bundling/index.bzl index a0352cf2a..02db12727 100644 --- a/bazel/spec-bundling/index.bzl +++ b/bazel/spec-bundling/index.bzl @@ -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") @@ -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], diff --git a/bazel/spec-bundling/test/BUILD.bazel b/bazel/spec-bundling/test/BUILD.bazel index 4c6833c5b..ac5cc0213 100644 --- a/bazel/spec-bundling/test/BUILD.bazel +++ b/bazel/spec-bundling/test/BUILD.bazel @@ -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", @@ -19,7 +22,7 @@ spec_bundle( jasmine_node_test( name = "test", - specs = [ + deps = [ ":test_bundle", ], ) diff --git a/ng-dev/BUILD.bazel b/ng-dev/BUILD.bazel index 424dee207..7800363c8 100644 --- a/ng-dev/BUILD.bazel +++ b/ng-dev/BUILD.bazel @@ -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( diff --git a/ng-dev/utils/resolve-yarn-bin.ts b/ng-dev/utils/resolve-yarn-bin.ts index 503f0bd64..53efc4e95 100644 --- a/ng-dev/utils/resolve-yarn-bin.ts +++ b/ng-dev/utils/resolve-yarn-bin.ts @@ -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'; @@ -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)}, ]; diff --git a/ng-dev/utils/test/BUILD.bazel b/ng-dev/utils/test/BUILD.bazel index 7f6622ff9..3c35de59a 100644 --- a/ng-dev/utils/test/BUILD.bazel +++ b/ng-dev/utils/test/BUILD.bazel @@ -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"], ) diff --git a/ng-dev/utils/version-check.ts b/ng-dev/utils/version-check.ts index 4768c71d0..9a9219370 100644 --- a/ng-dev/utils/version-check.ts +++ b/ng-dev/utils/version-check.ts @@ -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, @@ -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.'); @@ -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] ?? diff --git a/package.json b/package.json index a0cc5b393..940f29dfa 100644 --- a/package.json +++ b/package.json @@ -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", @@ -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", diff --git a/tools/esbuild.bzl b/tools/esbuild.bzl index dc6d9a254..ccee5f074 100644 --- a/tools/esbuild.bzl +++ b/tools/esbuild.bzl @@ -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). @@ -19,7 +30,7 @@ def esbuild(name, platform = "node", target = "node14", deps = [], **kwargs): include_declarations = False, ) - _esbuild( + esbuild_rule( name = name, platform = platform, target = target, @@ -27,31 +38,15 @@ def esbuild(name, platform = "node", target = "node14", deps = [], **kwargs): **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 ) diff --git a/tslint.json b/tslint.json index 0e2043928..971136112 100644 --- a/tslint.json +++ b/tslint.json @@ -8,6 +8,7 @@ true, { "noNamedExports": [ + "@yarnpkg/lockfile", "typescript", "multimatch", "semver",