-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Cannot use -D for @define constant within a module #1601
Comments
Technically the compiler is doing the right thing. According to https://developers.google.com/closure/compiler/docs/js-for-compiler,
I'd prefer going with option 1. We should also update the documentation as ES6 modules are becoming popular. |
Treat @define's as truly global definitions and don't mangle the names. Fixes google#1601.
As I mentioned on the PR, I'm opposed to option 1 as it will block proper scoping of modules and prevent two different versions of a module from being used in the same compile. There's also a couple of other options:
|
Or 3) make it an error to have a define in a module
|
I think that goog.define() will work inside ES6 modules, which is generally preferred over naked @defines anyway since it can also work in uncompiled code. |
goog.define() only works in uncompiled code if you include closure's base.js |
Treat @define's as truly global definitions and don't mangle the names. Fixes google#1601.
I thought of a better way to handle this: during module rewriting, rewrite the define flags in a similar way that rewrite type nodes. |
Here is what I had in mind: -D "path/to/module.js:NAME=1" for the define to be visible outside the module, it would need to be exported separately. Defines in modules should only be allowed on const declarations: /** @define {boolean} */ goog.define also needs to be modified for ES6 modules as they don't know their own name so it is difficult to look them up at runtime. Alternately, we require all @define values to be globally unique but that would eventually going to cause problems. |
Probably worth revisiting this as modules (including ES6 modules) gain popularity. fwiw
There's two issues with the above code:
Ideally we'd have some define mechanism that truly fits with modules, i.e. creates an expression result for the value only. For Closure Library I'd like to add a
imo these module define names still need to be unique. You shouldn't be allowed to reuse them. Keeps the tl;dr need help deciding on what the expected behavior and syntax is. Then we can move to implement. But there's been disagreement between myself, @shicks, and @concavelenz as to what the |
Since we don't have a clear decision here, I'll offer some more bikeshedding. For const FOO = goog.define('path/to/my:FOO', false); The name needn't necessarily be the same as the actual path - it just needs to have a non-identifier character in it, which by convention could be slashes and colons. Otherwise it's an arbitrary globally-unique string. |
@shicks I'd recommend relying on module resolution to locate the file. That handles all the relative/absolute/goog.module issues. |
@shicks not sure I like having ES6 modules have their path as the define and @ChadKillingsworth I think his point is if you take your compiler defs and then build a directory up from where you normally do your defs are broken. But hey, welcome to paths. I think is reasonable. However it might be unreasonable how it works with other flags. I think if you pass In any case its the best we have. I guess if you make your POV that the flag file is another ES6 module in your build directory that can reference others it makes more sense. |
Let's maybe ignore the Closure Library method for now. Thinking further a string constant might be necessary, otherwise how do you resolve the path in the browser? Unless we do |
Am I correct in understanding Since defines are expected to be in global scope, a file containing defines can only be a script, but at the same time it must be included in the compilation which in case of module-managed projects means something has to depend on it which requires it being a module. The two workaround I found so far are Is there a better way currently? Any progress on resolving the problem itself? |
You're correct in your assumptions, and I haven't had time to prioritize this. |
My vote would go to "treat all |
Still want this to be resolved... One more idea how to deal with this; Let |
This maps to internal issue http://b/117789111, which Steve has fixed. @shicks can we close this issue and update the external documentation? You can write: goog.module('my.module');
/** @define {number} */
const MAX_SIZE = goog.define('some.arbitrary.string', 42); with the corresponding flag: |
@lauraharker How does this work with ES modules? With CJS? |
We've made some improvements, but the story is pretty different depending on whether or not you're using Closure Library. TL;DR: With Closure Library
/** @define {number} */
const FOO = goog.define('some.ns.FOO', 1); and then set it from the command line with This has sort of worked in the past, but in an unsupported way: in compiled code it defines a module-local with no global, while in uncompiled code it defined a global. The main breakages that need to be fixed before we can stop exporting the global are based on folks exploiting this inconsistency to change Without Closure LibraryWithout Independent of this, it's still an error to define the same symbol twice. We could revisit that, but I'm not convinced that would be a good idea. |
Whether or not this satisfies the requirements of this issue is unclear to me. |
Doesn't sound like it is working to me 😉 . |
How about something like |
That should be fine - they're all defined in a globally unique way (by passing to the compiler at compile-time). The @define variables are always global by definition, I fail to see the conflict in adding this. |
I've finally managed to find a solution to this that will not throw a /** global.js */
// overrides `goog.define` for NodeJS runtime, where it does not exist
if (typeof goog === 'undefined' && typeof globalThis !== 'undefined') {
globalThis.goog = {
define: (n, v) => v,
};
}
export var PRODUCTION = goog.define('compiler.globals.PRODUCTION', false); Where the compiler is called with |
The super-hacky solution I've come up with for this:
This avoids the use of |
I left a hacky, but working solution above if you want to actually use Hacky but it works while still relying on the compiler, and I also posted a polyfill for |
For the debug build I have special comments like Pro: quicker/easier to write (imho), and needs no |
This was a bit of a pain to get working. The closure compiler appears to include modules even if they are not dependencies of the entry point. It requires some extra work to use @define with ES6 modules. See Closure compiler bug: google/closure-compiler#1601
Repro case:
Things work if you use the mangled name:
The text was updated successfully, but these errors were encountered: