diff --git a/.github/workflows/docs-hosting-merge.yml b/.github/workflows/docs-hosting-merge.yml new file mode 100644 index 000000000..ec29a6455 --- /dev/null +++ b/.github/workflows/docs-hosting-merge.yml @@ -0,0 +1,34 @@ +# This file was auto-generated by the Firebase CLI +# https://github.com/firebase/firebase-tools + +name: Deploy to GitHub README.md on merge +'on': + push: + branches: + - main +jobs: + update_docs: + runs-on: ubuntu-latest + steps: + - name: Checkout the repository + uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Production build (client & server & function) + run: npm run nx run docs:build + + - name: Update main readme file + uses: EndBug/add-and-commit@v7 + with: + author_name: push-based.io + author_email: opensource@push-based.io + message: 'Update main readme file' + add: '*' diff --git a/.github/workflows/firebase-hosting-merge.yml b/.github/workflows/firebase-hosting-merge.yml index 39f397666..91f3e1380 100644 --- a/.github/workflows/firebase-hosting-merge.yml +++ b/.github/workflows/firebase-hosting-merge.yml @@ -7,7 +7,7 @@ name: Deploy to Firebase Hosting on merge branches: - main jobs: - build_and_deploy: + deploy_firebase_function: runs-on: ubuntu-latest steps: - name: Checkout the repository @@ -41,14 +41,3 @@ jobs: url: https://angular-movies-a12d3.web.app # url: ${{ fromJson(steps.deployStep.outputs.urls)[0] }} // @TODO figure out why outputs urls are different from `https://angular-movies-a12d3.web.app` rcPath: ./projects/movies-user-flows/.user-flowrc.json - - - name: Update readme with bundle stats - run: npm run nx update-readme movies - - - name: Commit measures - uses: EndBug/add-and-commit@v7 - with: - author_name: push-based.io - author_email: opensource@push-based.io - message: 'Persist stats.json bundle-size report and readme' - add: '*' diff --git a/.github/workflows/firebase-hosting-pull-request.yml b/.github/workflows/firebase-hosting-pull-request.yml index 573ae9a32..05c94fbd5 100644 --- a/.github/workflows/firebase-hosting-pull-request.yml +++ b/.github/workflows/firebase-hosting-pull-request.yml @@ -4,7 +4,7 @@ name: Deploy to Firebase Preview Channel Hosting on PR 'on': pull_request jobs: - build_and_preview: + deploy_firebase_preview: if: '${{ github.event.pull_request.head.repo.full_name == github.repository }}' runs-on: ubuntu-latest steps: @@ -42,14 +42,3 @@ jobs: url: ${{ fromJson(steps.previewDeployStep.outputs.urls)[0] }} rcPath: projects/movies-user-flows/.user-flowrc.json outPath: dist/user-flow/ng-universal-express - - - name: Update readme with bundle stats - run: npm run nx update-readme movies - - - name: Commit measures - uses: EndBug/add-and-commit@v7 - with: - author_name: push-based.io - author_email: opensource@push-based.io - message: 'Persist stats.json bundle-size report and readme' - add: '*' diff --git a/README.md b/README.md index a071155b8..c7da02156 100644 --- a/README.md +++ b/README.md @@ -30,12 +30,6 @@ For now you can search the codebase for "Perf Tip" later on there will be proppe **Bundle Stats** - - - - - - | Names | Size | | --- | --- | @@ -63,12 +57,6 @@ For now you can search the codebase for "Perf Tip" later on there will be proppe - - - - - - ## Comparison to next and nuxt - [angular](https://angular-movies-a12d3.web.app/list/category/popular) diff --git a/projects/docs/.eslintrc.json b/projects/docs/.eslintrc.json new file mode 100644 index 000000000..bca8fff84 --- /dev/null +++ b/projects/docs/.eslintrc.json @@ -0,0 +1,33 @@ +{ + "extends": [ + "../.eslintrc.json" + ], + "ignorePatterns": [ + "!**/*" + ], + "overrides": [ + { + "files": [ + "*.ts", + "*.tsx", + "*.js", + "*.jsx" + ], + "rules": {} + }, + { + "files": [ + "*.ts", + "*.tsx" + ], + "rules": {} + }, + { + "files": [ + "*.js", + "*.jsx" + ], + "rules": {} + } + ] +} diff --git a/projects/docs/README.md b/projects/docs/README.md new file mode 100644 index 000000000..5561e1229 --- /dev/null +++ b/projects/docs/README.md @@ -0,0 +1,102 @@ +# angular-movies + +This is a Movies App built using [Angular](https://angular.io) +and [RxAngular](https://github.com/rx-angular/rx-angular). +As data source the [The Movie Database (TMDB)](https://www.themoviedb.org/) API is used. + +[![angular-and-rx-angular](https://user-images.githubusercontent.com/10064416/154189195-c32cbdec-b061-46a5-8590-a9e3d8dc050a.png)](https://www.rx-angular.io/) + +## [Demo](https://angular-movies-a12d3.web.app/list/category/popular) + +A [live deployment](https://angular-movies-a12d3.web.app/list/category/popular) of this app is available to try it out. + +## Performance Optimizations + +[![angular-movies--after-before](https://user-images.githubusercontent.com/10064416/155904454-f70b5bb5-6591-497a-9d21-dca0e2940566.gif)](https://www.webpagetest.org/video/compare.php?tests=220216_BiDcPP_CVM,220216_AiDcBN_ETK) + +For now you can search the codebase for "Perf Tip" later on there will be propper documentation here. + +[Measures before optimization](https://lighthouse-metrics.com/checks/9ddeb46e-2c28-453c-b719-cf080a01b13c) +[![angular-movies-before_michael-hladky](https://user-images.githubusercontent.com/10064416/137785051-1cf9f63a-e803-4d92-a952-c327b7628530.PNG)](https://lighthouse-metrics.com/checks/9ddeb46e-2c28-453c-b719-cf080a01b13c) + +[Measures after optimization](https://lighthouse-metrics.com/checks/6a888a17-b17b-46a6-abc9-e605b73a530c/runs/503701ad-36aa-43ad-8de3-cb40e775c770) +![angular-movies-after-optimization_michael-hladky](https://user-images.githubusercontent.com/10064416/146446241-ad9eeed4-b0a4-44a2-a88e-4ea7c97e1acf.PNG) + +**Bundle Stats** + + + + +## Comparison to next and nuxt + +- [angular](https://angular-movies-a12d3.web.app/list/category/popular) +- [next](https://movies.zaps.dev/?category=Popular&page=1) +- [nuxt](https://movies.jason.codes/movie/category/popular) + +[![angular-vs-next-vs-nuxt](https://user-images.githubusercontent.com/10064416/155904543-333e1c25-7c01-470a-b399-40eee4c9d02c.gif)](https://www.webpagetest.org/video/compare.php?tests=220216_AiDcBJ_EAA,220216_BiDcER_CDY,220216_BiDc68_CDZ) + +## Contributing + +Contributions are always welcome! + +For large changes, please file an issue to discuss your proposed changes with us before working on a PR :) + +## Installation + +Clone and install the dependencies for `angular-movies` locally: + +```bash + git clone https://github.com/tastejs/angular-movies.git + cd angular-movies + npm install +``` + +## Quick setup + +1. Take a copy of `src/environments/environment.local.example.ts` and re-name + to `src/environments/environment.production.ts` +2. Get your TMDb API key +3. Get your TMDB API read access token +4. Enter the details into the `src/environments/environment.production.ts` file + +## Running locally + +* `npm run build:dev`: dev build +* `npm run build:prod`: production build +* `npm run build:prod:ssr`: production build for SSR +* `npm run start`: serve the project locally for development +* `npm run start:ssr:dev`: serve the project locally SSR for development +* `npm run start:ssr:prod`: serve the project locally SSR for production +* `npm run analyze:bundlesize`: bundle size analysis + +## Tech Stack + +Built with: + +* [Angular](https://angular.io) +* [rx-angular](https://github.com/rx-angular/rx-angular) + +[![angular-and-rx-angular](https://user-images.githubusercontent.com/10064416/154189195-c32cbdec-b061-46a5-8590-a9e3d8dc050a.png)](https://www.rx-angular.io/) + +Measures: + +* Bundle sice listed fron dist +* Comparison videos with [webpagetest](https://www.webpagetest.org) +* Lighthoure reports with [lighthouse-metrics](https://lighthouse-metrics.com) +* User-flows created with [@push-based/user-flow](https://www.npmjs.com/package/@push-based/user-flow) + +## Authors + +- [push-based.io](https://push-based.io) +- [Michael Hladky](https://github.com/BioPhoton) +- [Kirill Karnaukhov](https://github.com/Karnaukhov-kh) +- [Julian Jandl](https://github.com/HoebbelsB) +- [Vojtech MaĊĦek](https://github.com/vmasek) +- [Enea Jahollari](https://github.com/eneajaho) +- [Matthieu Riegler](https://github.com/jeanmeche) + +Based on the original `angular-movies` foundation by [@clamarque](https://github.com/clamarque/angular-movies). + +## License + +[MIT](https://choosealicense.com/licenses/mit/) diff --git a/projects/docs/project.json b/projects/docs/project.json new file mode 100644 index 000000000..7c0046691 --- /dev/null +++ b/projects/docs/project.json @@ -0,0 +1,44 @@ +{ + "name": "docs", + "$schema": "../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "movies-user-flows/src", + "projectType": "library", + "implicitDependencies": [ + "movies" + ], + "targets": { + "build": { + "outputs": [ + "./README.md" + ], + "executor": "nx:run-commands", + "options": { + "commands": [ + "npx cpx dist/projects/movies/browser/stats.json dist/measures/movies", + "nx run docs:generate-bundle-audit", + "nx run docs:update-readme" + ], + "parallel": false + } + }, + "generate-bundle-audit": { + "executor": "nx:run-commands", + "options": { + "commands": [ + "npx webpack-bundle-analyzer dist/projects/movies/browser/stats.json -m static -r dist/measures/movies/bundle-size-report.prod.html" + ], + "parallel": false + } + }, + "update-readme": { + "executor": "nx:run-commands", + "options": { + "commands": [ + "npx ts-node -P ./projects/docs/tsconfig.tooling.json ./projects/docs/tooling/bundle-stats/index.ts update-bundle-stats --stats=./dist/measures/movies/stats.json --target=./README.md --source=./projects/docs/README.md" + ], + "parallel": false + } + } + }, + "tags": [] +} diff --git a/tooling/bundle-stats/Readme.md b/projects/docs/tooling/bundle-stats/Readme.md similarity index 100% rename from tooling/bundle-stats/Readme.md rename to projects/docs/tooling/bundle-stats/Readme.md diff --git a/tooling/bundle-stats/commands/update-docs.ts b/projects/docs/tooling/bundle-stats/commands/update-docs.ts similarity index 79% rename from tooling/bundle-stats/commands/update-docs.ts rename to projects/docs/tooling/bundle-stats/commands/update-docs.ts index 54074dd31..58b63fd79 100644 --- a/tooling/bundle-stats/commands/update-docs.ts +++ b/projects/docs/tooling/bundle-stats/commands/update-docs.ts @@ -1,14 +1,15 @@ -import { YargsCommandObject } from '../../cli/model'; -import { getCliParam } from '../../cli/utils'; -import { formatBytes, formatChunkName, readFile } from '../utils'; +import {YargsCommandObject} from '../../../../../tooling/cli/model'; +import {getCliParam} from '../../../../../tooling/cli/utils'; +import {formatBytes, formatChunkName, readFile} from '../utils'; import * as fs from 'fs'; export async function run(): Promise { - const statsPath: string = getCliParam(['stats', 's']) || './stats.json'; - const readmePath: string = getCliParam(['target', 't']) || './readme.md'; + const statsPath: string = getCliParam(['stats', 's']) || ''; + const sourcePath: string = getCliParam(['source', 'r']) || ''; + const targetPath: string = getCliParam(['target', 't']) || ''; const stats = readFile(statsPath); - const readme = readFile(readmePath, 'string'); + const readme = readFile(sourcePath, 'string'); const [top, rest] = readme.split(''); if (rest === undefined) { @@ -56,7 +57,7 @@ export async function run(): Promise { ` + bottom; - fs.writeFileSync(readmePath, statsContent); + fs.writeFileSync(targetPath, statsContent); } const command = 'update-bundle-stats'; diff --git a/tooling/bundle-stats/index.ts b/projects/docs/tooling/bundle-stats/index.ts similarity index 75% rename from tooling/bundle-stats/index.ts rename to projects/docs/tooling/bundle-stats/index.ts index 0e1a22fa4..19ecb6ad0 100644 --- a/tooling/bundle-stats/index.ts +++ b/projects/docs/tooling/bundle-stats/index.ts @@ -1,7 +1,7 @@ -import { Options } from 'yargs'; -import { YargsCommandObject } from '../cli/model'; -import { updateDocsCommand } from './commands/update-docs'; -import { runCli } from '../cli'; +import {Options} from 'yargs'; +import {YargsCommandObject} from '../../../../tooling/cli/model'; +import {updateDocsCommand} from './commands/update-docs'; +import {runCli} from '../../../../tooling/cli'; const OPTIONS: { [key: string]: Options } = { verbose: { diff --git a/tooling/bundle-stats/utils.ts b/projects/docs/tooling/bundle-stats/utils.ts similarity index 100% rename from tooling/bundle-stats/utils.ts rename to projects/docs/tooling/bundle-stats/utils.ts diff --git a/projects/docs/tsconfig.tooling.json b/projects/docs/tsconfig.tooling.json new file mode 100644 index 000000000..acf8c9bd2 --- /dev/null +++ b/projects/docs/tsconfig.tooling.json @@ -0,0 +1,13 @@ +{ + // This is an alias to @tsconfig/node12: https://github.com/tsconfig/bases + "extends": "../../tsconfig.json", + // Most ts-node options can be specified here using their programmatic names. + "ts-node": { + // It is faster to skip typechecking. + // Remove if you want ts-node to do typechecking. + "transpileOnly": true, + "files": true, + "compilerOptions": {} + }, + "compilerOptions": {} +} diff --git a/projects/movies-user-flows/project.json b/projects/movies-user-flows/project.json index 80d875456..6306ba1e0 100644 --- a/projects/movies-user-flows/project.json +++ b/projects/movies-user-flows/project.json @@ -1,5 +1,5 @@ { - "name": "_movies-user-flows", + "name": "movies-user-flows", "$schema": "../node_modules/nx/schemas/project-schema.json", "sourceRoot": "movies-user-flows/src", "projectType": "library", diff --git a/projects/movies/project.json b/projects/movies/project.json index 24f576d66..293d2f8b0 100644 --- a/projects/movies/project.json +++ b/projects/movies/project.json @@ -148,33 +148,6 @@ "parallel": false } }, - "build-report": { - "dependsOn": [ - "build" - ], - "executor": "nx:run-commands", - "outputs": [ - "dist/measures/movies" - ], - "options": { - "commands": [ - "npx cpx \"dist/projects/movies/browser/stats.json\" dist/measures/movies", - "npx webpack-bundle-analyzer dist/projects/movies/browser/stats.json -m static -r dist/measures/movies/bundle-size-report.prod.html" - ], - "parallel": false - } - }, - "update-readme": { - "executor": "nx:run-commands", - "dependsOn": ["build-report"], - "outputs": ["README.md"], - "options": { - "commands": [ - "npx ts-node -P tooling/tsconfig.json ./tooling/bundle-stats/index.ts update-bundle-stats --stats=dist/measures/movies/stats.json --target=./README.md" - ], - "parallel": false - } - }, "build-server-cf": { "executor": "@angular-devkit/build-angular:server", "options": { diff --git a/tooling/generate-routes/generate-routes.ts b/tooling/generate-routes/generate-routes.ts deleted file mode 100644 index b4a8d47da..000000000 --- a/tooling/generate-routes/generate-routes.ts +++ /dev/null @@ -1,86 +0,0 @@ -import {existsSync, mkdirSync, readFileSync, WriteFileOptions, writeFileSync} from 'fs'; -import {dirname} from 'path'; -import {EOL} from 'os'; -import axios from 'axios'; -import {TMDBMovieModel} from '../../projects/movies/src/app/data-access/api/model/movie.model'; -import {TMDBPaginateResult} from '../../projects/movies/src/app/data-access/api/paginate/paginate.interface'; -import {GenresResponse} from '../../projects/movies/src/app/data-access/api/resources/genre.resource'; -import {environment} from '../../projects/movies/src/environments/environment'; - -// PARAMS -const mutation = !getArgv('no-mutation'); - -const targetFile = getArgv('target-file'); -if (!targetFile) { - throw new Error('CLI param --targetFile is required'); -} - -let defaultRoutes: string[] = []; - -const sourceFile = getArgv('source-file'); -if (existsSync(sourceFile)) { - console.log('Read source rout.txt ', sourceFile); - defaultRoutes = readFileSync(sourceFile).toString().split(EOL).filter(v => !!v); - console.log('Default routes: ', defaultRoutes); -} - -// URLs -const readApi = (url: string) => `${environment.tmdbBaseUrl}/${environment.apiV3}/${url}`; -const movieGenresURL = readApi('genre/movie/list'); -const genresListURL = (id: string | number) => readApi(`list/genre/${id}`); -const movieDetailURL = (id: string | number) => readApi(`detail/movie/${id}`); -const moviesPopularURL = readApi('movie/popular'); - -const movieGenresRoutes = axios - .get<{ genres: GenresResponse }>(movieGenresURL, { - headers: getTmdbHeaders() - }) - .then(({data}) => data.genres.map(({id}) => genresListURL(id))); - -const moviesPopularRoutes = (options: { - pages: number; // how many page details of popular movies should be pre-rendered -}) => - [...Array(options.pages).keys()].map((_, i) => - axios - .get>(moviesPopularURL, { - headers: getTmdbHeaders(), - params: { - sort_by: 'popularity.asc', - page: i + 1, - }, - }) - .then(({data}) => data.results.map(({id}) => movieDetailURL(id))) - ); - - -// GENERATE -Promise.all([ - Promise.resolve(defaultRoutes), - movieGenresRoutes, // list the routes of the genres featured in the app sidebar - // list routes for movie details equivalent to N pages of popular movies list - ...moviesPopularRoutes({pages: 2}), -]) - .then((routes) => { - console.log('write to target ' + (mutation ? 'with' : 'without') + ' mutations', targetFile); - writeFileSyncRecursive(targetFile, mutation ? defaultRoutes.flat().join(EOL) : routes.flat().join(EOL)); - }) - .catch((e) => console.error(e)); - - -/// HELPER -function getArgv(propName: string): string { - return process.argv.find((i: string) => i.includes(`--${propName}`))?.split(/[= ]/).pop() || ''; -} - -function writeFileSyncRecursive(filename: string, content: string, options: WriteFileOptions = {encoding: 'utf8'}) { - mkdirSync(dirname(filename), {recursive: true}) - writeFileSync(filename, content, options) -} - -function getTmdbHeaders() { - return { - // Is this needed to get accepted by TMDB server ??? - "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36", - authorization: `Bearer ${environment.tmdbApiReadAccessKey}` - } -} diff --git a/tsconfig.json b/tsconfig.json index a4473617f..661a6bb36 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -31,8 +31,8 @@ "angular-movies": [ "projects/movies/src/index.ts" ], - "movies-user-flows": [ - "movies-user-flows/src/index.ts" + "movies-ufo": [ + "projects/movies-user-flows/src/index.ts" ] } },