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

Weird issues with externs #509

Open
sgammon opened this issue Jan 17, 2021 · 2 comments
Open

Weird issues with externs #509

sgammon opened this issue Jan 17, 2021 · 2 comments

Comments

@sgammon
Copy link
Contributor

sgammon commented Jan 17, 2021

When trying to use Google Maps externs, I get some very strange behavior that doesn't seem to have a remedy except for a bug fix.

consider the following property initializer in an arbitrary JS class and accompanying Bazel targets:

WORKSPACE:

# ...

http_file(
    name = "com_google_gmaps",
    downloaded_file_path = "gmaps-extern.js",
    urls = ["https://raw.githubusercontent.com/google/closure-compiler/db22839eee034c1b302879f64a2984407459b0f2/contrib/externs/maps/google_maps_api_v3_43.js"],
)

# ...

BUILD.bazel:

closure_js_library(
    name = "gmaps",
    srcs = ["@com_google_gmaps//file"],
)

closure_js_library(
    name = "some-thing",
    srcs = ["some-thing.js"],
    deps = [":gmaps"],
)

closure_js_binary(
    name = "some-js",
    deps = [":some-thing"],
    dependency_mode = "PRUNE_LEGACY",
    entry_points = ["repro.some_thing"],
)

some-thing.js:

goog.module('repro.some_thing');

class SomeThing {
    constructor() {
      /**
       * Holds a reference to the managed Maps marker.
       *
       * @const
       * @type {!google.maps.Marker}
       * @private
       */
      this.marker_ = new google.maps.Marker({});
    }
}

simple, right? however, Closure Compiler fails to recognize the symbols as externs:

(17:00:49) INFO: Current date is 2021-01-16
(17:00:49) INFO: Analyzed target //:some-js.js (0 packages loaded, 0 targets configured).
(17:00:49) INFO: Found 1 target...
(17:00:56) ERROR: /...project path.../BUILD.bazel:207:7: Compiling N JavaScript files to some-js.js failed (Exit 1): ClosureWorker failed: error executing command bazel-out/host/bin/external/io_bazel_rules_closure/java/io/bazel/rules/closure/ClosureWorker @@bazel-out/darwin-fastbuild/bin/some-js.js-0.params
some-thing.js:12: ERROR - could not determine the type of this expression
    this.marker_ = new google.maps.Marker({});
                       ^
  ProTip: "JSC_UNKNOWN_EXPR_TYPE" or "missingSourcesWarnings" or "reportUnknownTypes" can be added to the `suppress` attribute of:
  //:some-thing
  Alternatively /** @suppress {reportUnknownTypes} */ can be added to the source file.

1 error(s), 0 warning(s), 97.6% typed

Target //:some-js failed to build
Use --verbose_failures to see the command lines of failed build steps.
(17:00:56) INFO: Elapsed time: 6.756s, Critical Path: 6.29s
(17:00:56) INFO: 3 processes: 2 internal, 1 worker.
(17:00:56) FAILED: Build did NOT complete successfully

Diagnosis

Okay, so, let's start in the extern (google_maps_api_v3_43.js).

google_maps_api_v3_43.js:4845:

/**
 * @param {google.maps.MarkerOptions=} opts
 * @extends {google.maps.MVCObject}
 * @constructor
 */
google.maps.Marker = function(opts) {};

So it's in the extern. So maybe the extern isn't getting loaded by rules_closure / JsChecker? Let's check:

> grep gmaps bazel-out/darwin-fastbuild/bin/some-js.js-0.params
bazel-out/darwin-fastbuild/bin/tools/externs/libs/gmaps.pbtxt
tools/externs/libs/gmaps.js

So it's making it into the build ☹️

To make matters even more interesting, with the Firebase externs, I had to change the firebase = {}; @namespace to const = for it to work:

firebase-externs.js:

/**
 * @fileoverview Firebase namespace and Firebase App API.
 * @externs
 */

/**
 * <code>firebase</code> is a global namespace from which all the Firebase
 * services are accessed.
 *
 * @namespace
 */
const firebase = {};

No idea why, and I'm still suspicious of this change (i.e. maybe it just busted a build cache somewhere), but changing var = to const = fixed my extern issues with Firebase. Trying that with Google Maps wasn't fruitful:

google_maps_api_v3_43.js:4845:

/**
 * @fileoverview Externs for the Google Maps v3 API.
 * @see https://developers.google.com/maps/documentation/javascript/reference
 * @externs
 */

/**
 * @const
 * @suppress {const,duplicate,strictMissingProperties}
 */
const google = {};

Yields:

(17:17:02) INFO: Current date is 2021-01-16
(17:17:02) INFO: Analyzed target //:some-js.js (0 packages loaded, 0 targets configured).
(17:17:02) INFO: Found 1 target...
(17:17:08) ERROR: /Volumes/VANTAGE/platform/cookies/frontend/BUILD.bazel:207:7: Compiling N JavaScript files to some-js.js failed (Exit 1): ClosureWorker failed: error executing command bazel-out/host/bin/external/io_bazel_rules_closure/java/io/bazel/rules/closure/ClosureWorker @@bazel-out/darwin-fastbuild/bin/some-js.js-0.params
(gmaps-extern):27: ERROR - Illegal redeclared variable: google
const google = {};
      ^
  ProTip: "JSC_REDECLARED_VARIABLE_ERROR" can be added to the `suppress` attribute of:
  //:gmaps

1 error(s), 0 warning(s)

Target //:some-js.js failed to build
Use --verbose_failures to see the command lines of failed build steps.
(17:18:26) INFO: Elapsed time: 1.793s, Critical Path: 1.33s
(17:18:26) INFO: 3 processes: 2 internal, 1 worker.
(17:18:26) FAILED: Build did NOT complete successfully

This is already weird because I don't have a google = anywhere in my code (in an extern or otherwise). As far as I can tell, none of my upstream dependencies do, either. But if I add that suppression:

# ...
ERROR: Bad --suppress value: JSC_REDECLARED_VARIABLE_ERROR
# ...

Going back to our Google Maps sample, what's even more interesting is, it will find certain symbols in the gmaps extern, for instance:

  • google.maps.LatLng
  • google.maps.Point
  • google.maps.Map (it seems to find this sometimes)

So, I'm stuck at this point, because (1) there appears to (maybe) be a builtin google that I cannot re-define, because of (2) a warning from JSC that I cannot suppress or (3) perhaps an inability to re-declare this namespace for my use.

Any ideas? Is anyone else experiencing the same thing?

@gkdn
Copy link
Collaborator

gkdn commented Jan 20, 2021

there appears to (maybe) be a builtin google that I cannot re-define

Could you reproduce the issue without rules_closure and file a bug with Closure Compiler?

a warning from JSC that I cannot suppress

IIRC, rules_closure doesn't let you suppress, and I'm not sure what criteria used there but this warning sounds something that you don't want to suppress.

@gramic
Copy link
Contributor

gramic commented May 19, 2023

I had the same issue today and even that the cause of the problem was not found, the solution was to use --env=CUSTOM for the compiler, so the default externs are disabled. Then adding only the externs that were needed.

Here is the valuable issue #81 that gave me the hint for this solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants