diff --git a/.gitignore b/.gitignore index b8fb8dcdad..cf358d2e01 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ dist build .DS_Store tmp +yarn-error +.ng_pkg_build \ No newline at end of file diff --git a/e2e/schematics/application.test.ts b/e2e/schematics/application.test.ts index 18a7689a8d..d411852772 100644 --- a/e2e/schematics/application.test.ts +++ b/e2e/schematics/application.test.ts @@ -1,4 +1,11 @@ -import { newApp, newLib, newProject, runCLI, updateFile } from '../utils'; +import { + newApp, + newLib, + newProject, + runCLI, + updateFile, + cleanup +} from '../utils'; describe('Nrwl Workspace', () => { it( diff --git a/e2e/schematics/bazel-application.test.ts b/e2e/schematics/bazel-application.test.ts index 1b15b6708c..9bc36fc56c 100644 --- a/e2e/schematics/bazel-application.test.ts +++ b/e2e/schematics/bazel-application.test.ts @@ -20,3 +20,132 @@ xdescribe('Nrwl Workspace (Bazel)', () => { 1000000 ); }); + +// afterEach(() => { +// runCommand('bazel build ...'); +// }); + +// itShould('create a bazel project', () => { +// newBazelProject(); +// checkFilesExist('WORKSPACE', 'BUILD.bazel'); +// }); + +// itShould('create an app', () => { +// newApp('myApp --directory=myDir'); +// }); + +// itShould('create a lib', () => { +// newLib('myLib --directory=myDir'); + +// runCommand('bazel test //libs/my-dir/my-lib/src:test'); +// }); + +// itShould('allow adding a lib to a module', () => { +// updateFile( +// 'apps/my-dir/my-app/src/app/app.module.ts', +// `import { NgModule } from '@angular/core'; +// import { BrowserModule } from '@angular/platform-browser'; +// import { MyLibModule } from 'proj/libs/my-dir/my-lib/src/my-lib.module'; +// import { AppComponent } from './app.component'; +// import { StoreModule } from '@ngrx/store'; +// import { NxModule } from '@nrwl/nx'; + +// @NgModule({ +// imports: [BrowserModule, MyLibModule, StoreModule.forRoot({}), +// NxModule.forRoot()], declarations: [AppComponent], bootstrap: [AppComponent] +// }) +// export class AppModule {} +// `); + +// // TODO: Replace this with a buildozer command to add the lib as a dep. +// updateFile('apps/my-dir/my-app/src/app/BUILD.bazel', ` +// package(default_visibility = ["//visibility:public"]) + +// load("@angular//:index.bzl", "ng_module") + +// ng_module( +// name = "app", +// srcs = glob( +// ["*.ts"], +// exclude = ["*.spec.ts"], +// ), +// assets = [ +// "app.component.css", +// "app.component.html", +// ], +// deps = [ +// "//libs/my-dir/my-lib/src", +// "@rxjs", +// ], +// ) +// `); +// }); + +// itShould('add a module', () => { +// newModule('helloWorld --directory=myDir'); +// }); + +// itShould('run protractor', () => { +// const prodServerPort = 8080; +// headlessProtractorConfig(prodServerPort); +// runCommand([ +// 'node', 'node_modules/concurrently/src/main.js', +// '"bazel run //apps/my-dir/my-app/src:prodserver"', +// `"while ! nc -z 127.0.0.1 ${prodServerPort}; do sleep 1; done && ng +// e2e -s=false --app=my-dir/my-app"`, +// '--kill-others', '--success', 'first' +// ].join(' ')); + +// const devServerPort = 5432; +// headlessProtractorConfig(devServerPort); +// runCommand([ +// 'node', 'node_modules/concurrently/src/main.js', +// '"bazel run //apps/my-dir/my-app/src:devserver"', +// `"while ! nc -z 127.0.0.1 ${devServerPort}; do sleep 1; done && ng +// e2e -s=false --app=my-dir/my-app"`, +// '--kill-others', '--success', 'first' +// ].join(' ')); +// }); +// }); + +// function headlessProtractorConfig(port: number): void { +// return updateFile( +// 'protractor.conf.js', +// `const { SpecReporter } = require('jasmine-spec-reporter'); +// const { getAppDirectoryUsingCliConfig } = +// require('@nrwl/schematics/src/utils/cli-config-utils'); const appDir = +// getAppDirectoryUsingCliConfig(); + +// exports.config = { +// allScriptsTimeout: 11000, +// specs: [ +// appDir + '/e2e/**/*.e2e-spec.ts' +// ], +// multiCapabilities: { +// 'browserName': 'chrome', + +// chromeOptions: { +// args: [ +// '--headless', +// '--disable-gpu', +// '--window-size=1280x720', +// ], +// }, +// }, +// directConnect: true, +// baseUrl: 'http://localhost:${port}/', +// framework: 'jasmine', +// jasmineNodeOpts: { +// showColors: true, +// defaultTimeoutInterval: 30000, +// print: function() {} +// }, +// onPrepare() { +// require('ts-node').register({ +// project: appDir + '/e2e/tsconfig.e2e.json' +// }); +// jasmine.getEnv().addReporter(new SpecReporter({ spec: { +// displayStacktrace: true } })); +// } +// };`); +// } diff --git a/e2e/utils.ts b/e2e/utils.ts index 95b57c88e2..e44ea802b4 100644 --- a/e2e/utils.ts +++ b/e2e/utils.ts @@ -14,7 +14,7 @@ export function runNgNew(command?: string, silent?: boolean): string { export function newProject(): void { cleanup(); if (!directoryExists('./tmp/proj_backup')) { - //TODO delete the try catch after 0.8.0 is released + // TODO delete the try catch after 0.8.0 is released try { runNgNew('--collection=@nrwl/schematics --npmScope=proj', true); } catch (e) {} @@ -27,8 +27,8 @@ export function newProject(): void { export function newBazelProject(): void { cleanup(); - if (!directoryExists('./tmp/proj_backup')) { - //TODO delete the try catch after 0.8.0 is released + if (!directoryExists('./tmp/proj_bazel_backup')) { + // TODO delete the try catch after 0.8.0 is released try { runNgNew('--collection=@nrwl/bazel --npmScope=proj', true); } catch (e) {} @@ -36,16 +36,14 @@ export function newBazelProject(): void { execSync('npm run postinstall', { cwd: './tmp/proj' }); execSync('mv ./tmp/proj ./tmp/proj_backup'); } - execSync('cp -a ./tmp/proj_backup ./tmp/proj'); + execSync('cp -a ./tmp/proj_bazel_backup ./tmp/proj'); } export function createNxWorkspace(command: string): string { cleanup(); return execSync( - `node ../node_modules/@nrwl/schematics/bin/create-nx-workspace.js ${command}`, - { - cwd: `./tmp` - } + `node ../node_modules/@nrwl/schematics/bin/create-nx-workspace.js --yarn ${command}`, + { cwd: `./tmp` } ).toString(); } @@ -98,6 +96,10 @@ export function newLib(name: string): string { return runCLI(`generate lib ${name}`); } +export function newModule(name: string): string { + return runCLI(`generate module ${name}`); +} + export function runSchematic(command: string): string { return execSync(`./node_modules/.bin/schematics ${command}`, { cwd: `./tmp/${projectName}` @@ -132,6 +134,10 @@ export function cleanup() { execSync('rm -rf ./tmp/proj'); } +export function purge() { + execSync('rm -rf ./tmp'); +} + export function getCwd(): string { return process.cwd(); } diff --git a/package.json b/package.json index d022d1e960..6827a61645 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "private": true, "scripts": { - "build": "./scripts/build.sh", + "build": "ng-packagr -p packages/nx/ng-package.json && ./scripts/build.sh", "e2e": "./scripts/e2e.sh", "format": "precise-commits --whitelist=\"{packages,e2e}/**/*.ts\"", "linknpm": "./scripts/link.sh", @@ -13,8 +13,9 @@ "release": "./scripts/release.sh", "copy": "./scripts/copy.sh", "test:schematics": "yarn linknpm && ./scripts/test_schematics.sh", - "test:nx": "yarn linknpm && ./scripts/test_nx.sh", - "test": "yarn linknpm && ./scripts/test_nx.sh && ./scripts/test_schematics.sh", + "test:nx": "./scripts/link-spec.sh && ./scripts/test_nx.sh", + "test": + "./scripts/link-spec.sh && ./scripts/test_nx.sh && ./scripts/test_schematics.sh", "checkformat": "echo 1", "publish_npm": "./scripts/publish.sh", "precommit": "yarn checkformat" @@ -32,10 +33,10 @@ "@angular/platform-browser-dynamic": "5.2.7", "@angular/router": "5.2.7", "@angular/upgrade": "5.2.7", - "@ngrx/effects": "5.1.0", - "@ngrx/router-store": "5.0.1", - "@ngrx/store": "5.1.0", - "@ngrx/store-devtools": "5.1.0", + "@ngrx/effects": "5.2.0", + "@ngrx/router-store": "5.2.0", + "@ngrx/store": "5.2.0", + "@ngrx/store-devtools": "5.2.0", "@types/jasmine": "~2.8.3", "@types/jasminewd2": "~2.0.2", "@types/node": "~6.0.60", @@ -43,6 +44,7 @@ "angular": "1.6.6", "app-root-path": "^2.0.1", "cosmiconfig": "^4.0.0", + "ng-packagr": "2.2.0", "husky": "^0.14.3", "jasmine-core": "~2.8.0", "jasmine-spec-reporter": "~4.2.1", @@ -64,9 +66,6 @@ "author": "Victor Savkin", "license": "MIT", "jest": { - "modulePathIgnorePatterns": [ - "tmp", - "files" - ] + "modulePathIgnorePatterns": ["tmp", "files"] } } diff --git a/packages/bazel/README.md b/packages/bazel/README.md new file mode 100644 index 0000000000..6467a66653 --- /dev/null +++ b/packages/bazel/README.md @@ -0,0 +1,41 @@ +Bazel Commands + +## Add new app + +node_modules/.bin/ng generate app [name] + +Example: node_modules/.bin/ng generate app test + +## Add new component + +node_modules/.bin/ng generate component [name] --directory=[dir] + +Example: node_modules/.bin/ng generate component friends --directory=myDir + +* must manually import the component's Bazel rule in the consuming Bazel rule + +## Add new lib + +node_modules/.bin/ng generate lib [name] + +Example: node_modules/.bin/ng generate lib mylib + +* must manually import the lib's Bazel rule in the consuming Bazel rule + +## Run dev server + +ibazel run apps/[app specific path]]/src:devserver (anything between apps/\*\*/src points to a specific app) + +Example: ibazel run apps/my-dir/my-app/src:devserver + +## Run prod server + +bazel run apps/[app specific path]]/src:prodserver (anything between apps/\*\*/src points to a specific app) + +Example: bazel run apps/my-dir/my-app/src:prodserver + +## Run unit tests + +ibazel test //libs/mylib/src:test + +* currently works for libs diff --git a/packages/bazel/src/collection.json b/packages/bazel/src/collection.json index acdd631e62..5ff8e26353 100644 --- a/packages/bazel/src/collection.json +++ b/packages/bazel/src/collection.json @@ -11,6 +11,19 @@ "factory": "./collection/app", "schema": "./collection/app/schema.json", "description": "Create an application." + }, + "lib": { + "factory": "./collection/lib", + "schema": "./collection/lib/schema.json", + "description": "Create a library" + }, + "module": { + "aliases": [ + "m" + ], + "factory": "./collection/module", + "schema": "./collection/module/schema.json", + "description": "Create a Module" } } -} +} \ No newline at end of file diff --git a/packages/bazel/src/collection/app/app.spec.ts b/packages/bazel/src/collection/app/app.spec.ts deleted file mode 100644 index c68c4ed9db..0000000000 --- a/packages/bazel/src/collection/app/app.spec.ts +++ /dev/null @@ -1,236 +0,0 @@ -import { SchematicTestRunner } from '@angular-devkit/schematics/testing'; -import * as path from 'path'; -import { Tree, VirtualTree } from '@angular-devkit/schematics'; -import { createEmptyWorkspace } from '../../../../schematics/src/utils/testing-utils'; -import { getFileContent } from '@schematics/angular/utility/test'; -import * as stripJsonComments from 'strip-json-comments'; - -describe('app', () => { - const schematicRunner = new SchematicTestRunner( - '@nrwl/bazel', - path.join(__dirname, '../../collection.json') - ); - - let appTree: Tree; - - beforeEach(() => { - appTree = new VirtualTree(); - appTree = createEmptyWorkspace(appTree); - }); - - describe('not nested', () => { - it('should update angular-cli.json', () => { - const tree = schematicRunner.runSchematic( - 'app', - { name: 'myApp', npmScope: 'nrwl' }, - appTree - ); - const updatedAngularCLIJson = JSON.parse( - getFileContent(tree, '/.angular-cli.json') - ); - expect(updatedAngularCLIJson.apps).toEqual([ - { - assets: ['assets', 'favicon.ico'], - environmentSource: 'environments/environment.ts', - environments: { - dev: 'environments/environment.ts', - prod: 'environments/environment.prod.ts' - }, - index: 'index.html', - main: 'main.ts', - name: 'my-app', - outDir: 'dist/apps/my-app', - polyfills: 'polyfills.ts', - prefix: 'app', - root: 'apps/my-app/src', - scripts: [], - styles: ['styles.css'], - test: '../../../test.js', - testTsconfig: '../../../tsconfig.spec.json', - tsconfig: 'tsconfig.app.json' - } - ]); - expect(updatedAngularCLIJson.lint).toEqual([ - { - project: `apps/my-app/src/tsconfig.app.json`, - exclude: '**/node_modules/**' - }, - { - project: `apps/my-app/e2e/tsconfig.e2e.json`, - exclude: '**/node_modules/**' - } - ]); - }); - - it('should generate files', () => { - const tree = schematicRunner.runSchematic( - 'app', - { name: 'myApp', npmScope: 'nrwl' }, - appTree - ); - expect(tree.exists('apps/my-app/src/main.ts')).toBeTruthy(); - expect(tree.exists('apps/my-app/src/app/app.module.ts')).toBeTruthy(); - expect(tree.exists('apps/my-app/src/app/app.component.ts')).toBeTruthy(); - expect(tree.exists('apps/my-app/e2e/app.po.ts')).toBeTruthy(); - expect( - getFileContent(tree, 'apps/my-app/src/app/app.module.ts') - ).toContain('class AppModule'); - - const tsconfigApp = JSON.parse( - stripJsonComments( - getFileContent(tree, 'apps/my-app/src/tsconfig.app.json') - ) - ); - expect(tsconfigApp.compilerOptions.outDir).toEqual( - '../../../dist/out-tsc/apps/my-app' - ); - - const tsconfigE2E = JSON.parse( - stripJsonComments( - getFileContent(tree, 'apps/my-app/e2e/tsconfig.e2e.json') - ) - ); - expect(tsconfigE2E.compilerOptions.outDir).toEqual( - '../../../dist/out-tsc/e2e/my-app' - ); - }); - }); - - describe('nested', () => { - it('should update angular-cli.json', () => { - const tree = schematicRunner.runSchematic( - 'app', - { name: 'myApp', npmScope: 'nrwl', directory: 'myDir' }, - appTree - ); - const updatedAngularCLIJson = JSON.parse( - getFileContent(tree, '/.angular-cli.json') - ); - expect(updatedAngularCLIJson.apps).toEqual([ - { - assets: ['assets', 'favicon.ico'], - environmentSource: 'environments/environment.ts', - environments: { - dev: 'environments/environment.ts', - prod: 'environments/environment.prod.ts' - }, - index: 'index.html', - main: 'main.ts', - name: 'my-dir/my-app', - outDir: 'dist/apps/my-dir/my-app', - polyfills: 'polyfills.ts', - prefix: 'app', - root: 'apps/my-dir/my-app/src', - scripts: [], - styles: ['styles.css'], - test: '../../../../test.js', - testTsconfig: '../../../../tsconfig.spec.json', - tsconfig: 'tsconfig.app.json' - } - ]); - - expect(updatedAngularCLIJson.lint).toEqual([ - { - project: `apps/my-dir/my-app/src/tsconfig.app.json`, - exclude: '**/node_modules/**' - }, - { - project: `apps/my-dir/my-app/e2e/tsconfig.e2e.json`, - exclude: '**/node_modules/**' - } - ]); - }); - - it('should generate files', () => { - const tree = schematicRunner.runSchematic( - 'app', - { name: 'myApp', npmScope: 'nrwl', directory: 'myDir' }, - appTree - ); - expect(tree.exists('apps/my-dir/my-app/src/main.ts')).toBeTruthy(); - expect( - tree.exists('apps/my-dir/my-app/src/app/app.module.ts') - ).toBeTruthy(); - expect( - tree.exists('apps/my-dir/my-app/src/app/app.component.ts') - ).toBeTruthy(); - expect(tree.exists('apps/my-dir/my-app/e2e/app.po.ts')).toBeTruthy(); - expect( - getFileContent(tree, 'apps/my-dir/my-app/src/app/app.module.ts') - ).toContain('class AppModule'); - - const tsconfigApp = JSON.parse( - stripJsonComments( - getFileContent(tree, 'apps/my-dir/my-app/src/tsconfig.app.json') - ) - ); - expect(tsconfigApp.compilerOptions.outDir).toEqual( - '../../../../dist/out-tsc/apps/my-dir/my-app' - ); - - const tsconfigE2E = JSON.parse( - stripJsonComments( - getFileContent(tree, 'apps/my-dir/my-app/e2e/tsconfig.e2e.json') - ) - ); - expect(tsconfigE2E.compilerOptions.outDir).toEqual( - '../../../../dist/out-tsc/e2e/my-dir/my-app' - ); - }); - }); - - it('should import NgModule', () => { - const tree = schematicRunner.runSchematic( - 'app', - { name: 'myApp', npmScope: 'nrwl', directory: 'myDir' }, - appTree - ); - expect( - getFileContent(tree, 'apps/my-dir/my-app/src/app/app.module.ts') - ).toContain('NxModule.forRoot()'); - }); - - describe('routing', () => { - it('should include RouterTestingModule', () => { - const tree = schematicRunner.runSchematic( - 'app', - { name: 'myApp', npmScope: 'nrwl', directory: 'myDir', routing: true }, - appTree - ); - expect( - getFileContent(tree, 'apps/my-dir/my-app/src/app/app.module.ts') - ).toContain('RouterModule.forRoot'); - expect( - getFileContent(tree, 'apps/my-dir/my-app/src/app/app.component.spec.ts') - ).toContain('imports: [RouterTestingModule]'); - }); - }); - - describe('view encapsulation', () => { - it('should not set Component encapsulation metadata if option flag not included', () => { - const tree = schematicRunner.runSchematic( - 'app', - { name: 'myApp', npmScope: 'nrwl', directory: 'myDir' }, - appTree - ); - expect( - getFileContent(tree, 'apps/my-dir/my-app/src/app/app.component.ts') - ).not.toContain('encapsulation: '); - }); - it('should set Component encapsulation metadata if option flag is included', () => { - const tree = schematicRunner.runSchematic( - 'app', - { - name: 'myApp', - npmScope: 'nrwl', - directory: 'myDir', - viewEncapsulation: 'Native' - }, - appTree - ); - expect( - getFileContent(tree, 'apps/my-dir/my-app/src/app/app.component.ts') - ).toContain('encapsulation: ViewEncapsulation.Native'); - }); - }); -}); diff --git a/packages/bazel/src/collection/app/files/apps/__fullName__/__sourceDir__/BUILD.bazel b/packages/bazel/src/collection/app/files/apps/__fullName__/__sourceDir__/BUILD.bazel new file mode 100644 index 0000000000..d6debbfb82 --- /dev/null +++ b/packages/bazel/src/collection/app/files/apps/__fullName__/__sourceDir__/BUILD.bazel @@ -0,0 +1,57 @@ +load("@angular//:index.bzl", "ng_module") +load("@build_bazel_rules_typescript//:defs.bzl", "ts_devserver") + +package(default_visibility = ["//visibility:public"]) + +ng_module( + name = "<%= sourceDir %>", + srcs = glob(["main.ts"]), + deps = [ + "//apps/<%= fullName %>/src/app", + "@rxjs", + ], +) + +# Needed because the devserver only loads static files that appear under this +# package. +genrule( + name = "zone.js", + srcs = ["//:node_modules/zone.js/dist/zone.min.js"], + outs = ["zone.min.js"], + cmd = "cp $< $@", +) + +STATIC_FILES = [ + "favicon.ico", + "index.html", + "styles.css", + ":zone.js", +] + +ts_devserver( + name = "devserver", + data = ["//apps/<%= fullName %>/src/assets"], + entry_module = "proj/apps/<%= fullName %>/src/main", + scripts = ["//:angular_bundles"], + serving_path = "/bundle.min.js", + static_files = STATIC_FILES, + deps = [":<%= sourceDir %>"], +) + +load("@build_bazel_rules_nodejs//:defs.bzl", "rollup_bundle", "nodejs_binary") + +rollup_bundle( + name = "bundle", + entry_point = "proj/apps/<%= fullName %>/src/main", + deps = [":<%= sourceDir %>"], +) + +nodejs_binary( + name = "prodserver", + args = ["./apps/<%= fullName %>/src"], + data = STATIC_FILES + [ + ":bundle", + "//apps/<%= fullName %>/src/assets", + ], + entry_point = "http-server/bin/http-server", +) diff --git a/packages/bazel/src/collection/app/files/apps/__fullName__/__sourceDir__/assets/BUILD.bazel b/packages/bazel/src/collection/app/files/apps/__fullName__/__sourceDir__/assets/BUILD.bazel new file mode 100644 index 0000000000..1ff978212a --- /dev/null +++ b/packages/bazel/src/collection/app/files/apps/__fullName__/__sourceDir__/assets/BUILD.bazel @@ -0,0 +1,6 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "assets", + srcs = glob(["*"]), +) diff --git a/packages/bazel/src/collection/app/files/apps/__fullName__/__sourceDir__/environments/environment.prod.ts__tmpl__ b/packages/bazel/src/collection/app/files/apps/__fullName__/__sourceDir__/environments/environment.prod.ts__tmpl__ deleted file mode 100644 index 3612073bc3..0000000000 --- a/packages/bazel/src/collection/app/files/apps/__fullName__/__sourceDir__/environments/environment.prod.ts__tmpl__ +++ /dev/null @@ -1,3 +0,0 @@ -export const environment = { - production: true -}; diff --git a/packages/bazel/src/collection/app/files/apps/__fullName__/__sourceDir__/environments/environment.ts__tmpl__ b/packages/bazel/src/collection/app/files/apps/__fullName__/__sourceDir__/environments/environment.ts__tmpl__ deleted file mode 100644 index b7f639aeca..0000000000 --- a/packages/bazel/src/collection/app/files/apps/__fullName__/__sourceDir__/environments/environment.ts__tmpl__ +++ /dev/null @@ -1,8 +0,0 @@ -// The file contents for the current environment will overwrite these during build. -// The build system defaults to the dev environment which uses `environment.ts`, but if you do -// `ng build --env=prod` then `environment.prod.ts` will be used instead. -// The list of which env maps to which file can be found in `.angular-cli.json`. - -export const environment = { - production: false -}; diff --git a/packages/bazel/src/collection/app/files/apps/__fullName__/__sourceDir__/index.html__tmpl__ b/packages/bazel/src/collection/app/files/apps/__fullName__/__sourceDir__/index.html__tmpl__ index cd8a591155..57b68e2eab 100644 --- a/packages/bazel/src/collection/app/files/apps/__fullName__/__sourceDir__/index.html__tmpl__ +++ b/packages/bazel/src/collection/app/files/apps/__fullName__/__sourceDir__/index.html__tmpl__ @@ -4,11 +4,14 @@