{"action":"created","issue":{"url":"https://api.github.com/repos/jsforum/jsforum/issues/5","repository_url":"https://api.github.com/repos/jsforum/jsforum","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":58,"created_at":"2015-10-23T18:48:06Z","updated_at":"2016-02-09T18:39:32Z","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/181997066","html_url":"https://github.com/jsforum/jsforum/issues/5#issuecomment-181997066","issue_url":"https://api.github.com/repos/jsforum/jsforum/issues/5","id":181997066,"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},"created_at":"2016-02-09T18:39:32Z","updated_at":"2016-02-09T18:39:32Z","body":"I think the name should reflect that it's *the* entry point for the package – or will become so soon enough – rather than one of several, since that's the whole point of ES modules. `esmodules:main` suffers from the same drawback as `jsnext:main` IMHO, in that it looks like a temporary kludge and not the preferred entry point, so I think that from a 2018/19 vantage point it would seem regrettable.\r\n\r\n`exports` and `module` seem equally valid to me, though `module` does reinforce the connection between this and ES modules."}}