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

Idea: Add Header to Identify imported names #156

Open
Jamesernator opened this issue Apr 9, 2017 · 5 comments
Open

Idea: Add Header to Identify imported names #156

Jamesernator opened this issue Apr 9, 2017 · 5 comments

Comments

@Jamesernator
Copy link

For libraries with large collections of functions it can be nice to import them in a single declaration e.g.

import { map, filter } from "./some-itertools.mjs"

// vs individual
import map from "some-itertools/map.mjs"
import filter from "some-itertools/filter.mjs"

However with the former this will fetch the entire library even if a lot of it is not used. Basically what would be nice is if there was an additional header that the server could choose to consider when serving a module e.g.

import { map, filter } from "./some-itertools.mjs"

could send an additional header:

Imported-Names: map, filter

which a smart server could choose to respond with only what's needed instead:

export function map() {
    ...
}

export function filter() {
    ...
}

or even respond more simply with something like:

export { map } from "./some-itertools/map.js"
export { filter } from "./some-itertools/filter.js"
@matthewrobb
Copy link

I really like this idea.

@rictic
Copy link

rictic commented Apr 10, 2017

Maybe I'm missing something, but how would this handle multiple files that depend on some-itertools that each use different subsets of the file? Would each bespoke version of some-itertools need to be sent down the wire separately? What if they're using partially overlapping subsets of the exports?

My gut feeling is that this use case is better solved by avoiding very large modules that export tons of things.

@Jamesernator
Copy link
Author

@rictic I could imagine you could aggregate the names from all modules as you navigate the dependency tree, but I definitely see the concern, especially in the case of circular imports.

However I'd still say being able to have collection modules is desirable rather than having 10 different boilerplate declarations:

import { map } from "rxjs/operator/map"
import { take } from "rxjs/operator/take"
import { merge } from "rxjs/operator/merge"
// ... etc
// and imagine how much boilerplate it would be from a CDN:
import { map } from "https://unpkg.com/rxjs@5.3.0/operator/map.js"
import { take } from "https://unpkg.com/rxjs@5.3.0/operator/take.js"
import { merge } from "https://unpkg.com/rxjs@5.3.0/operator/merge.js"
// ... etc

could become something like:

// And this could still maintain the size-sensitive building
import {
    map,
    take,
    merge,
    // ...etc
} from "rxjs/operator" // or something like that

// Or from a CDN
import {
    map,
    take,
    merge,
    // ...etc
} from "https://unpkg.com/rxjs@5.3.0/operator" // or something like that

My reasoning for suggesting something of the form (even if it can't work as I suggested) for the default loader is:

  1. Size-sensitive building is more a concern of internet applications given that page load time can still be a significant factor (especially on mobile) so I thought it would fit better as part of the loader instead of part of JavaScript itself
  2. I wanted it to be transparent on the consumer side of the library especially if they get their data from a CDN, that way if a CDN were to implement it then people could automatically get the benefits for free which is why I didn't want to to simply be part of a custom loader (otherwise every single client who wants size reduction of this form would have to include virtually identical loaders)

I'm very open to suggestions to other methods reducing boilerplate in these sorts of declarations, obviously something like this could improve things but it'd still be a pain:

// Just using import with for the sake of exposition
import with {
    // Some special form of block which is run before normal module execution time
    const a = operator => `https://unpkg.com/rxjs@5.3.0/operator/${ operator }.js`
    // Allow expressions after import within such a block as it's run at a different time
    import { map } from a('map')
    import { take } from a('take')
}

@Jamesernator
Copy link
Author

An alternative I thought of that would be a language level change could be a variant of the export-from statement that tells the engine that if they're not imported then they need not be resolved fetched or evaluated:

// Using static here for exposition to say that these should be loaded *only* if requested
export static { map } from "./operators/map.js"
export static { filter } from "./operators/filter.js"
export static { reduce } from "./operators/reduce.js"
// ...etc

// In another file
import { map, filter } from "rxjs/operators"
// reduce, etc need not be loaded as they were declared to be only fetched/evaluated if actually required.

One downside of this approach (not that they're mutually exclusive) is that you'd still have to send a full file of export static declarations instead of just the ones you need, however this feels fairly acceptable as a declarations file isn't likely to be large anyway.

On the upside is that it would simply work for both consumers and CDNs (whereas with my previous suggestion a CDN would have to be aware of how to serve each module, which might need be defined by metadata in the module). Whereas this approach fully shifts the work to the module developer (who would only need to add a few export-static-from declarations, and in the worst case where the module developer doesn't do this then the module simply continues to work albeit at a higher bandwidth/load time for consumers.

@frog-o
Copy link

frog-o commented Dec 29, 2024

I am confused , would some mind tell me
is not the

export static { map } from "./operators/map.js"

part of the esm standard now or is the portion { map } not

Also can't this already be done ?

I have not used JavaScript enough and find all this hard to follow

Also one of the reason I came here look at(Whatwg/load) issues is I keep have problem with undefine variable and I think it has a lot to do with the loader.

I also like an idea of a header I was reading this (a-brief-journey-through-hell) and I really like the idea of adding A one line statement to a javascript file module

if (typeof(define) !== "function" || define.amd !== true)

that would allow for such a thing
except mind would get it info from package.json which has all of it decency list along with other useful info

so it would loook like this

#my module.mjs
if (typeof(define header) == "json")
import package.json //or something else like package.json5

I am kind of disappoint that the web stand has not imporved.json
some example json not support comments and time variable like amazon .ion does . I was looking at the mime type and I can't find anything like ion.

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

No branches or pull requests

4 participants