├── .browserslistrc ├── .gitignore ├── .vscode ├── extensions.json ├── launch.json └── tasks.json ├── LICENSE.md ├── README.md ├── angular.json ├── netlify.toml ├── package.json ├── src ├── app │ ├── about.component.ts │ ├── app.component.ts │ ├── child.component.ts │ ├── home.component.ts │ ├── parent.component.ts │ ├── router │ │ ├── index.ts │ │ ├── outlet.directive.ts │ │ └── router.service.ts │ └── routes.ts ├── assets │ └── .gitkeep ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon.ico ├── index.html ├── main.ts ├── polyfills.ts └── styles.css ├── tsconfig.app.json ├── tsconfig.json └── yarn.lock /.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # For the full list of supported browsers by the Angular framework, please see: 6 | # https://angular.io/guide/browser-support 7 | 8 | # You can see what browsers were selected by your queries by running: 9 | # npx browserslist 10 | 11 | last 1 Chrome version 12 | last 1 Firefox version 13 | last 2 Edge major versions 14 | last 2 Safari major versions 15 | last 2 iOS major versions 16 | Firefox ESR 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # Compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | /bazel-out 8 | 9 | # Node 10 | /node_modules 11 | npm-debug.log 12 | yarn-error.log 13 | 14 | # IDEs and editors 15 | .idea/ 16 | .project 17 | .classpath 18 | .c9/ 19 | *.launch 20 | .settings/ 21 | *.sublime-workspace 22 | 23 | # Visual Studio Code 24 | .vscode/* 25 | !.vscode/settings.json 26 | !.vscode/tasks.json 27 | !.vscode/launch.json 28 | !.vscode/extensions.json 29 | .history/* 30 | 31 | # Miscellaneous 32 | /.angular/cache 33 | .sass-cache/ 34 | /connect.lock 35 | /coverage 36 | /libpeerconnection.log 37 | testem.log 38 | /typings 39 | 40 | # System files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846 3 | "recommendations": ["angular.ng-template"] 4 | } 5 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 3 | "version": "0.2.0", 4 | "configurations": [ 5 | { 6 | "name": "ng serve", 7 | "type": "pwa-chrome", 8 | "request": "launch", 9 | "preLaunchTask": "npm: start", 10 | "url": "http://localhost:4200/" 11 | }, 12 | { 13 | "name": "ng test", 14 | "type": "chrome", 15 | "request": "launch", 16 | "preLaunchTask": "npm: test", 17 | "url": "http://localhost:9876/debug.html" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558 3 | "version": "2.0.0", 4 | "tasks": [ 5 | { 6 | "type": "npm", 7 | "script": "start", 8 | "isBackground": true, 9 | "problemMatcher": { 10 | "owner": "typescript", 11 | "pattern": "$tsc", 12 | "background": { 13 | "activeOnStart": true, 14 | "beginsPattern": { 15 | "regexp": "(.*?)" 16 | }, 17 | "endsPattern": { 18 | "regexp": "bundle generation complete" 19 | } 20 | } 21 | } 22 | }, 23 | { 24 | "type": "npm", 25 | "script": "test", 26 | "isBackground": true, 27 | "problemMatcher": { 28 | "owner": "typescript", 29 | "pattern": "$tsc", 30 | "background": { 31 | "activeOnStart": true, 32 | "beginsPattern": { 33 | "regexp": "(.*?)" 34 | }, 35 | "endsPattern": { 36 | "regexp": "bundle generation complete" 37 | } 38 | } 39 | } 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2022 Brandon Roberts 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Remix Router + Angular 2 | 3 | This is a working example of routing with @remix-run/router in Angular. It uses Angular's new standalone features for components, pipes, and directives. It also uses the new `inject()` function for using DI without explicit an explicit constructor. 4 | 5 | ## Setup 6 | 7 | Install dependencies 8 | 9 | ```sh 10 | yarn 11 | ``` 12 | 13 | ## Serve application 14 | 15 | Run the `dev` command to serve the application 16 | 17 | ```sh 18 | yarn dev 19 | ``` 20 | 21 | Navigate to http://localhost:4200 in your browser 22 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "cli": { 5 | "packageManager": "yarn" 6 | }, 7 | "newProjectRoot": "projects", 8 | "projects": { 9 | "remix-router-ng": { 10 | "projectType": "application", 11 | "schematics": { 12 | "@schematics/angular:component": { 13 | "inlineTemplate": true, 14 | "inlineStyle": true, 15 | "skipTests": true 16 | }, 17 | "@schematics/angular:class": { 18 | "skipTests": true 19 | }, 20 | "@schematics/angular:directive": { 21 | "skipTests": true 22 | }, 23 | "@schematics/angular:guard": { 24 | "skipTests": true 25 | }, 26 | "@schematics/angular:interceptor": { 27 | "skipTests": true 28 | }, 29 | "@schematics/angular:pipe": { 30 | "skipTests": true 31 | }, 32 | "@schematics/angular:resolver": { 33 | "skipTests": true 34 | }, 35 | "@schematics/angular:service": { 36 | "skipTests": true 37 | }, 38 | "@schematics/angular:application": { 39 | "strict": true 40 | } 41 | }, 42 | "root": "", 43 | "sourceRoot": "src", 44 | "prefix": "app", 45 | "architect": { 46 | "build": { 47 | "builder": "@angular-devkit/build-angular:browser", 48 | "options": { 49 | "outputPath": "dist/remix-router-ng", 50 | "index": "src/index.html", 51 | "main": "src/main.ts", 52 | "polyfills": "src/polyfills.ts", 53 | "tsConfig": "tsconfig.app.json", 54 | "assets": [ 55 | "src/favicon.ico", 56 | "src/assets" 57 | ], 58 | "styles": [ 59 | "src/styles.css" 60 | ], 61 | "scripts": [] 62 | }, 63 | "configurations": { 64 | "production": { 65 | "budgets": [ 66 | { 67 | "type": "initial", 68 | "maximumWarning": "500kb", 69 | "maximumError": "1mb" 70 | }, 71 | { 72 | "type": "anyComponentStyle", 73 | "maximumWarning": "2kb", 74 | "maximumError": "4kb" 75 | } 76 | ], 77 | "fileReplacements": [ 78 | { 79 | "replace": "src/environments/environment.ts", 80 | "with": "src/environments/environment.prod.ts" 81 | } 82 | ], 83 | "outputHashing": "all" 84 | }, 85 | "development": { 86 | "buildOptimizer": false, 87 | "optimization": false, 88 | "vendorChunk": true, 89 | "extractLicenses": false, 90 | "sourceMap": true, 91 | "namedChunks": true 92 | } 93 | }, 94 | "defaultConfiguration": "production" 95 | }, 96 | "serve": { 97 | "builder": "@angular-devkit/build-angular:dev-server", 98 | "configurations": { 99 | "production": { 100 | "browserTarget": "remix-router-ng:build:production" 101 | }, 102 | "development": { 103 | "browserTarget": "remix-router-ng:build:development" 104 | } 105 | }, 106 | "defaultConfiguration": "development" 107 | }, 108 | "extract-i18n": { 109 | "builder": "@angular-devkit/build-angular:extract-i18n", 110 | "options": { 111 | "browserTarget": "remix-router-ng:build" 112 | } 113 | } 114 | } 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [[redirects]] 2 | from = "/*" 3 | to = "/index.html" 4 | status = 200 -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "remix-router-ng", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "ng": "ng", 7 | "dev": "ng serve", 8 | "start": "ng serve", 9 | "build": "ng build", 10 | "watch": "ng build --watch --configuration development" 11 | }, 12 | "private": true, 13 | "dependencies": { 14 | "@angular/animations": "^14.0.0", 15 | "@angular/common": "^14.0.0", 16 | "@angular/compiler": "^14.0.0", 17 | "@angular/core": "^14.0.0", 18 | "@angular/forms": "^14.0.0", 19 | "@angular/platform-browser": "^14.0.0", 20 | "@angular/platform-browser-dynamic": "^14.0.0", 21 | "@angular/router": "^14.0.0", 22 | "@remix-run/router": "^1.0.1", 23 | "rxjs": "~7.5.0", 24 | "tslib": "^2.3.0", 25 | "zone.js": "~0.11.4" 26 | }, 27 | "devDependencies": { 28 | "@angular-devkit/build-angular": "^14.0.0", 29 | "@angular/cli": "~14.0.0", 30 | "@angular/compiler-cli": "^14.0.0", 31 | "typescript": "~4.7.2" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/app/about.component.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { Component } from '@angular/core'; 3 | 4 | import { 5 | ActionFunction, 6 | LoaderFunction, 7 | json, 8 | redirect, 9 | getActionData, 10 | getLoaderData, 11 | getRouter, 12 | } from 'remix-router-angular'; 13 | 14 | export const action: ActionFunction = async ({ request }) => { 15 | const formData = await request.formData(); 16 | const name = formData.get('name'); 17 | 18 | if (!name) { 19 | return { 20 | name: 'Name is required', 21 | }; 22 | } 23 | 24 | return redirect(`/?name=${name}`); 25 | }; 26 | 27 | export const loader: LoaderFunction = async () => { 28 | const res = await fetch('https://jsonplaceholder.typicode.com/todos/1'); 29 | const todos = await res.json(); 30 | 31 | return json({ todos }); 32 | }; 33 | 34 | @Component({ 35 | selector: 'about', 36 | standalone: true, 37 | imports: [CommonModule], 38 | template: ` 39 | Remixing Routing in Angular 40 | 41 |
42 | Action Data: {{ actionData$ | async | json }} 43 | 44 |
45 | Loader Data: {{ loaderData$ | async | json }} 46 | 47 |
48 | 49 | 1. Submit the form without entering a name to see the action data containing the validation message.
50 | 2. Enter a name and submit to be redirected back to home with the name in the query params. 51 | 52 |
53 |
Name:
54 | 55 | 56 |
57 | `, 58 | }) 59 | export class AboutComponent { 60 | loaderData$ = getLoaderData(); 61 | actionData$ = getActionData(); 62 | router = getRouter(); 63 | 64 | onSubmit($event: any) { 65 | $event.preventDefault(); 66 | 67 | this.router.navigate('/about', { 68 | formMethod: 'post', 69 | formData: new FormData($event.target), 70 | }); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | import { getRouter, Outlet } from 'remix-router-angular'; 4 | 5 | @Component({ 6 | selector: 'app-root', 7 | template: ` 8 | Home | 9 | About | 10 | Nested 11 | 12 |

13 | 14 | 15 | `, 16 | imports: [Outlet], 17 | standalone: true, 18 | styles: [ 19 | ` 20 | a { 21 | text-decoration: underline; 22 | } 23 | `, 24 | ], 25 | }) 26 | export class AppComponent { 27 | router = getRouter(); 28 | 29 | goHome() { 30 | this.router.navigate('/'); 31 | } 32 | 33 | goAbout() { 34 | this.router.navigate('/about'); 35 | } 36 | 37 | goNested() { 38 | this.router.navigate('/parent/child'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/app/child.component.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { Component } from '@angular/core'; 3 | 4 | import { getRouteParams } from 'remix-router-angular'; 5 | 6 | @Component({ 7 | selector: 'child', 8 | standalone: true, 9 | imports: [CommonModule], 10 | template: ` Child {{ (params$ | async)?.child }}`, 11 | }) 12 | export class ChildComponent { 13 | params$ = getRouteParams<{ child: string }>(); 14 | } 15 | -------------------------------------------------------------------------------- /src/app/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'home', 5 | standalone: true, 6 | template: ` 7 | Hello from Remix Router 8 | `, 9 | }) 10 | export class HomeComponent {} 11 | -------------------------------------------------------------------------------- /src/app/parent.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { getRouter, Outlet } from 'remix-router-angular'; 3 | 4 | @Component({ 5 | selector: 'parent', 6 | standalone: true, 7 | imports: [Outlet], 8 | template: ` 9 | Parent - 10 | Child | 11 | Child 1 | 12 | Child 2 13 |
14 | 15 | 16 | `, 17 | styles: [ 18 | ` 19 | a { 20 | text-decoration: underline; 21 | } 22 | `, 23 | ], 24 | }) 25 | export class ParentComponent { 26 | router = getRouter(); 27 | 28 | child(num: string) { 29 | this.router.navigate(`/parent/${num}`); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/app/router/index.ts: -------------------------------------------------------------------------------- 1 | export * from './router.service'; 2 | export * from './outlet.directive'; 3 | export { 4 | json, 5 | redirect, 6 | LoaderFunction, 7 | ActionFunction, 8 | } from '@remix-run/router'; 9 | -------------------------------------------------------------------------------- /src/app/router/outlet.directive.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Directive, 3 | inject, 4 | Injector, 5 | Type, 6 | ViewContainerRef, 7 | } from '@angular/core'; 8 | import { RouterState } from '@remix-run/router'; 9 | import { Subject, takeUntil, tap } from 'rxjs'; 10 | 11 | import { 12 | DataRouteMatch, 13 | getRouteContext, 14 | getRouter, 15 | ROUTE_CONTEXT, 16 | } from './router.service'; 17 | 18 | @Directive({ 19 | selector: 'outlet', 20 | standalone: true, 21 | }) 22 | export class Outlet { 23 | private destroy$ = new Subject(); 24 | private cmp!: Type; 25 | private context? = getRouteContext(); 26 | private router = getRouter(); 27 | private vcr = inject(ViewContainerRef); 28 | 29 | ngOnInit() { 30 | this.setUpListener(); 31 | } 32 | 33 | setUpListener() { 34 | this.router.routerState$ 35 | .pipe( 36 | tap((rs) => { 37 | const matchesToRender = this.getMatch(rs); 38 | const currentCmp = matchesToRender.route.element; 39 | 40 | if (this.cmp !== currentCmp) { 41 | this.vcr.clear(); 42 | this.vcr.createComponent(currentCmp, { 43 | injector: this.getInjector(matchesToRender), 44 | }); 45 | this.cmp = currentCmp; 46 | } 47 | }), 48 | takeUntil(this.destroy$) 49 | ) 50 | .subscribe(); 51 | } 52 | 53 | getInjector(matchesToRender: DataRouteMatch) { 54 | const injector = Injector.create({ 55 | providers: [ 56 | { 57 | provide: ROUTE_CONTEXT, 58 | useValue: { 59 | id: matchesToRender.route.id, 60 | index: matchesToRender.route.index === true, 61 | params: matchesToRender.params, 62 | }, 63 | }, 64 | ], 65 | parent: this.vcr.injector, 66 | }); 67 | 68 | return injector; 69 | } 70 | 71 | getMatch(routerState: RouterState): DataRouteMatch { 72 | const { matches } = routerState; 73 | const idx = matches.findIndex( 74 | (match) => match.route.id === this.context?.id 75 | ); 76 | const matchesToRender = matches[idx + 1]; 77 | 78 | return matchesToRender as DataRouteMatch; 79 | } 80 | 81 | ngOnDestroy() { 82 | this.destroy$.next(true); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/app/router/router.service.ts: -------------------------------------------------------------------------------- 1 | import { 2 | inject, 3 | Injectable, 4 | InjectFlags, 5 | InjectionToken, 6 | Type, 7 | } from '@angular/core'; 8 | import { 9 | Params, 10 | AgnosticRouteObject as RemixRouteObject, 11 | AgnosticDataRouteMatch as RemixDataRouteMatch, 12 | RouterState, 13 | Router as RemixRouter, 14 | createBrowserHistory, 15 | createRouter, 16 | RouterNavigateOptions, 17 | } from '@remix-run/router'; 18 | import { BehaviorSubject, filter, map } from 'rxjs'; 19 | 20 | export type RouteObject = RemixRouteObject & { 21 | element: Type; 22 | children?: RouteObject[]; 23 | }; 24 | 25 | export type DataRouteMatch = RemixDataRouteMatch & { 26 | route: { element: Type }; 27 | }; 28 | 29 | export const ROUTES = new InjectionToken('ROUTES'); 30 | 31 | export const REMIX_ROUTER = new InjectionToken('Remix Router', { 32 | providedIn: 'root', 33 | factory() { 34 | const routes = inject(ROUTES); 35 | const history = createBrowserHistory(); 36 | const router = createRouter({ 37 | routes, 38 | history, 39 | }); 40 | router.initialize(); 41 | return router; 42 | }, 43 | }); 44 | 45 | export const ROUTE_CONTEXT = new InjectionToken<{ 46 | id: string; 47 | index: boolean; 48 | params: Params; 49 | }>('Route Context'); 50 | 51 | export function getRouter() { 52 | return inject(Router); 53 | } 54 | 55 | export function getRouteContext() { 56 | return inject(ROUTE_CONTEXT, InjectFlags.Optional | InjectFlags.SkipSelf); 57 | } 58 | 59 | export function getActionData() { 60 | const router = inject(Router); 61 | const context = getRouteContext(); 62 | 63 | return router.routerState$.pipe( 64 | filter((rs) => !!rs.actionData), 65 | map((rs) => rs.actionData![context!.id]) 66 | ); 67 | } 68 | 69 | export function getLoaderData() { 70 | const router = inject(Router); 71 | const context = getRouteContext(); 72 | 73 | return router.routerState$.pipe(map((rs) => rs.loaderData[context!.id])); 74 | } 75 | 76 | export function getRouteParams() { 77 | const router = inject(Router); 78 | const context = getRouteContext(); 79 | 80 | return router.routerState$.pipe( 81 | map((rs) => { 82 | const route = rs.matches.find((match) => { 83 | console.log(match.route, context); 84 | return match.route.id === context!.id; 85 | }); 86 | 87 | return ((route && route.params) || {}) as T; 88 | }) 89 | ); 90 | } 91 | 92 | @Injectable({ 93 | providedIn: 'root', 94 | }) 95 | export class Router { 96 | private _remixRouter = inject(REMIX_ROUTER); 97 | routerState$ = new BehaviorSubject(this._remixRouter.state); 98 | 99 | constructor() { 100 | this._remixRouter.subscribe((rs) => this.routerState$.next(rs)); 101 | } 102 | 103 | get state() { 104 | return this._remixRouter.state; 105 | } 106 | 107 | navigate(path: string, opts?: RouterNavigateOptions) { 108 | this._remixRouter.navigate(path, opts); 109 | } 110 | } 111 | 112 | export function provideRoutes(routes: RouteObject[]) { 113 | return [{ provide: ROUTES, useValue: routes }]; 114 | } 115 | -------------------------------------------------------------------------------- /src/app/routes.ts: -------------------------------------------------------------------------------- 1 | import { RouteObject } from 'remix-router-angular'; 2 | 3 | import { 4 | AboutComponent, 5 | loader as aboutLoader, 6 | action as aboutAction, 7 | } from './about.component'; 8 | import { HomeComponent } from './home.component'; 9 | import { ParentComponent } from './parent.component'; 10 | import { ChildComponent } from './child.component'; 11 | 12 | export const routes: RouteObject[] = [ 13 | { path: '/', element: HomeComponent }, 14 | { 15 | path: '/parent', 16 | element: ParentComponent, 17 | children: [ 18 | { 19 | path: ':child', 20 | element: ChildComponent, 21 | }, 22 | ], 23 | }, 24 | { 25 | path: '/about', 26 | element: AboutComponent, 27 | action: aboutAction, 28 | loader: aboutLoader, 29 | }, 30 | ]; 31 | -------------------------------------------------------------------------------- /src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brandonroberts/remix-router-angular/27a454303b7e570271a3529b954c7881f1b68afc/src/assets/.gitkeep -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brandonroberts/remix-router-angular/27a454303b7e570271a3529b954c7881f1b68afc/src/favicon.ico -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | RemixRouterNg 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { bootstrapApplication } from '@angular/platform-browser'; 3 | import { provideRoutes } from 'remix-router-angular'; 4 | 5 | import { AppComponent } from './app/app.component'; 6 | import { routes } from './app/routes'; 7 | import { environment } from './environments/environment'; 8 | 9 | if (environment.production) { 10 | enableProdMode(); 11 | } 12 | 13 | bootstrapApplication(AppComponent, { 14 | providers: [provideRoutes(routes)], 15 | }); 16 | -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes recent versions of Safari, Chrome (including 12 | * Opera), Edge on the desktop, and iOS and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** 22 | * By default, zone.js will patch all possible macroTask and DomEvents 23 | * user can disable parts of macroTask/DomEvents patch by setting following flags 24 | * because those flags need to be set before `zone.js` being loaded, and webpack 25 | * will put import in the top of bundle, so user need to create a separate file 26 | * in this directory (for example: zone-flags.ts), and put the following flags 27 | * into that file, and then add the following code before importing zone.js. 28 | * import './zone-flags'; 29 | * 30 | * The flags allowed in zone-flags.ts are listed here. 31 | * 32 | * The following flags will work for all browsers. 33 | * 34 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 35 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 36 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 37 | * 38 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 39 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 40 | * 41 | * (window as any).__Zone_enable_cross_context_check = true; 42 | * 43 | */ 44 | 45 | /*************************************************************************************************** 46 | * Zone JS is required by default for Angular itself. 47 | */ 48 | import 'zone.js'; // Included with Angular CLI. 49 | 50 | 51 | /*************************************************************************************************** 52 | * APPLICATION IMPORTS 53 | */ 54 | -------------------------------------------------------------------------------- /src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [] 7 | }, 8 | "files": [ 9 | "src/main.ts", 10 | "src/polyfills.ts" 11 | ], 12 | "include": [ 13 | "src/**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": "./", 6 | "outDir": "./dist/out-tsc", 7 | "forceConsistentCasingInFileNames": true, 8 | "strict": true, 9 | "noImplicitOverride": true, 10 | "noPropertyAccessFromIndexSignature": true, 11 | "noImplicitReturns": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "sourceMap": true, 14 | "declaration": false, 15 | "downlevelIteration": true, 16 | "experimentalDecorators": true, 17 | "moduleResolution": "node", 18 | "importHelpers": true, 19 | "target": "es2020", 20 | "module": "es2020", 21 | "skipLibCheck": true, 22 | "lib": [ 23 | "es2020", 24 | "dom" 25 | ], 26 | "paths": { 27 | "remix-router-angular": [ 28 | "./src/app/router" 29 | ] 30 | } 31 | }, 32 | "angularCompilerOptions": { 33 | "enableI18nLegacyMessageIdFormat": false, 34 | "strictInjectionParameters": true, 35 | "strictInputAccessModifiers": true, 36 | "strictTemplates": true 37 | } 38 | } 39 | --------------------------------------------------------------------------------