├── .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 |
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 |
--------------------------------------------------------------------------------