diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..b769287 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true + +[*.{js,json,ts,md}] +charset = utf-8 +indent_style = space +indent_size = 2 diff --git a/README.md b/README.md index a00954c..9ea1bd3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ yarn 0.27.x introduced the [yarn workspaces feature][1]. -[1]: https://github.com/yarnpkg/yarn/issues/3294 @@ -32,3 +31,129 @@ error The workspace feature is currently experimental and needs to be manually e The cool thing is that workspaces can be enabled only for a specific project. Adding `.yarnrc` to the project root and simply add the above line to it! + +## Building a multi-package Angular project + +Let's now try to build a multi-package Angular project inspired by the project layout of [angular/angular][3] + + +``` +demo + |- .angular-cli.json + |- package.json +packages + |- common + |- package.json + |- components + |- package.json +``` + +Then, we must give workspaces name and at least add the `name` property to the `package.json` files! + +Example `packages/common/package.json`: + +```json +{ + "name": "@foo/common", + "version": "1.0.0", + "private": true +} +``` + +Running commands in a single workspace: + +```bash +$ yarn workspace @foo/common add @angular/common +$ yarn workspace @foo/components add @angular/http +``` + +What happened? + +Yarn installs dependencies to the project's root folder, e.g. `node_modules/@angular`. +By node's module resolution algorithm, sub-projects will recursively walk up the file-tree until they find a `node_modules` folder with the right dependencies! + +A little bit counter-intuitive, this does not add the dependencies to the sub-projects but rather to the top-level `package.json`! + +Also, it creates symlinks from the top-level `node_modules/@foo` folder to the directories of the individual workspaces: + +```bash +$ ls -l node_modules/@foo +total 24 +lrwxr-xr-x ... common -> ../../packages/common +lrwxr-xr-x ... components -> ../../packages/components +lrwxr-xr-x ... demo-app -> ../../demo +``` + +What happens on dependency version conflicts? + +Let's simulate that by adding to `demo/package.json`: + +```json +{ + "name": "@foo/demo-app", + "version": "1.0.0", + "private": true, + "dependencies": { + "@angular/core": "4.2.0", + "@angular/common": "4.2.0", + "@angular/http": "4.2.0", + "@angular/platform-browser": "4.2.0" + } +} +``` + +```bash +$ rm yarn.lock +$ yarn install +yarn install v0.27.5 +info No lockfile found. +[1/4] Resolving packages... +[2/4] Fetching packages... +[3/4] Linking dependencies... +[4/4] Building fresh packages... +success Saved lockfile. +Done in 2.32s. +$ cat node_modules/@angular/http/package.json +{ + "name": "@angular/http", + "version": "4.3.1", + "description": "Angular - the http service", + "main": "./bundles/http.umd.js", + ... +} +``` + +Uh, the install command silently installed the `4.3.1` version, even though `@foo/demo` specified the `4.2.0` version. +But wait, there's another `demo/node_modules` directory created now! + +```bash +$ cat demo/node_modules/@angular/http/package.json +{ + "name": "@angular/http", + "version": "4.2.0", + "description": "Angular - the http service", + "main": "./bundles/http.umd.js", + ... +} +``` + +That means that `yarn install` installs local dependencies, if needed, next to the `package.json` of the workspace. +It tries to assemble global depencies of all worksapces next to the root-level `package.json`! + +I suggest that working on different Angular versions within the same project isn't a very good idea. +So, when we change everything to depend on the `4.3.1` version and re-run: + +```bash +$ rm -rf demo/node_modules +$ rm -rf node_modules +$ rm yarn.lock +$ yarn install +``` + +Now, we only get dependencies installed to the top-most `node_modules` directory, meaning that all workspaces share the same depencies! + + + +[1]: https://github.com/yarnpkg/yarn/issues/3294 +[2]: https://github.com/thejameskyle/rfcs-1/blob/workspaces/accepted/0000-workspaces.md +[3]: https://github.com/angular/angular diff --git a/demo/package.json b/demo/package.json new file mode 100644 index 0000000..2165f29 --- /dev/null +++ b/demo/package.json @@ -0,0 +1,11 @@ +{ + "name": "@foo/demo-app", + "version": "1.0.0", + "private": true, + "dependencies": { + "@angular/core": "4.3.1", + "@angular/common": "4.3.1", + "@angular/http": "4.3.1", + "@angular/platform-browser": "4.3.1" + } +} diff --git a/package.json b/package.json index 7702362..e23d1c9 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,13 @@ "author": "David ", "license": "MIT", "workspaces": [ - - ] + "packages/*", + "demo" + ], + "dependencies": { + "@angular/http": "^4.3.1", + "@angular/platform-browser": "^4.3.1", + "rxjs": "^5.4.2", + "zone.js": "^0.8.14" + } } diff --git a/packages/common/package.json b/packages/common/package.json new file mode 100644 index 0000000..7fd1ed8 --- /dev/null +++ b/packages/common/package.json @@ -0,0 +1,9 @@ +{ + "name": "@foo/common", + "version": "1.0.0", + "private": true, + "peerDependencies": { + "@angular/common": "4.3.1", + "@angular/http": "4.3.1" + } +} diff --git a/packages/components/package.json b/packages/components/package.json new file mode 100644 index 0000000..753c5fb --- /dev/null +++ b/packages/components/package.json @@ -0,0 +1,8 @@ +{ + "name": "@foo/components", + "version": "1.0.0", + "private": true, + "peerDependencies": { + "@angular/common": "4.3.1" + } +} diff --git a/yarn.lock b/yarn.lock index fb57ccd..ca4e6c4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,3 +2,44 @@ # yarn lockfile v1 +"@angular/common@4.3.1": + version "4.3.1" + resolved "https://registry.yarnpkg.com/@angular/common/-/common-4.3.1.tgz#260f487a7cdca326c436bd3ea9515c797de2ff72" + dependencies: + tslib "^1.7.1" + +"@angular/core@4.3.1": + version "4.3.1" + resolved "https://registry.yarnpkg.com/@angular/core/-/core-4.3.1.tgz#a9d0a7d644b96260674269b689a04feea632a8d3" + dependencies: + tslib "^1.7.1" + +"@angular/http@4.3.1", "@angular/http@^4.3.1": + version "4.3.1" + resolved "https://registry.yarnpkg.com/@angular/http/-/http-4.3.1.tgz#e4f661f746711e88ecbea76a3c905babf97d315a" + dependencies: + tslib "^1.7.1" + +"@angular/platform-browser@4.3.1", "@angular/platform-browser@^4.3.1": + version "4.3.1" + resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-4.3.1.tgz#db727b06eed64bda5defec71815db26a4da2f690" + dependencies: + tslib "^1.7.1" + +rxjs@^5.4.2: + version "5.4.2" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.4.2.tgz#2a3236fcbf03df57bae06fd6972fd99e5c08fcf7" + dependencies: + symbol-observable "^1.0.1" + +symbol-observable@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d" + +tslib@^1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.7.1.tgz#bc8004164691923a79fe8378bbeb3da2017538ec" + +zone.js@^0.8.14: + version "0.8.14" + resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.14.tgz#0c4db24b178232274ccb43f78c99db7f3642b6cf"