2020/02/23 にQiitaに投稿した記事のアーカイブです
こんにちは、奥野賢太郎 ( @okunokentaro ) です。今回は Nrwl/Nx
#というウェブアプリケーション開発におけるモノレポ管理のための開発ツールを用いて、3通りのやり方でAngularアプリケーションを新規作成してみました。そのやり方の紹介と、生成結果の違いについて紹介します。
- モノレポとはなにか、その有用性についてなどは紹介しません
- Nxとは何かについての詳細は紹介しません
上から見ていけば、だいたいNxとは何かがわかります。
- ng-japan OnAir 第12回 "Managing Monorepos with Nx"(2020年映像資料)
- Managing Monorepos with Nx Nrwl/Nxの近況(2020年資料)
- [Nxではじめる Angular + NestJS フルスタックWebアプリ開発] (https://qiita.com/puku0x/items/9191fb432f4292736c2d)(2019年記事)
- Nxに触ってみる(2017年記事)
Nxとはコマンドラインツールです。そのため npx
で呼び出すか、 npm install -g
にてインストールします。
公式のGetting Startedでは2020/2/23現在失敗してしまったので、ここに成功する方法をまとめます。
暗黙でグローバルに @nrwl/workspace
, typescript
を求められるのが少々惜しいですが、 npx create-nx-workspace
ではモジュールが不足してしまうようでグローバルインストールをおすすめします。(不具合にみえるが、これが意図的なら不親切)
npm install -g create-nx-workspace @nrwl/workspace typescript
インストールの確認には次のコマンドを実行します。
create-nx-workspace --help
ヘルプが表示されれば、インストールに成功しています。
create-nx-workspace
を使うことによってアプリケーション用の各種設定ファイルを自動生成します。
create-react-app
# や create-nuxt-app
# のようなものですね。ここ3年くらいでウェブアプリケーションの立ち上げにスケルトンの複製やツールチェインの記述をする機会がかなり減りました。Nxもそういったツールチェインを隠蔽する目的を持っています。
さて、 create-nx-workspace
を使うとAngular with Nxなアプリケーション開発基盤が整うわけですが、そのやり方は3つあります。筆者もNxを実務で利用したことはまだないため、どれを使うとよいか判断すべく、比較していきます。
create-nx-workspace
にてemptyなworkspaceを作成し、そこにng g @nrwl/angular:application
にてAngularアプリケーションを追加するcreate-nx-workspace
にて新規のAngularアプリケーションを含むworkspaceを作成するng new
にて新規のAngularアプリケーションを作成し、その後ng add @nrwl/workspace
にてworkspaceに変換する
1.はチュートリアルにて紹介されている手法、2.はCLIを実行したときに現れる選択肢から進める手法、3.はもっともリアルユースでありそうな既存アプリにNxを採用する手法です。
以下、それぞれの手法を実行した結果を紹介します。
まずは無機質に生成結果だけ貼ります。比較は以後の節にて。
create-nx-workspace myworkspace
実行中のログ
? What to create in the new workspace (Use arrow keys)
❯ empty [an empty workspace]
web components [a workspace with a single app built using web components]
angular [a workspace with a single Angular application]
angular-nest [a workspace with a full stack application (Angular + Nest)]
react [a workspace with a single React application]
react-express [a workspace with a full stack application (React + Express)]
next.js [a workspace with a single Next.js application]
? CLI to power the Nx workspace
Nx [Extensible CLI for JavaScript and TypeScript applications]
❯ Angular CLI [Extensible CLI for Angular applications. Recommended for Angular projects.]
Creating a sandbox with Nx...
new myworkspace --preset="empty" --interactive=false --collection=@nrwl/workspace
CREATE myworkspace/nx.json (262 bytes)
CREATE myworkspace/tsconfig.json (509 bytes)
CREATE myworkspace/README.md (2705 bytes)
CREATE myworkspace/.editorconfig (245 bytes)
CREATE myworkspace/.gitignore (503 bytes)
CREATE myworkspace/.prettierignore (74 bytes)
CREATE myworkspace/.prettierrc (25 bytes)
CREATE myworkspace/angular.json (96 bytes)
CREATE myworkspace/package.json (1187 bytes)
CREATE myworkspace/apps/.gitkeep (1 bytes)
CREATE myworkspace/libs/.gitkeep (0 bytes)
CREATE myworkspace/tools/tsconfig.tools.json (218 bytes)
CREATE myworkspace/tools/schematics/.gitkeep (0 bytes)
CREATE myworkspace/.vscode/extensions.json (170 bytes)
✔ Packages installed successfully.
Directory is already under version control. Skipping initialization of git.
———————————————————————————————————————————————
> NX NOTE Nx CLI is not installed globally.
This means that you might have to use "yarn nx" or "npm nx" to execute commands in the workspace.
Run "yarn global add @nrwl/cli" or "npm install -g @nrwl/cli" to be able to execute command directly.
cd myworkspace
ng add @nrwl/angular --defaults
実行中のログ
? Would you like to share anonymous usage data about this project with the Angular Team at
Google under Google’s Privacy Policy at https://policies.google.com/privacy? For more
details and how to change this setting, see http://angular.io/analytics. (y/N) No
Installing packages for tooling via npm.
Installed packages for tooling via npm.
CREATE jest.config.js (250 bytes)
UPDATE angular.json (316 bytes)
UPDATE package.json (2006 bytes)
✔ Packages installed successfully.
ng g @nrwl/angular:application myapp
実行中のログ
? Which stylesheet format would you like to use? (Use arrow keys)
❯ CSS
SASS(.scss) [ http://sass-lang.com ]
Stylus(.styl)[ http://stylus-lang.com ]
LESS [ http://lesscss.org ]
? Would you like to configure routing for this application? No
CREATE tslint.json (2261 bytes)
CREATE apps/myapp/tsconfig.json (97 bytes)
CREATE apps/myapp/src/favicon.ico (15086 bytes)
CREATE apps/myapp/browserslist (429 bytes)
CREATE apps/myapp/tsconfig.app.json (163 bytes)
CREATE apps/myapp/tslint.json (203 bytes)
CREATE apps/myapp/src/index.html (335 bytes)
CREATE apps/myapp/src/main.ts (375 bytes)
CREATE apps/myapp/src/polyfills.ts (2836 bytes)
CREATE apps/myapp/src/styles.css (80 bytes)
CREATE apps/myapp/src/assets/.gitkeep (0 bytes)
CREATE apps/myapp/src/environments/environment.prod.ts (51 bytes)
CREATE apps/myapp/src/environments/environment.ts (662 bytes)
CREATE apps/myapp/src/app/app.module.ts (297 bytes)
CREATE apps/myapp/src/app/app.component.css (2088 bytes)
CREATE apps/myapp/src/app/app.component.html (2537 bytes)
CREATE apps/myapp/src/app/app.component.spec.ts (919 bytes)
CREATE apps/myapp/src/app/app.component.ts (217 bytes)
CREATE apps/myapp/tsconfig.spec.json (233 bytes)
CREATE apps/myapp/jest.config.js (347 bytes)
CREATE apps/myapp/src/test-setup.ts (30 bytes)
CREATE apps/myapp-e2e/tslint.json (48 bytes)
CREATE apps/myapp-e2e/cypress.json (410 bytes)
CREATE apps/myapp-e2e/tsconfig.e2e.json (167 bytes)
CREATE apps/myapp-e2e/tsconfig.json (137 bytes)
CREATE apps/myapp-e2e/src/fixtures/example.json (80 bytes)
CREATE apps/myapp-e2e/src/integration/app.spec.ts (402 bytes)
CREATE apps/myapp-e2e/src/plugins/index.js (832 bytes)
CREATE apps/myapp-e2e/src/support/app.po.ts (47 bytes)
CREATE apps/myapp-e2e/src/support/commands.ts (1068 bytes)
CREATE apps/myapp-e2e/src/support/index.ts (599 bytes)
UPDATE package.json (2006 bytes)
UPDATE angular.json (4063 bytes)
UPDATE nx.json (387 bytes)
.
├── .editorconfig
├── .gitignore
├── .prettierignore
├── .prettierrc
├── .vscode
│ └── extensions.json
├── README.md
├── angular.json
├── apps
│ ├── .gitkeep
│ ├── myapp
│ │ ├── browserslist
│ │ ├── jest.config.js
│ │ ├── src
│ │ │ ├── app
│ │ │ │ ├── app.component.css
│ │ │ │ ├── app.component.html
│ │ │ │ ├── app.component.spec.ts
│ │ │ │ ├── app.component.ts
│ │ │ │ └── app.module.ts
│ │ │ ├── assets
│ │ │ │ └── .gitkeep
│ │ │ ├── environments
│ │ │ │ ├── environment.prod.ts
│ │ │ │ └── environment.ts
│ │ │ ├── favicon.ico
│ │ │ ├── index.html
│ │ │ ├── main.ts
│ │ │ ├── polyfills.ts
│ │ │ ├── styles.css
│ │ │ └── test-setup.ts
│ │ ├── tsconfig.app.json
│ │ ├── tsconfig.json
│ │ ├── tsconfig.spec.json
│ │ └── tslint.json
│ └── myapp-e2e
│ ├── cypress.json
│ ├── src
│ │ ├── fixtures
│ │ │ └── example.json
│ │ ├── integration
│ │ │ └── app.spec.ts
│ │ ├── plugins
│ │ │ └── index.js
│ │ └── support
│ │ ├── app.po.ts
│ │ ├── commands.ts
│ │ └── index.ts
│ ├── tsconfig.e2e.json
│ ├── tsconfig.json
│ └── tslint.json
├── jest.config.js
├── libs
│ └── .gitkeep
├── node_modules
├── nx.json
├── package-lock.json
├── package.json
├── tools
│ ├── schematics
│ │ └── .gitkeep
│ └── tsconfig.tools.json
├── tsconfig.json
└── tslint.json
create-nx-workspace myworkspace
実行中のログ
? What to create in the new workspace
empty [an empty workspace]
web components [a workspace with a single app built using web components]
❯ angular [a workspace with a single Angular application]
angular-nest [a workspace with a full stack application (Angular + Nest)]
react [a workspace with a single React application]
react-express [a workspace with a full stack application (React + Express)]
next.js [a workspace with a single Next.js application]
? Application name myapp
? Default stylesheet format (Use arrow keys)
❯ CSS
SASS(.scss) [ http://sass-lang.com ]
Stylus(.styl)[ http://stylus-lang.com ]
LESS [ http://lesscss.org ]
Creating a sandbox with Nx...
new myworkspace --preset="angular" --appName="myapp" --style="css" --interactive=false --collection=@nrwl/workspace
CREATE myworkspace/nx.json (262 bytes)
CREATE myworkspace/tsconfig.json (509 bytes)
CREATE myworkspace/README.md (2705 bytes)
CREATE myworkspace/.editorconfig (245 bytes)
CREATE myworkspace/.gitignore (503 bytes)
CREATE myworkspace/.prettierignore (74 bytes)
CREATE myworkspace/.prettierrc (25 bytes)
CREATE myworkspace/angular.json (96 bytes)
CREATE myworkspace/package.json (1190 bytes)
CREATE myworkspace/apps/.gitkeep (1 bytes)
CREATE myworkspace/libs/.gitkeep (0 bytes)
CREATE myworkspace/tools/tsconfig.tools.json (218 bytes)
CREATE myworkspace/tools/schematics/.gitkeep (0 bytes)
CREATE myworkspace/.vscode/extensions.json (170 bytes)
✔ Packages installed successfully.
? Would you like to share anonymous usage data about this project with the Angular Team at
Google under Google’s Privacy Policy at https://policies.google.com/privacy? For more
details and how to change this setting, see http://angular.io/analytics. No
CREATE jest.config.js (250 bytes)
CREATE tslint.json (2261 bytes)
CREATE apps/myapp/tsconfig.json (97 bytes)
CREATE apps/myapp/src/favicon.ico (15086 bytes)
CREATE apps/myapp/browserslist (429 bytes)
CREATE apps/myapp/tsconfig.app.json (163 bytes)
CREATE apps/myapp/tslint.json (203 bytes)
CREATE apps/myapp/src/index.html (335 bytes)
CREATE apps/myapp/src/main.ts (375 bytes)
CREATE apps/myapp/src/polyfills.ts (2833 bytes)
CREATE apps/myapp/src/styles.css (80 bytes)
CREATE apps/myapp/src/assets/.gitkeep (0 bytes)
CREATE apps/myapp/src/environments/environment.prod.ts (51 bytes)
CREATE apps/myapp/src/environments/environment.ts (662 bytes)
CREATE apps/myapp/src/app/app.module.ts (297 bytes)
CREATE apps/myapp/src/app/app.component.css (2088 bytes)
CREATE apps/myapp/src/app/app.component.html (2537 bytes)
CREATE apps/myapp/src/app/app.component.spec.ts (919 bytes)
CREATE apps/myapp/src/app/app.component.ts (217 bytes)
CREATE apps/myapp/tsconfig.spec.json (233 bytes)
CREATE apps/myapp/jest.config.js (347 bytes)
CREATE apps/myapp/src/test-setup.ts (30 bytes)
CREATE apps/myapp-e2e/tslint.json (48 bytes)
CREATE apps/myapp-e2e/cypress.json (410 bytes)
CREATE apps/myapp-e2e/tsconfig.e2e.json (167 bytes)
CREATE apps/myapp-e2e/tsconfig.json (137 bytes)
CREATE apps/myapp-e2e/src/fixtures/example.json (80 bytes)
CREATE apps/myapp-e2e/src/integration/app.spec.ts (402 bytes)
CREATE apps/myapp-e2e/src/plugins/index.js (832 bytes)
CREATE apps/myapp-e2e/src/support/app.po.ts (47 bytes)
CREATE apps/myapp-e2e/src/support/commands.ts (1068 bytes)
CREATE apps/myapp-e2e/src/support/index.ts (599 bytes)
UPDATE angular.json (4063 bytes)
UPDATE package.json (2005 bytes)
UPDATE nx.json (387 bytes)
✔ Packages installed successfully.
> NX NOTE Because you selected an Angular-specific preset, we generated an Nx workspace powered by the Angular CLI.
Run 'create-nx-workspace --help' to see how to select a different CLI.
———————————————————————————————————————————————
> NX NOTE Nx CLI is not installed globally.
This means that you might have to use "yarn nx" or "npm nx" to execute commands in the workspace.
Run "yarn global add @nrwl/cli" or "npm install -g @nrwl/cli" to be able to execute command directly.
———————————————————————————————————————————————
> NX NOTE First time using Nx? Check out this interactive Nx tutorial.
https://nx.dev/angular/tutorial/01-create-application
Prefer watching videos? Check out this free Nx course on YouTube.
https://www.youtube.com/watch?v=2mYLe9Kp9VM&list=PLakNactNC1dH38AfqmwabvOszDmKriGco
.
├── .editorconfig
├── .gitignore
├── .prettierignore
├── .prettierrc
├── .vscode
│ └── extensions.json
├── README.md
├── angular.json
├── apps
│ ├── .gitkeep
│ ├── myapp
│ │ ├── browserslist
│ │ ├── jest.config.js
│ │ ├── src
│ │ │ ├── app
│ │ │ │ ├── app.component.css
│ │ │ │ ├── app.component.html
│ │ │ │ ├── app.component.spec.ts
│ │ │ │ ├── app.component.ts
│ │ │ │ └── app.module.ts
│ │ │ ├── assets
│ │ │ │ └── .gitkeep
│ │ │ ├── environments
│ │ │ │ ├── environment.prod.ts
│ │ │ │ └── environment.ts
│ │ │ ├── favicon.ico
│ │ │ ├── index.html
│ │ │ ├── main.ts
│ │ │ ├── polyfills.ts
│ │ │ ├── styles.css
│ │ │ └── test-setup.ts
│ │ ├── tsconfig.app.json
│ │ ├── tsconfig.json
│ │ ├── tsconfig.spec.json
│ │ └── tslint.json
│ └── myapp-e2e
│ ├── cypress.json
│ ├── src
│ │ ├── fixtures
│ │ │ └── example.json
│ │ ├── integration
│ │ │ └── app.spec.ts
│ │ ├── plugins
│ │ │ └── index.js
│ │ └── support
│ │ ├── app.po.ts
│ │ ├── commands.ts
│ │ └── index.ts
│ ├── tsconfig.e2e.json
│ ├── tsconfig.json
│ └── tslint.json
├── jest.config.js
├── libs
│ └── .gitkeep
├── node_modules
├── nx.json
├── package-lock.json
├── package.json
├── tools
│ ├── schematics
│ │ └── .gitkeep
│ └── tsconfig.tools.json
├── tsconfig.json
└── tslint.json
ng new myapp
実行中のログ
? Would you like to add Angular routing? No
? Which stylesheet format would you like to use? (Use arrow keys)
❯ CSS
SCSS [ https://sass-lang.com/documentation/syntax#scss ]
Sass [ https://sass-lang.com/documentation/syntax#the-indented-syntax ]
Less [ http://lesscss.org ]
Stylus [ http://stylus-lang.com ]
CREATE myapp/README.md (1022 bytes)
CREATE myapp/.editorconfig (246 bytes)
CREATE myapp/.gitignore (631 bytes)
CREATE myapp/angular.json (3559 bytes)
CREATE myapp/package.json (1282 bytes)
CREATE myapp/tsconfig.json (543 bytes)
CREATE myapp/tslint.json (1953 bytes)
CREATE myapp/browserslist (429 bytes)
CREATE myapp/karma.conf.js (1017 bytes)
CREATE myapp/tsconfig.app.json (210 bytes)
CREATE myapp/tsconfig.spec.json (270 bytes)
CREATE myapp/src/favicon.ico (948 bytes)
CREATE myapp/src/index.html (291 bytes)
CREATE myapp/src/main.ts (372 bytes)
CREATE myapp/src/polyfills.ts (2835 bytes)
CREATE myapp/src/styles.css (80 bytes)
CREATE myapp/src/test.ts (753 bytes)
CREATE myapp/src/assets/.gitkeep (0 bytes)
CREATE myapp/src/environments/environment.prod.ts (51 bytes)
CREATE myapp/src/environments/environment.ts (662 bytes)
CREATE myapp/src/app/app.module.ts (314 bytes)
CREATE myapp/src/app/app.component.css (0 bytes)
CREATE myapp/src/app/app.component.html (25723 bytes)
CREATE myapp/src/app/app.component.spec.ts (939 bytes)
CREATE myapp/src/app/app.component.ts (209 bytes)
CREATE myapp/e2e/protractor.conf.js (808 bytes)
CREATE myapp/e2e/tsconfig.json (214 bytes)
CREATE myapp/e2e/src/app.e2e-spec.ts (638 bytes)
CREATE myapp/e2e/src/app.po.ts (301 bytes)
✔ Packages installed successfully.
cd myapp
ng add @nrwl/workspace
実行中のログ
? Would you like to share anonymous usage data about this project with the Angular Team at
Google under Google’s Privacy Policy at https://policies.google.com/privacy? For more
details and how to change this setting, see http://angular.io/analytics. No
Skipping installation: Package already installed
Renamed tsconfig.app.json -> apps/myapp/tsconfig.app.json
Renamed karma.conf.js -> apps/myapp/karma.conf.js
Renamed tsconfig.spec.json -> apps/myapp/tsconfig.spec.json
Renamed src -> apps/myapp/src
Renamed e2e -> apps/myapp-e2e
DELETE browserslist
DELETE tsconfig.app.json
DELETE tsconfig.spec.json
DELETE src/favicon.ico
DELETE src/index.html
DELETE src/main.ts
DELETE src/polyfills.ts
DELETE src/styles.css
DELETE src/test.ts
DELETE src/app/app.component.css
DELETE src/app/app.component.html
DELETE src/app/app.component.spec.ts
DELETE src/app/app.component.ts
DELETE src/app/app.module.ts
DELETE src/assets/.gitkeep
DELETE src/environments/environment.prod.ts
DELETE src/environments/environment.ts
DELETE e2e/protractor.conf.js
DELETE e2e/tsconfig.json
DELETE e2e/src/app.e2e-spec.ts
DELETE e2e/src/app.po.ts
CREATE apps/myapp/browserslist (429 bytes)
CREATE apps/myapp/tsconfig.app.json (219 bytes)
CREATE apps/myapp/karma.conf.js (1017 bytes)
CREATE apps/myapp/tsconfig.spec.json (278 bytes)
CREATE apps/myapp/src/favicon.ico (1642 bytes)
CREATE apps/myapp/src/index.html (291 bytes)
CREATE apps/myapp/src/main.ts (372 bytes)
CREATE apps/myapp/src/polyfills.ts (2835 bytes)
CREATE apps/myapp/src/styles.css (80 bytes)
CREATE apps/myapp/src/test.ts (753 bytes)
CREATE apps/myapp/src/app/app.component.css (0 bytes)
CREATE apps/myapp/src/app/app.component.html (25723 bytes)
CREATE apps/myapp/src/app/app.component.spec.ts (939 bytes)
CREATE apps/myapp/src/app/app.component.ts (209 bytes)
CREATE apps/myapp/src/app/app.module.ts (314 bytes)
CREATE apps/myapp/src/assets/.gitkeep (0 bytes)
CREATE apps/myapp/src/environments/environment.prod.ts (51 bytes)
CREATE apps/myapp/src/environments/environment.ts (662 bytes)
CREATE apps/myapp-e2e/protractor.conf.js (808 bytes)
CREATE apps/myapp-e2e/tsconfig.json (221 bytes)
CREATE apps/myapp-e2e/src/app.e2e-spec.ts (638 bytes)
CREATE apps/myapp-e2e/src/app.po.ts (301 bytes)
CREATE .prettierignore (57 bytes)
CREATE tools/tsconfig.tools.json (218 bytes)
CREATE tools/schematics/.gitkeep (0 bytes)
CREATE nx.json (280 bytes)
CREATE libs/.gitkeep (0 bytes)
CREATE .vscode/extensions.json (164 bytes)
CREATE .prettierrc (26 bytes)
UPDATE karma.conf.js (1012 bytes)
UPDATE package.json (2031 bytes)
UPDATE angular.json (4168 bytes)
UPDATE tslint.json (2261 bytes)
UPDATE tsconfig.json (579 bytes)
✔ Packages installed successfully.
ファイル移動後の、なにもファイルが入っていないディレクトリがノイズとして残るので除去します。
rm -rf ./e2e
rm -rf ./src
.
├── README.md
├── angular.json
├── apps
│ ├── myapp
│ │ ├── browserslist
│ │ ├── karma.conf.js
│ │ ├── src
│ │ │ ├── app
│ │ │ │ ├── app.component.css
│ │ │ │ ├── app.component.html
│ │ │ │ ├── app.component.spec.ts
│ │ │ │ ├── app.component.ts
│ │ │ │ └── app.module.ts
│ │ │ ├── assets
│ │ │ ├── environments
│ │ │ │ ├── environment.prod.ts
│ │ │ │ └── environment.ts
│ │ │ ├── favicon.ico
│ │ │ ├── index.html
│ │ │ ├── main.ts
│ │ │ ├── polyfills.ts
│ │ │ ├── styles.css
│ │ │ └── test.ts
│ │ ├── tsconfig.app.json
│ │ └── tsconfig.spec.json
│ └── myapp-e2e
│ ├── protractor.conf.js
│ ├── src
│ │ ├── app.e2e-spec.ts
│ │ └── app.po.ts
│ └── tsconfig.json
├── karma.conf.js
├── libs
├── node_modules
├── nx.json
├── package-lock.json
├── package.json
├── tools
│ ├── schematics
│ └── tsconfig.tools.json
├── tsconfig.json
└── tslint.json
ファイルツリーにもすでに違いがあるようです。1.を基準に「1.と2.」「1.と3.」の差分を確認します。
こちらは差がありませんでした。生成されるファイル、そのディレクトリ構造はともに同一です。
まぁまぁ差が出ました。
- │ ├── .gitkeep
- │ │ ├── jest.config.js
+ │ │ ├── karma.conf.js
- │ │ │ └── test-setup.ts
+ │ │ │ └── test.ts
- │ │ ├── tsconfig.json
- │ │ ├── tsconfig.spec.json
- │ │ └── tslint.json
+ │ │ └── tsconfig.spec.json
- │ ├── cypress.json
+ │ ├── protractor.conf.js
- │ │ ├── fixtures
- │ │ │ └── example.json
- │ │ ├── integration
- │ │ │ └── app.spec.ts
- │ │ ├── plugins
- │ │ │ └── index.js
- │ │ └── support
- │ │ ├── app.po.ts
- │ │ ├── commands.ts
- │ │ └── index.ts
- │ ├── tsconfig.e2e.json
- │ ├── tsconfig.json
- │ └── tslint.json
- ├── jest.config.js
+ │ │ ├── app.e2e-spec.ts
+ │ │ └── app.po.ts
+ │ └── tsconfig.json
+ ├── karma.conf.js
大きな違いはテストランナーJestとKarmaの違い、E2EテストフレームワークCypressとProtractorの違いです。つまりテスト環境全般についてはAngular ng new
による生成から変換したときと、最初からNxで生成したときで大きく異なります。
ng new
- Karma
- Protractor
create-nx-workspace
- Jest
- Cypress
変化の大きそうな package.json
についても見ておきます。
diff a-nx-empty/myworkspace/package.json b-nx-angular/myworkspace/package.json
32c32
< "@nrwl/angular": "^9.0.2",
---
> "@nrwl/angular": "9.0.2",
非常に地味ですが^
有無だけ差異ありで、内容自体は同一とみてよいでしょう。
こちらに関しては差が大きすぎるので、一旦fixpack
をかけます。
1.の`package.json`
{
"name": "myworkspace",
"version": "0.0.0",
"dependencies": {
"@angular/animations": "9.0.0",
"@angular/common": "9.0.0",
"@angular/compiler": "9.0.0",
"@angular/core": "9.0.0",
"@angular/forms": "9.0.0",
"@angular/platform-browser": "9.0.0",
"@angular/platform-browser-dynamic": "9.0.0",
"@angular/router": "9.0.0",
"@nrwl/angular": "^9.0.2",
"core-js": "^2.5.4",
"rxjs": "~6.5.0",
"zone.js": "^0.10.2"
},
"devDependencies": {
"@angular-devkit/build-angular": "0.900.1",
"@angular/cli": "9.0.1",
"@angular/compiler-cli": "9.0.0",
"@angular/language-service": "9.0.0",
"@nrwl/cypress": "9.0.2",
"@nrwl/jest": "9.0.2",
"@nrwl/workspace": "9.0.2",
"@types/jest": "24.0.9",
"@types/node": "~8.9.4",
"codelyzer": "~5.0.1",
"cypress": "^3.8.2",
"dotenv": "6.2.0",
"eslint": "6.1.0",
"jest": "24.1.0",
"jest-preset-angular": "8.0.0",
"prettier": "1.18.2",
"ts-jest": "24.0.0",
"ts-node": "~7.0.0",
"tslint": "~5.11.0",
"typescript": "~3.7.4"
},
"license": "MIT",
"private": true,
"scripts": {
"affected": "nx affected",
"affected:apps": "nx affected:apps",
"affected:build": "nx affected:build",
"affected:dep-graph": "nx affected:dep-graph",
"affected:e2e": "nx affected:e2e",
"affected:libs": "nx affected:libs",
"affected:lint": "nx affected:lint",
"affected:test": "nx affected:test",
"build": "ng build",
"dep-graph": "nx dep-graph",
"e2e": "ng e2e",
"format": "nx format:write",
"format:check": "nx format:check",
"format:write": "nx format:write",
"help": "nx help",
"lint": "nx workspace-lint && ng lint",
"ng": "ng",
"nx": "nx",
"postinstall": "ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points",
"start": "ng serve",
"test": "ng test",
"update": "ng update @nrwl/workspace",
"workspace-schematic": "nx workspace-schematic"
}
}
< "name": "myworkspace",
---
> "name": "myapp",
5,16c5,16
< "@angular/animations": "9.0.0",
< "@angular/common": "9.0.0",
< "@angular/compiler": "9.0.0",
< "@angular/core": "9.0.0",
< "@angular/forms": "9.0.0",
< "@angular/platform-browser": "9.0.0",
< "@angular/platform-browser-dynamic": "9.0.0",
< "@angular/router": "9.0.0",
< "@nrwl/angular": "^9.0.2",
< "core-js": "^2.5.4",
< "rxjs": "~6.5.0",
< "zone.js": "^0.10.2"
---
> "@angular/animations": "~9.0.2",
> "@angular/common": "~9.0.2",
> "@angular/compiler": "~9.0.2",
> "@angular/core": "~9.0.2",
> "@angular/forms": "~9.0.2",
> "@angular/platform-browser": "~9.0.2",
> "@angular/platform-browser-dynamic": "~9.0.2",
> "@angular/router": "~9.0.2",
> "@nrwl/angular": "9.0.2",
> "rxjs": "~6.5.4",
> "tslib": "^1.10.0",
> "zone.js": "~0.10.2"
19,24c19,22
< "@angular-devkit/build-angular": "0.900.1",
< "@angular/cli": "9.0.1",
< "@angular/compiler-cli": "9.0.0",
< "@angular/language-service": "9.0.0",
< "@nrwl/cypress": "9.0.2",
< "@nrwl/jest": "9.0.2",
---
> "@angular-devkit/build-angular": "~0.900.3",
> "@angular/cli": "~9.0.3",
> "@angular/compiler-cli": "~9.0.2",
> "@angular/language-service": "~9.0.2",
26,33c24,34
< "@types/jest": "24.0.9",
< "@types/node": "~8.9.4",
< "codelyzer": "~5.0.1",
< "cypress": "^3.8.2",
< "dotenv": "6.2.0",
< "eslint": "6.1.0",
< "jest": "24.1.0",
< "jest-preset-angular": "8.0.0",
---
> "@types/jasmine": "~3.5.0",
> "@types/jasminewd2": "~2.0.3",
> "@types/node": "^12.11.1",
> "codelyzer": "^5.1.2",
> "jasmine-core": "~3.5.0",
> "jasmine-spec-reporter": "~4.2.1",
> "karma": "~4.3.0",
> "karma-chrome-launcher": "~3.1.0",
> "karma-coverage-istanbul-reporter": "~2.1.0",
> "karma-jasmine": "~2.0.1",
> "karma-jasmine-html-reporter": "^1.4.2",
35,38c36,39
< "ts-jest": "24.0.0",
< "ts-node": "~7.0.0",
< "tslint": "~5.11.0",
< "typescript": "~3.7.4"
---
> "protractor": "~5.4.3",
> "ts-node": "~8.3.0",
> "tslint": "~5.18.0",
> "typescript": "~3.7.5"
40d40
< "license": "MIT",
61d60
< "postinstall": "ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points",
64a64
> "update:check": "ng update",
やはりJest, Karma, Protractor, Cypress周りに差分が現れました。Angular CLIをベースにしている3.はJasmineに関する依存が残っているのも特徴です。
Angular CLIにてAngularアプリケーションを管理する際の定義ファイルとなるangular.json
について確認します。
まったく差分はありませんでした。
diff a-nx-empty/myworkspace/angular.json b-nx-angular/myworkspace/angular.json
こちらは激しく差分が生じているので先にangular.json
自体にPrettierを処理し改行や整形由来の差分を除外します。
diff a-fixed/angular.json c-fixed/angular.json
1a2
> "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
2a4
> "newProjectRoot": "",
9c11
< "prefix": "myworkspace",
---
> "prefix": "app",
71a74,85
> "test": {
> "builder": "@angular-devkit/build-angular:karma",
> "options": {
> "main": "apps/myapp/src/test.ts",
> "polyfills": "apps/myapp/src/polyfills.ts",
> "tsConfig": "apps/myapp/tsconfig.spec.json",
> "karmaConfig": "apps/myapp/karma.conf.js",
> "assets": ["apps/myapp/src/favicon.ico", "apps/myapp/src/assets"],
> "styles": ["apps/myapp/src/styles.css"],
> "scripts": []
> }
> },
79,88c93
< "exclude": ["**/node_modules/**", "!apps/myapp/**"]
< }
< },
< "test": {
< "builder": "@nrwl/jest:jest",
< "options": {
< "jestConfig": "apps/myapp/jest.config.js",
< "tsConfig": "apps/myapp/tsconfig.spec.json",
< "passWithNoTests": true,
< "setupFile": "apps/myapp/src/test-setup.ts"
---
> "exclude": ["**/node_modules/**"]
94,95d98
< "root": "apps/myapp-e2e",
< "sourceRoot": "apps/myapp-e2e/src",
96a100
> "root": "apps/myapp-e2e",
99c103
< "builder": "@nrwl/cypress:cypress",
---
> "builder": "@angular-devkit/build-angular:protractor",
101,102c105
< "cypressConfig": "apps/myapp-e2e/cypress.json",
< "tsConfig": "apps/myapp-e2e/tsconfig.e2e.json",
---
> "protractorConfig": "apps/myapp-e2e/protractor.conf.js",
114,115c117,118
< "tsConfig": ["apps/myapp-e2e/tsconfig.e2e.json"],
< "exclude": ["**/node_modules/**", "!apps/myapp-e2e/**"]
---
> "tsConfig": "apps/myapp-e2e/tsconfig.json",
> "exclude": ["**/node_modules/**"]
120a124
> "defaultProject": "myapp",
122d125
< "defaultCollection": "@nrwl/angular",
124,134c127
< },
< "schematics": {
< "@nrwl/angular:application": {
< "unitTestRunner": "jest",
< "e2eTestRunner": "cypress"
< },
< "@nrwl/angular:library": {
< "unitTestRunner": "jest"
< }
< },
< "defaultProject": "myapp"
---
> }
案の定、テスト周りの設定が大きく異なります。"builder": "@nrwl/jest:jest"
, "builder": "@nrwl/cypress:cypress"
が最初から入っているのはありがたいですね。
"prefix": "myworkspace"
については、おそらく社名やサービス名を想定しているようなのですが、適宜変更することもあり得ると思います。
TypeScriptの設定ファイルについても確認します。
diff a-nx-empty/myworkspace/tsconfig.json b-nx-angular/myworkspace/tsconfig.json
差分はありません、安心です。
Prettier処理、プロパティのソート後について確認します。
diff a-fixed/tsconfig.json c-fixed/tsconfig.json
< "emitDecoratorMetadata": true,
---
> "downlevelIteration": true,
9c9
< "lib": ["es2017", "dom"],
---
> "lib": ["es2018", "dom"],
11a12
> "outDir": "./dist/out-tsc",
14,15d14
< "skipDefaultLibCheck": true,
< "skipLibCheck": true,
20c19,22
< "exclude": ["node_modules", "tmp"]
---
> "angularCompilerOptions": {
> "fullTemplateTypeCheck": true,
> "strictInjectionParameters": true
> }
3.のケースでemitDecoratorMetadata
が無くなっているのが驚きで、Angularアプリケーション開発には必須オプションだと思っていただけに、別の関心が生まれましたが今回は深追いしないことにします。
angularCompilerOptions
については3.のケースでは生成されていますが、1.2.のケースでは生成されないので、必要に応じて追記がよいかと思います。
なお、すべてのケースでstrict: true
は表記されないので、こちらも忘れず追記する必要があります。
最後にNxのワークスペースの定義を記述するファイルについて確認します。
diff a-nx-empty/myworkspace/nx.json b-nx-angular/myworkspace/nx.json
差分はありませんでした。これによって1.と2.の生成結果には違いがほぼないと言ってよさそうです。
{
"npmScope": "myworkspace",
"implicitDependencies": {
"angular.json": "*",
"package.json": {
"dependencies": "*",
"devDependencies": "*"
},
"tsconfig.json": "*",
"tslint.json": "*",
"nx.json": "*"
},
"projects": {
"myapp": {
"tags": []
},
"myapp-e2e": {
"tags": [],
"implicitDependencies": ["myapp"]
}
}
}
diff a-fixed/nx.json c-fixed/nx.json
2c2
< "npmScope": "myworkspace",
---
> "npmScope": "myapp",
5,8c5
< "package.json": {
< "dependencies": "*",
< "devDependencies": "*"
< },
---
> "package.json": "*",
18,19c15
< "tags": [],
< "implicitDependencies": ["myapp"]
---
> "tags": []
もともと1.にてmyworkspace
として作るか、3.にてmyapp
として作るかの違いが反映されていますが、それ以外は大きな違いはないようでした。
少々マニアックな記事になりましたが、業務案件での導入を検討する際、1.のケースと3.のケースについて差を気にする方は多いと思いまとめを作成しました。
1.2.についてはどちらも同じようですが、ひとつ重要な違いとして
Would you like to configure routing for this application?
この質問をCLI上でされるかどうかがあります。Routingに関する処理はあとからでも追加できますので、さほど大きな問題ではないですが、そこのひと手間を省略する場合は1.の手法をおすすめします。
1.3.をどちらにするかは工数次第かなと思いますが、既存案件をなるべく1.生成結果に馴染むようリファクタリングしたあと、1.で作った空ディレクトリに既存案件を配置する移行を進めたほうが、Nxの恩恵はより受けられるかと思います。特にテスト周りはゆくゆくKarma, Protractorなどが不要となる場合、依存関係定義上のノイズとなり得るため、angular.json
の生成結果の美しさを考慮すると、1.を基とした移行の方がよいかと思います。ここはこだわりが反映されそうです。
どのみち、CircleCIの設定ファイルなどの見直しのほうが影響大きいと思うので、迷いどころではありますね。サブパッケージの利用やSchematicsの利用を本格的に進めている場合でなければ見送りでよいかと思いますが、Schematics, Storybook, Cypress, Jestなどのサポートを魅力と捉える場合、工数次第では悪くないと感じます。
モノレポにすると何がうれしいか、Nxを導入すると何がうれしいかという観点はまったく触れなかった本稿ですが、何かの参考になれば。
それではまた。