-
Notifications
You must be signed in to change notification settings - Fork 21
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
Resolve (external) paths when bundling #68
Comments
Here is an example: https://github.com/yahoo/react-intl, where it depends on pkgs like |
@caridy I like the |
The idea was proposed by @wycats a while ago, we have been using it in FormatJS project (all packages), and we have discussed it with the modules champions at TC39 as a way to signal an entry point for NPM packages that contains an ES6 distro. Lastly, in december we get a chance to discussed it with @othiym23, and he is OK with it, although NPM does ignores it (for now). Email me (caridy at gmail dot com) and I can share the link to the original doc. |
I can guarantee that npm will never use |
Can this also be supported in the non-bundling case? Use case: Suppose you write a module |
Some progress on this front - have opened PR #99. It basically works as planned: esperanto.bundle({
base: 'src',
entry: 'main.js',
resolvePath: function ( importee, importer ) {
// return a string representing the path, or a promise
// that resolves to same
}
}).then( ... ); As a starting point, magic-string (one of Esperanto's dependencies) is now using The magic-string build definition includes a function that uses node-resolve to find the package and replace {
resolvePath: esperanto.useJsnextMain // or something less ugly
} ...but for now it's a manual process. Will probably try this out in a few more places before merging the PR, but if anyone has feedback in the meantime then shout. @mmun I'm not sure you mean by supporting this in the non-bundling case - if external libs are involved aren't we bundling by definition? Could you elaborate? |
awesome! Definitely not One note about |
@mmun @Rich-Harris: this use case is easy to explain if you compare a particular workflow to node/npm. Say you have a two libraries
And now make changes in This is easy in node because of shared module system and resolver. In Emberland, at least, this workflow is vary painful. We author pretty much everything in ES6 and the platform as a whole moves quickly, requiring updates to many smaller libraries at once. There are other ways to get this workflow working, but they fail the Just Works™ test. |
Further update: Esperanto itself is now using this to bundle magic-string and vlq as part of the browser build (which basically exists for the sole purpose of esperantojs.org - see esperanto.browser.js). Going through this dogfooding process uncovered one bug, and served to demonstrate that it makes much more sense to use relative paths for internal modules (one of magic-string's internal files referred to Other than that, it seems to work pretty well - though it's not (and is not intended to be) a replacement for browserify/webpack/jspm, since it doesn't do various things like deduplication. Maybe that will become important in the future, though I don't see it as an immediate priority.
Thanks for explaining that, it's relevant to something I'm hoping to get round to shortly. We use d3 from time to time, and it's a fairly big library. Since we only ever use a tiny part of it, it would be good to have an ES6 fork of it and replace this... import d3 from 'd3';
var layout = d3.layout.force()... ...with... import forceLayout from 'd3/layout/force';
var layout = forceLayout()... ...but given what you say, that's probably not the best approach, and we need to do something more like this: // d3/index.js
import layout_force from './layout/force';
import geo_projection from './geo/projection'; // etc
...
export { layout_force, geo_projection, ... };
// app.js
import { layout_force } from 'd3'; Have I understood that correctly? I'm not totally sure how I feel about it - I agree with the point about refactoring hazard, but it does presumably mean that all the other imports in @mmun @trek Ah, I think I understand, the situation you want is this: building |
@Rich-Harris Yes, exactly. Re: The reason this breaks down in Node is that paths are always referenced relative to the root of the module and not relative to the module's For example, Handlebar's main is import Visitor from "handlebars/compiler/visitor"; This would fail in Node if directly transpiled to Like Caridy said, small modules with flat exports are generally better. That said, not not all existing ES6 code is structured that way and there are arguments in favor of paths ( |
Yes, you did! |
In short, we want to transpile node modules written in ES6 that depend on node modules written in ES6. |
@mmun which is a very different idea than I think most people have for module transpilation. The current practice seems to assume each library author will have already transpiled (using the transpiler of their choice) from ES6 modules and/or other features into ES5 in some module flavor. Consumers of those libraries (who are also library authors) can author in ES6, but will consume external dependencies in ES5 and rely on CJS/AMD loader semantics. This all seems good, but there's a lot of value in letting an application developer delay transpilation until just the moment of publication and use their preferred toolchain. That's probably one of our main use cases. |
@trek Yes, exactly. That blog post works great if you want to write your module in ES6 and compile it to CJS as a pre-publish step. It assumes that the module is intended to be used in a CJS environment (or transpiled through Browserify). There isn't a way to build up a tree of ES6 source across several NPM packages and compile directly to, say, AMD. |
@trek @mmun that's what we are aiming for with this. Few notes:
|
This is great! I’m so glad I stumbled across it. I’ve been oh-so-painfully trying to piece together a usable workflow for publishing and consuming small and simple ES6 modules via npm that also can do the CJS/AMD/window.global dance for others, and have felt awfully sympathetic towards @trek’s “Emo Hellscape” sentiment. I resorted to a terrible hack for one module (which only has a single dependency) where I set esperanto’s From my perspective, having the Thanks for this very useful project and to all for charting a way through this murky mess of mystery and madness. |
Closing this now that Rollup is taking over from Esperanto (#191). Rollup searches |
This discussion started on #59 (comment) but I think it's probably better considered as a separate issue.
Right now, all non-relative import paths are resolved relative to
options.base
(orprocess.cwd()
, if that option is missing), and treated as external modules if they can't be found. (see also #31)That excludes the possibility of having e.g. a separate
vendor
folder, or bundling modules found innode_modules
. (True, those external dependencies typically won't be ES6 modules, and Esperanto only knows how to read ES6 modules. But @caridy mentions some valid use cases.)There are two (possibly complementary) solutions:
resolvePath
functionpaths
config, where module IDs are mapped to paths (relative tobase
, or absolute):The text was updated successfully, but these errors were encountered: