{"action":"created","issue":{"url":"https://api.github.com/repos/meteor/meteor/issues/9771","repository_url":"https://api.github.com/repos/meteor/meteor","labels_url":"https://api.github.com/repos/meteor/meteor/issues/9771/labels{/name}","comments_url":"https://api.github.com/repos/meteor/meteor/issues/9771/comments","events_url":"https://api.github.com/repos/meteor/meteor/issues/9771/events","html_url":"https://github.com/meteor/meteor/pull/9771","id":308738698,"node_id":"MDExOlB1bGxSZXF1ZXN0MTc3NTcwNDY3","number":9771,"title":"Allow selective compilation of packages and modules within node_modules.","user":{"login":"benjamn","id":5750,"node_id":"MDQ6VXNlcjU3NTA=","avatar_url":"https://avatars0.githubusercontent.com/u/5750?v=4","gravatar_id":"","url":"https://api.github.com/users/benjamn","html_url":"https://github.com/benjamn","followers_url":"https://api.github.com/users/benjamn/followers","following_url":"https://api.github.com/users/benjamn/following{/other_user}","gists_url":"https://api.github.com/users/benjamn/gists{/gist_id}","starred_url":"https://api.github.com/users/benjamn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/benjamn/subscriptions","organizations_url":"https://api.github.com/users/benjamn/orgs","repos_url":"https://api.github.com/users/benjamn/repos","events_url":"https://api.github.com/users/benjamn/events{/privacy}","received_events_url":"https://api.github.com/users/benjamn/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":{"login":"benjamn","id":5750,"node_id":"MDQ6VXNlcjU3NTA=","avatar_url":"https://avatars0.githubusercontent.com/u/5750?v=4","gravatar_id":"","url":"https://api.github.com/users/benjamn","html_url":"https://github.com/benjamn","followers_url":"https://api.github.com/users/benjamn/followers","following_url":"https://api.github.com/users/benjamn/following{/other_user}","gists_url":"https://api.github.com/users/benjamn/gists{/gist_id}","starred_url":"https://api.github.com/users/benjamn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/benjamn/subscriptions","organizations_url":"https://api.github.com/users/benjamn/orgs","repos_url":"https://api.github.com/users/benjamn/repos","events_url":"https://api.github.com/users/benjamn/events{/privacy}","received_events_url":"https://api.github.com/users/benjamn/received_events","type":"User","site_admin":false},"assignees":[{"login":"benjamn","id":5750,"node_id":"MDQ6VXNlcjU3NTA=","avatar_url":"https://avatars0.githubusercontent.com/u/5750?v=4","gravatar_id":"","url":"https://api.github.com/users/benjamn","html_url":"https://github.com/benjamn","followers_url":"https://api.github.com/users/benjamn/followers","following_url":"https://api.github.com/users/benjamn/following{/other_user}","gists_url":"https://api.github.com/users/benjamn/gists{/gist_id}","starred_url":"https://api.github.com/users/benjamn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/benjamn/subscriptions","organizations_url":"https://api.github.com/users/benjamn/orgs","repos_url":"https://api.github.com/users/benjamn/repos","events_url":"https://api.github.com/users/benjamn/events{/privacy}","received_events_url":"https://api.github.com/users/benjamn/received_events","type":"User","site_admin":false}],"milestone":{"url":"https://api.github.com/repos/meteor/meteor/milestones/47","html_url":"https://github.com/meteor/meteor/milestone/47","labels_url":"https://api.github.com/repos/meteor/meteor/milestones/47/labels","id":2931507,"node_id":"MDk6TWlsZXN0b25lMjkzMTUwNw==","number":47,"title":"Release 1.7","description":"","creator":{"login":"benjamn","id":5750,"node_id":"MDQ6VXNlcjU3NTA=","avatar_url":"https://avatars0.githubusercontent.com/u/5750?v=4","gravatar_id":"","url":"https://api.github.com/users/benjamn","html_url":"https://github.com/benjamn","followers_url":"https://api.github.com/users/benjamn/followers","following_url":"https://api.github.com/users/benjamn/following{/other_user}","gists_url":"https://api.github.com/users/benjamn/gists{/gist_id}","starred_url":"https://api.github.com/users/benjamn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/benjamn/subscriptions","organizations_url":"https://api.github.com/users/benjamn/orgs","repos_url":"https://api.github.com/users/benjamn/repos","events_url":"https://api.github.com/users/benjamn/events{/privacy}","received_events_url":"https://api.github.com/users/benjamn/received_events","type":"User","site_admin":false},"open_issues":7,"closed_issues":69,"state":"open","created_at":"2017-11-22T16:38:48Z","updated_at":"2018-08-03T21:20:31Z","due_on":null,"closed_at":null},"comments":6,"created_at":"2018-03-26T21:16:59Z","updated_at":"2018-08-27T04:11:11Z","closed_at":"2018-03-27T16:05:25Z","author_association":"MEMBER","pull_request":{"url":"https://api.github.com/repos/meteor/meteor/pulls/9771","html_url":"https://github.com/meteor/meteor/pull/9771","diff_url":"https://github.com/meteor/meteor/pull/9771.diff","patch_url":"https://github.com/meteor/meteor/pull/9771.patch"},"body":"## The problem\r\n\r\nEver since Meteor 1.3, we have assumed that code published to npm and installed inside `node_modules` should be consumed by Meteor without any further compilation.\r\n\r\nHowever, as the comments in https://github.com/meteor/meteor-feature-requests/issues/6 make clear, not every npm package author compiles their code for full compatibility with older browsers, and there are cases where you might like to use Meteor compiler plugins to compile resources installed in `node_modules`, even if that's not something the package author intended.\r\n\r\nA blanket policy of recompiling all packages in `node_modules` would be extraordinarily expensive, not to mention error-prone, because no single Babel configuration can safely process the immense variety of npm package code. Not even if you use the package's own `.babelrc` configuration, as the Parcel project has discovered: [parcel-bundler/parcel#13](https://goo.gl/UCSNKU)\r\n\r\nThe obvious alternative to compiling everything or nothing is to let the developer specify which packages should be compiled, but that approach increases the configuration burden of Meteor applications and steepens the learning curve for Meteor developers, which is something we take very seriously. Meteor was a \"zero-configuration\" build tool long before that terminology was hip.\r\n\r\nWith that background in mind, we are proud to offer a technique for selectively recompiling packages and modules within `node_modules` that is simultaneously easy to use, efficient, and flexible enough for any conceivable use case.\r\n\r\n## Our solution\r\n\r\nBecause Meteor refuses to compile code within `node_modules` by default, the trick is to expose npm package code outside of `node_modules` using [symbolic links](https://en.wikipedia.org/wiki/Symbolic_link), so that the code will be compiled as part of your application, using whatever compiler plugins you have installed.\r\n\r\nThis trick has worked for a long time, but it was never really satisfying, because you'd have to import the exposed code using a relative import like `import stuff from \"./imports/linked/the-package\"` rather than just doing `import stuff from \"the-package\"`.\r\n\r\nEven if you were very careful to stick to the relative `import` style, you couldn't control the way other npm packages imported `the-package`, so this approach was always doomed to failure—until now!\r\n\r\nThis pull request makes both of these `import` styles work in exactly the same way.\r\n\r\nTechnically speaking, if two modules share the same [`fs.realpath`](https://nodejs.org/api/fs.html#fs_fs_realpath_path_options_callback), but one of them is compiled by Meteor, this pull request ensures that both modules will use the compiled code.\r\n\r\nIn other words, if Meteor compiles some code as part of your application, you can create symbolic links to that code elsewhere in your application (including inside `node_modules`), and the same compiled code will be used everywhere.\r\n\r\n### Packages that need modification before compilation\r\n\r\nIf you want to use an npm package that needs to be recompiled, but you have to make some modifications to the package source code before the compilation happens, first clone the package repository somewhere in your application:\r\n\r\n```sh\r\ncd path/to/application\r\nmkdir -p imports/linked\r\ncd imports/linked\r\ngit clone git@github.com:acornjs/acorn.git\r\nrm -rf acorn/.git\r\ngit add acorn\r\n```\r\n\r\n> Tip: you can use [`git` submodules](http://www.vogella.com/tutorials/GitSubmodules/article.html) to include other `git` repositories in your application, instead of committing the clone.\r\n\r\nNow you can edit the package however you like, perhaps by replacing the `main` field of `acorn/package.json` with `src/index.js` instead of `dist/acorn.js`, or adding a custom `.babelrc` file to the root of the package.\r\n\r\nOnce you've modified the package to your liking, simply `npm link` it into your `node_modules` directory:\r\n\r\n```sh\r\ncd path/to/application\r\nmeteor npm link imports/linked/acorn\r\n```\r\n\r\nThe `npm link` command works by creating a symbolic link from `node_modules/acorn` to the package source directory (`imports/linked/acorn`).\r\n\r\nThanks to this linkage, `import { parse } from \"acorn\"`, `require(\"acorn\")`, and `import(\"acorn\")` will resolve to code within `node_modules/acorn/...`, but that code will be compiled by the Meteor, because it was also exposed via `imports/linked/acorn/...`.\r\n\r\nIf you accidentally `require(\"/imports/linked/acorn\")` instead of just `require(\"acorn\")`, that's fine, because the Meteor module system conveniently aliases the modules together. To see how this aliasing works, try checking the following relationships:\r\n```js\r\nrequire.resolve(\"/imports/linked/acorn\") === require.resolve(\"acorn\")\r\nrequire(\"acorn\").parse === require(\"./imports/linked/acorn\").parse\r\n```\r\n\r\n### Packages that only need to be compiled\r\n\r\nIf you want to use an npm package that isn't adequately compiled for older browsers, but you *don't* need to make any modifications to the package, that's even easier!\r\n\r\nInstead of using `npm link` to create a symbolic link from `node_modules/...` to somewhere else in your application, first `npm install` the package into `node_modules` as usual, then create a symbolic link *to* the installed package *from* somewhere else in the application:\r\n\r\n```sh\r\nmeteor npm install lodash-es\r\nmkdir imports\r\ncd imports\r\nln -s ../node_modules/loash-es .\r\n```\r\n\r\nAs you might imagine, `lodash-es` makes liberal use of ECMAScript `import` and `export` declarations, which need to be compiled in most JS environments. Because `imports/lodash-es` is now compiled as Meteor application code, code within `node_modules/lodash-es/...` will also be compiled, and can be imported as usual.\r\n\r\nIn some sense, this is the opposite of the previous example, because you're making a symbolic link *to* `node_modules/lodash-es` instead of making `node_modules/lodash-es` a link to somewhere else, but the common idea is the same: every module inside `lodash-es` shares the same `fs.realpath` with a module that was compiled by Meteor, so the direction of the symbolic linkage doesn't really matter. The module will be compiled by Meteor regardless of how you import it.\r\n\r\n### Packages that only need, like, _one file_ to be compiled\r\n\r\nJust as you can make a symbolic link between directories in `node_modules` and directories elsewhere in your application, you can also make symbolic links to individual files or subdirectories:\r\n\r\n```sh\r\nmeteor npm install some-npm-package\r\nmkdir -p imports/linked\r\ncd imports/linked\r\nln -s ../../node_modules/some-npm-package/that/file/with/class/syntax.js .\r\n```\r\n\r\nIf `that/file/with/class/syntax.js` is the only file in `some-npm-package` that needs to be recompiled, you can compile it by exposing it as `imports/linked/syntax.js` without compiling any of the other modules in the package.\r\n\r\n## tl;dr\r\n\r\nTo compile specific npm packages, use symbolic links to expose `node_modules` code within your application, outside of `node_modules`. Meteor will compile the exposed code as if it was part of your application, using whatever compiler plugins you have installed, and also guarantee that you get the compiled code when you import from `node_modules` (this is they key new feature)."},"comment":{"url":"https://api.github.com/repos/meteor/meteor/issues/comments/416109086","html_url":"https://github.com/meteor/meteor/pull/9771#issuecomment-416109086","issue_url":"https://api.github.com/repos/meteor/meteor/issues/9771","id":416109086,"node_id":"MDEyOklzc3VlQ29tbWVudDQxNjEwOTA4Ng==","user":{"login":"awatson1978","id":675910,"node_id":"MDQ6VXNlcjY3NTkxMA==","avatar_url":"https://avatars3.githubusercontent.com/u/675910?v=4","gravatar_id":"","url":"https://api.github.com/users/awatson1978","html_url":"https://github.com/awatson1978","followers_url":"https://api.github.com/users/awatson1978/followers","following_url":"https://api.github.com/users/awatson1978/following{/other_user}","gists_url":"https://api.github.com/users/awatson1978/gists{/gist_id}","starred_url":"https://api.github.com/users/awatson1978/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/awatson1978/subscriptions","organizations_url":"https://api.github.com/users/awatson1978/orgs","repos_url":"https://api.github.com/users/awatson1978/repos","events_url":"https://api.github.com/users/awatson1978/events{/privacy}","received_events_url":"https://api.github.com/users/awatson1978/received_events","type":"User","site_admin":false},"created_at":"2018-08-27T04:11:11Z","updated_at":"2018-08-27T04:11:11Z","author_association":"CONTRIBUTOR","body":"Bravo!  Fantastic work!  "}}
{"actor":{"display_login":"awatson1978"}}