ecmascript-more-export-from
                                
                                
                                
                                    ecmascript-more-export-from copied to clipboard
                            
                            
                            
                        import {x,y} as v from "mod";
I'd like to suggest an additional as v extension on the import side.
The syntax would be:
import {x,y} as v from "mod";
The semantics would be to create a plain object v and populate it with properties x, y (etc.) resulting in v = {x:x, y:y} (or v = {vx:x, vy:y} if x/y are also aliased).
The reasoning is to facilitate static analysis and tree-shaking when plucking individual exports from libraries like lodash.  If I import _ from "lodash"; then I get all of lodash.  If I import {x, y} from "lodash"; (where x and y are specific lodash functions like debounce or omit) then a smart loader or builder can ensure that only those functions and their dependencies are included in the resulting page or build.
The current {x, y} already works, but it clutters my module with names that I'd rather encapsulate.  I can use {x as _x, y as _y} (or whatever renaming scheme makes sense), but this is verbose and still produces a lot of top-level names.  If I could import {x, y} as _ from "lodash"; then I'd have a top-level _ variable with everything I wanted and nothing I didn't.
@nlwillia the main issue is that {} in import and export statements is not destructuring, it is just a descriptor, and changing that is a fundamental shift.
It would still be hoisted, and the properties would still be views, so it's not an attempt to conflate imports with destructuring but to introduce selective structuring to keep plucked names out of the top-level namespace.
From the perspective of symmetry, an export {x,y} as name; syntax could also be a useful shorthand for const name = {x,y};export {name};
It's syntactic sugar, but I think that as we shift to the ES6+ model for modularity this sort of selective import concern is going to be increasingly important to facilitate cleanly. (This proposal project looked like a good place to discuss import concerns, but if there's a better place for it, let me know. And I should make it clear that I'm not hung up on this particular mechanism...it's just something that seems like it could be improved and I'd be glad to hear other suggestions.)
Thanks for the suggestion and the idea! I agree with the problem and your solution is pretty interesting. I'll take it into consideration!
@caridy Perhaps this type of syntax could produce a binding namespace object? In fact I would love to be able to declare binding namespaces outside of modules!
const foo.bar = "baz!"; //  generates an exotic namespace object bound to 'foo' in the current scope
                                    
                                    
                                    
                                
my personal opinion here is: exporting an object with a well defined shape is not a primary use-case, and in fact I will probably discourage its use as part of your module API, why not just adding more named exports? Remember, our goal with the module grammar is to make it easier for common, well defined cases, and not so easy for those bad patterns.
Something that was not clear to me (but probably should have been) when I suggested this is that static analysis can't just go by exports and imports because a loaded module could have external side-effects that it does not export.  This means that even modules like lodash-es that are optimized for selective usage are having trouble getting the full benefit with some syntax forms.  That will hopefully improve in time, but it's a lot harder than it would be if there were a way of declaring a "weak reexport" for a child module known to be safe for static usage-based elimination.
@caridy just independently posted the same suggestion to @leebyron with same reasoning:
https://gist.github.com/philholden/25618771eed1e0fd58437f7af2fb8005
And he made me aware of your issue. I am finding this pattern would be very helpful in Redux apps as I struggle to find different names for constants and actions when most of the time they are doing CRUD. So I want to be able to do:
// todo-actions.js
export const CREATE = 'TODO.CREATE'
export const UPDATE = 'TODO.UPDATE'
export const CREATE_SUCCESSFUL = 'TODO.CREATE_SUCCESSFUL'
export const UPDATE_SUCCESSFUL = 'TODO.UPDATE_SUCCESSFUL'
//todo-reducer.js
import { CREATE_SUCCESSFUL, UPDATE_SUCCESSFUL } as TODO from './todo-actions'
reduce(state, action) {
  switch(action) {
    case TODO.CREATE_SUCCESSFUL: ...
    case TODO.UPDATE_SUCCESSFUL: ...
  }
}
In reality I would probably namespace actions further with npm-package-name to give globally unique actions:
export const CREATE = '@philholden/todo-redux/TODO.CREATE'
                                    
                                    
                                    
                                
@philholden I can definitely give more details about why I think this is
- namespaces are 1-1 mapping to existing module records. Each module record contains a namespace object that implements sort-of a proxy, with a 
[[Get]]internal slot described here: https://tc39.github.io/ecma262/#sec-module-namespace-exotic-objects-get-p-receiver - this proposal will requires the creation of arbitrary namespace objects, in the example above, 
TODOwill have to be a namespace object of some sort since its members can't be mutated from consumers. These namespace exotic objects are not particularly expensive IMO, but they are not as lightweight as regular objects. - accessing a member of a namespace is a very expensive operation IMO, as you can see in here, for every 
[[Get]]action on a namespace, there will be a lookup process of the named export to locate the final module that export the primitive value, then aGetBindingValueon the Environment Record of the exporter, and this will happen on every access. Obviously, with the time, engines will optimize this process, they always do, but for now, this is expensive. 
A couple of questions:
- what will be the reflective api for such new grammar?
 - can you re-export one of these namespaces? today you can only do 
export * from "foo". 
@caridy Thanks for reply.
For your two questions I've no strong opinions. I am not sure what the reflective API is. I have not used reflection yet in JS so might not be qualified to comment. Or do you just mean export? In which case probably the same as @nlwillia:
From the perspective of symmetry, an
export {x,y} as name;syntax could also be a useful shorthand forconst name = {x,y};export {name};
However if the import is exotic the export should be too. The alternative would be to have {} as and [] as being a kind of destructured import that immediately assigns import things to a regular array or object. This is fine for my usecase but inconsistent with the way * as works.
So probably the most consistent thing to do is have them being exportable exotic objects. But for the time being I only see import {} as as being useful for tree shaking, I cannot see a strong use case for export {} as.
Without export { add, remove } as foo we can do: export const foo = { add, remove }
But for import { add, remove } as foo from './foo' we need to do this to get the same functionality:
import {
  add as fooAdd,
  remove as fooRemove
} from './foo'
const foo = {
  add: fooAdd,
  remove: fooRemove
}