{"action":"created","issue":{"url":"https://api.github.com/repos/jsforum/jsforum/issues/5","labels_url":"https://api.github.com/repos/jsforum/jsforum/issues/5/labels{/name}","comments_url":"https://api.github.com/repos/jsforum/jsforum/issues/5/comments","events_url":"https://api.github.com/repos/jsforum/jsforum/issues/5/events","html_url":"https://github.com/jsforum/jsforum/issues/5","id":113078483,"number":5,"title":"jsnext:main – should we use it, and what for?","user":{"login":"Rich-Harris","id":1162160,"avatar_url":"https://avatars.githubusercontent.com/u/1162160?v=3","gravatar_id":"","url":"https://api.github.com/users/Rich-Harris","html_url":"https://github.com/Rich-Harris","followers_url":"https://api.github.com/users/Rich-Harris/followers","following_url":"https://api.github.com/users/Rich-Harris/following{/other_user}","gists_url":"https://api.github.com/users/Rich-Harris/gists{/gist_id}","starred_url":"https://api.github.com/users/Rich-Harris/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Rich-Harris/subscriptions","organizations_url":"https://api.github.com/users/Rich-Harris/orgs","repos_url":"https://api.github.com/users/Rich-Harris/repos","events_url":"https://api.github.com/users/Rich-Harris/events{/privacy}","received_events_url":"https://api.github.com/users/Rich-Harris/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":4,"created_at":"2015-10-23T18:48:06Z","updated_at":"2015-10-24T12:22:57Z","closed_at":null,"body":"This is a follow-up to [this Twitter conversation](https://twitter.com/RReverser/status/657601878214184964):\r\n\r\n## Exposition\r\n\r\nIn CommonJS packages, it's common to have a `main` field in your package.json that tells Node.js or Browserify (etc) where to find the code:\r\n\r\n```js\r\n{\r\n  \"name\": \"some-package\",\r\n  \"main\": \"lib/some-package.js\"\r\n}\r\n```\r\n\r\nNowadays, thanks to Babel, it's increasingly common to author in ES6/7 and use a prepublish hook to generate distributable files:\r\n\r\n```js\r\n{\r\n  \"name\": \"some-package\",\r\n  \"main\": \"dist/some-package.js\",\r\n  \"scripts\": {\r\n    \"build\": \"babel src --out-dir dist\",\r\n    \"prepublish\": \"npm run build\"\r\n  }\r\n}\r\n```\r\n\r\nSo far so good. But the `dist` file must be CommonJS or UMD, otherwise nothing can use it. **That means we're missing an opportunity**, because ES6 modules are better in lots of important ways, particularly when it comes to making efficient bundles for use in the browser. (See [The Importance of `import` and `export`](http://benjamn.github.io/empirenode-2015/#/) by @benjamn if you need persuading.)\r\n\r\nUnfortunately, we can't just create a better UMD block that incorporates ES6 imports and exports, because in engines that don't support ES6 modules (all of them), that's a syntax error. So package authors can't distribute ES6 modules without making their packages incompatible with everything.\r\n\r\n\r\n## Enter `jsnext:main`\r\n\r\nThere is a proposed solution to this problem – `jsnext:main` – which, like `main`, indicates the package's entry point, except that it uses `export` instead of `module.exports`. This is great, because it means that CommonJS/UMD distributable files can co-exist with ES6 distributable files. In the future, once everyone supports ES6 imports and exports, we can simply ditch the CommonJS/UMD stuff.\r\n\r\nBut does `jsnext:main` mean 'entry point written with potentially unsupported ES6/7 features', or 'entry point that runs in existing engines, except for the `import`/`export` statements'? It's unclear. It *sounds* as though you can use ES6/7 features, **the assumption being that it points to your source code**, and that a consumer (such as a bundler) takes responsibility for transpiling it (e.g. with Babel):\r\n\r\n```js\r\n{\r\n  \"main\": \"dist/some-package.js\",\r\n  \"jsnext:main\": \"src/index.js\"\r\n}\r\n```\r\n\r\nBut that's problematic. What if `src/index.js` uses stage 0 features? `some-package` might have a build process that transpiles those features, but does that mean that all consumers of `some-package` have to be similarly equipped? (Yes, .babelrc makes that *possible*, but it's still a weird and brittle process, and it may become rather more complex with Babel 6.)\r\n\r\n**A better solution**: `jsnext:main` could instead refer to an ES6-module entry point that is otherwise ready to use:\r\n\r\n```js\r\n{\r\n  \"main\": \"dist/some-package.cjs.js\",\r\n  \"jsnext:main\": \"dist/some-package.es6.js\"\r\n}\r\n```\r\n\r\nPrepublish hooks make this stuff very straightforward to set up, and it means that everyone can use your package, and no-one needs to worry about your source code – they're only ever dealing with code that is ready to distribute. It's a very simple solution to the problem of serving CommonJS/UMD and ES6 builds simultaneously.\r\n\r\nBut the 'jsnext' part of `jsnext:main` *is* confusing. I'd suggested changing it to something less ambiguous, but would that just confuse people even more?\r\n\r\n\r\n## Does it go far enough?\r\n\r\n@RReverser [thinks not](https://twitter.com/RReverser/status/657583571478024192), and argues that engines/bundlers/whatever should be able to select different files based on feature detection. I have no idea exactly how that would work but I'm eager to hear more.\r\n\r\n\r\n## In summary\r\n\r\n* We badly need a way for package authors to make their packages available as both CommonJS/UMD and ES6. Unless there's a way to transition from one to the other, we'll never be able to move past the legacy module formats, even when most widely-used engines support ES6 modules\r\n* `jsnext:main` is one possible solution, though it's ambiguous. Personally I think that if we use it, it should be used to point to ready-to-use (other than `import`/`export`) distributable code, *not* source code that still needs to be run through Babel\r\n* We could go even further and have multiple entry points based on feature detection\r\n\r\n\r\nAll thoughts welcome. Thanks"},"comment":{"url":"https://api.github.com/repos/jsforum/jsforum/issues/comments/150803986","html_url":"https://github.com/jsforum/jsforum/issues/5#issuecomment-150803986","issue_url":"https://api.github.com/repos/jsforum/jsforum/issues/5","id":150803986,"user":{"login":"RReverser","id":557590,"avatar_url":"https://avatars.githubusercontent.com/u/557590?v=3","gravatar_id":"","url":"https://api.github.com/users/RReverser","html_url":"https://github.com/RReverser","followers_url":"https://api.github.com/users/RReverser/followers","following_url":"https://api.github.com/users/RReverser/following{/other_user}","gists_url":"https://api.github.com/users/RReverser/gists{/gist_id}","starred_url":"https://api.github.com/users/RReverser/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RReverser/subscriptions","organizations_url":"https://api.github.com/users/RReverser/orgs","repos_url":"https://api.github.com/users/RReverser/repos","events_url":"https://api.github.com/users/RReverser/events{/privacy}","received_events_url":"https://api.github.com/users/RReverser/received_events","type":"User","site_admin":false},"created_at":"2015-10-24T12:22:57Z","updated_at":"2015-10-24T12:22:57Z","body":"> rarely documented or tested, and makes code less portable\r\n\r\nDepends. In the case with Acorn, for example, we provide separate well-documented entry points for generic and loose parser.\r\n\r\nLodash provides documented separate entry points for each particular function so that you can import only needed ones.\r\n\r\nThere are many cases, in fact, where devs make good use of structured import paths."}}