-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Avoiding pollution of environment's namespace #3338
Comments
To be clear, this is not a bug, it's - at best - a suggestion (cannot add label myself otherwise would have done it already) that probably needs refinement. |
You could do that with a build system. Example: var gulp = require('gulp');
var ts = require('gulp-typescript');
var header = require('gulp-header');
var footer = require('gulp-footer');
gulp.task('default', function() {
return gulp.src('lib/**/*.ts')
.pipe(ts())
.pipe(header('(function(){'))
.pipe(footer('})();'))
.pipe(gulp.dest('release'));
}); That will place the code between |
@ivogabe ...which is exactly what I've meant by
Btw, thanks for your excellent work on the gulp plugin for TS, I use it for all my TS projects, works great! However, while global namespace isn't changed, I still need an "entry point" to my code, if I just wrap it in IIFE, I can't get to it any more 😄 I would need code very similar to what TS emits itself - need to create one object which represents my own "namespace", send that into IIFE and place everything in that (instead in This last step in fact requires that TS compiler participates, so what I've said - and you unless I'm missing something - doesn't actually hold, I cannot (trivially) resolve this with a custom build step. If I am missing something obvious, please let me know. IOW, I want that TS pretends that I've written For a bit more context, please see my comment here: #2923 (comment) |
You can wrap your code in |
@ivogabe Which is also what I've implied by
I should have been more explicit. I started writing how this will not work still, but then starting executing code mentally and now I'm not sure any more 😄 Let me try in a test project. Also, don't forget that wrapping is 'easy', I need to preserve sourcemaps, and for that I need gulp plugins which can take sourcemaps from a previous transformation step and modify so that the next one is still valid (hopefully the plugins you've mentioned are compatible with gulp-sourcemaps plugin). |
@ivogabe I don't see how the proposed solution would work. For a trivial case where I have two empty classes (in TS), they both become local variables of the wrapper I definitely think we need TS compiler to participate here. Or, I could of course add |
@ivogabe If you look at my original example (with dummy classes You will see that adding But then we come back to ceremony 😄 Adding |
Missed that, sorry. You're right about the source maps, gulp-header doesn't support source maps, but there is an open issue (gulp-community/gulp-header#7) for it. If I'm not mistaken the Would it be a solution to add everything to a private namespace and create a public namespace that will export some classes? Example: module myLibPrivate {
class A {}
class B {}
}
module myLib {
export import B = myLibPrivate.B;
} |
This sounds excessively complex for such a simple case. The main issue here is the abuse of Based on several discussions I've seen here this appears to be a pain point for quite a few devs out there, I'm surprised Microsoft hasn't already done something about it. Ultimately, having 'namespace' then having to 'export' things only to satisfy compiler isn't too bad and if someone from TS team confirms that there are no plans to support "my" scenario I guess I'll have to go that route, I opened this issue to find out if there's any chance of having support from TS or should I do best with what we have. |
@ivogabe Ultimately, when I think about the current solution, the only thing that irritates me is that I need to export things which I don't potentially want to export. Looking at my example with Of course the best would be to have a compiler flag which would implicitly wrap everything, which is equivalent to wrapping everything in a |
We have talked about this as a self-executing-module. basically emitting the code with some |
@mhegazy Yes, yes, yes! 👍 👍 👍 Exactly. Will not work for some people, but will work for vast majority of simple to medium sized projects. I just realized the reason you require exporting a class one derives from - when you don't merge declarations into a single IIFE, you're obliged to do this because you emit separate IIFE for each TS file, so the derived class cannot see the base class unless base is exported. The problem disappears when you merge all declarations into a single IIFE. So you tentantively plan on doing this? May I be so bold to inquire at least about estimated complexity of this, if not timing? |
@mhegazy You would of course need a way to specify the "namespace" to put the names into, so just --m sfx would not be enough (I'm all for single additional switch, whichever way it is implemented). It's understood that the same thing should be achievable through |
why would you need a namespace? i am thinking of something that is not exported, i.e. not imported by any one, it is more of a side-effect-only-module; consider something like like the ts compiler for instance, it has something like; module ts {
....
}
ts.executeCommandLine(ts.sys.args); this would emit as: (function() {
var ts = ...
ts.executeCommandLine(ts.sys.args);
})(); there is nothing visible from outside, nor does it consume any other modules from the environment.. |
I see what you're saying, we're not talking about the same scenario. I do want to use stuff I've built from the "outside", and I'm not against using the newly added Let's see on a concrete example, the one I've used before
So my intention is to export Building this today with --out mylib.js results in compilation error. The only reason for error as far as I can understand is that emitter cannot create correct code if each file's code is wrapped in a separate IIFE, which is the case today. Adding If you merged things into a single IIFE, this should compile and work like a charm, no? Only Alternatively, you could also export everything given a "namespace" (my original ask), using the same approach - no exports (but everything is exported implicitly), no namespaces (just a single one given on a command line or in |
I think i see what you mean. I believe the change needed here is for the compiler to support bundeling for external modules, and then you would use ES6 module style exports by doing something like:
then the compiler would bundle all your modules to give you a single .js file that contains all the three files, and use |
@mhegazy If you look at my example, both I actually don't want any of the I have three classes, one needs to be visible after compilation, two don't. I don't care what the mechanism is, but a combination of Better yet, would you prefer if I used The Besides, your last example adds so much noise (including |
You are looking for an I see your point, but we are in the JS realm here, and compilation units are not well defined in JS as they are in C# for instance (with .dlls being non-modifiable project outputs); also function closures (namespaces) and modules (ES6 modules are now the standard) are existing common JS modularity patterns. There is already support for what you are asking for. just define all your classes/functions in one module/namespace closure and then your done; if you want to define a class per file, and do not use modules, you would need to make them accessible. changing this behavior now would be a huge breaking change that we can not take, and adding a flag to switch the visibility rule would result in forking the language, and that is something that we can not do either. Whether to use export or public is style question, TC39 opted for |
@mhegazy Yes, I am looking at the OK, if this is a huge undertaking, then I'll just put everything in a Out of curiosity, why wouldn't it be possible to support my scenario where I did annotate classes with Seeing how I'll have to now go back and annotate almost all of my classes, I'd like to do that as soon as |
The only problem is that each namespace introduces a lexical scope, and captures variables defined in this scope. merging multiple of these scopes means you have to resolve name conflicts, and rename things, in addition it changes the capturing rules.
We usually leave releases to stabilize for a few weeks before they are out. We have no more features for the release, just bugs, so should not be long. stay tuned :) |
OK, thanks for the info. Let me "help" by closing this issue then 😉 |
This is somewhat related to #2923, but I'm deliberately opening a separate item because the discussion there has abruptly stopped and more importantly I don't think we're on the right track for the issue at hand.
Let's restate the issue differently: imagine a simple TS project which uses no modules or namespaces, because it's really annoying to export/import almost every class in the project. It's not a library other people will use, it's just something I use for my own site(s). I use the feature of the TS compiler to produce a single JS file and reference it from my HTML5 page(s).
However, I don't like the fact that my 'classes' are polluting the global namespace of the browser environment (had I used the project for node/server side development, the result would be similary unpleasant).
Every discussion around this issue leads (inevitably?) to
modules
ornamespaces
, but more I think about this more it seems to me we're not on a right track.While
modules
and/ornamespaces
do allow for quite fine-grained level of control regarding visibility of 'classes', for the simple case I simply want everything visible, but I don't want it in a global namespace of the environment, I want to separate it so I don't produce clashes with other scripts running in the same environement/page. IOW, inside my project everything is 'public', outside too (I'd rather make everything visible than export/import all the time) but not in a global namespace of the environment.Would it be at all reasonable to expect the TS compiler to support this scenario through a flag or option in
tsconfig.json
the final result being identical to regular compilation but wrapping everything in a IIFE while preserving source maps info? It's understood that this option would effectively 'deactivate' any and all notions ofmodules
/namespaces
(it would be invalid to use the two at the same time).Or should I assume this will never be implemented and look into wrapping the final result myself through a custom build step (which should be possible but is slightly irritating to do when one uses sourcemaps as they will be invalidated by wrapping)?
The text was updated successfully, but these errors were encountered: