├── .editorconfig
├── .gitignore
├── LICENSE
├── README.md
├── angular-cli.json
├── package-lock.json
├── package.json
├── public
├── app.yaml
├── package.json
└── server.ts
├── src
├── app
│ ├── app-routing.module.ts
│ ├── app.component.css
│ ├── app.component.html
│ ├── app.component.ts
│ ├── app.module.ts
│ ├── app.server.module.ts
│ ├── features
│ │ ├── 404
│ │ │ ├── 404.component.css
│ │ │ ├── 404.component.html
│ │ │ └── 404.component.ts
│ │ ├── about
│ │ │ ├── about-routing.module.ts
│ │ │ ├── about.module.ts
│ │ │ ├── about
│ │ │ │ ├── about.component.css
│ │ │ │ ├── about.component.html
│ │ │ │ └── about.component.ts
│ │ │ └── index.ts
│ │ ├── contact
│ │ │ ├── contact-routing.module.ts
│ │ │ ├── contact.module.ts
│ │ │ ├── contact
│ │ │ │ ├── contact.component.css
│ │ │ │ ├── contact.component.html
│ │ │ │ └── contact.component.ts
│ │ │ └── index.ts
│ │ ├── features-routing.module.ts
│ │ ├── features.module.ts
│ │ └── home
│ │ │ ├── home-routing.module.ts
│ │ │ ├── home.module.ts
│ │ │ ├── home
│ │ │ ├── home.component.css
│ │ │ ├── home.component.html
│ │ │ └── home.component.ts
│ │ │ └── index.ts
│ ├── footer
│ │ ├── footer.component.css
│ │ ├── footer.component.html
│ │ └── footer.component.ts
│ ├── header
│ │ ├── header.component.css
│ │ ├── header.component.html
│ │ └── header.component.ts
│ ├── index.ts
│ └── shared
│ │ ├── index.ts
│ │ ├── services
│ │ ├── global-error-handler.service.ts
│ │ └── google-analytics.service.ts
│ │ └── shared.module.ts
├── assets
│ ├── .gitkeep
│ └── manifest.json
├── environments
│ ├── environment.prod.ts
│ └── environment.ts
├── favicon.ico
├── index.html
├── main.server.ts
├── main.ts
├── ngsw-config.json
├── polyfills.ts
├── styles.css
├── tsconfig.app.json
├── tsconfig.server.json
└── typings.d.ts
├── tsconfig.json
├── tslint.json
├── webpack.server.config.js
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | max_line_length = off
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # compiled output
2 | /public/dist
3 | /public/etc
4 | /tmp
5 | /out-tsc
6 |
7 | # dependencies
8 | /node_modules
9 |
10 | # IDEs and editors
11 | /.idea
12 | .project
13 | .classpath
14 | .c9/
15 | *.launch
16 | .settings/
17 | *.sublime-workspace
18 |
19 | # IDE - VSCode
20 | .vscode
21 | .vscode/*
22 | !.vscode/settings.json
23 | !.vscode/tasks.json
24 | !.vscode/launch.json
25 | !.vscode/extensions.json
26 |
27 | # misc
28 | /.sass-cache
29 | /connect.lock
30 | /coverage
31 | /libpeerconnection.log
32 | npm-debug.log
33 | testem.log
34 | /typings
35 |
36 | # e2e
37 | /e2e/*.js
38 | /e2e/*.map
39 |
40 | # System Files
41 | .DS_Store
42 | Thumbs.db
43 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Abhijit Kar
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Angular Scaffolding
2 |
3 | [](https://www.abhijit-kar.com/)
4 | [](https://opensource.org/licenses/mit-license.php)
5 | [](https://david-dm.org/abhijit-kar/angular-scaffolding)
6 | [](https://david-dm.org/abhijit-kar/angular-scaffolding?type=dev)
7 | [](https://www.abhijit-kar.com/angular-scaffolding/)
8 |
9 | - [x] Angular Universal
10 | - [x] Progressive Web App
11 | - [x] Google Analytics
12 | - [x] Global Error Handling
13 | - [x] Github Pages Deployment
14 | - [x] Google Cloud Deployment
15 | - [x] Advanced But Minimal Routing
16 | - [x] 2 SEO Features - Meta & Title services
17 |
18 | Use http://botmap.io/ to generate sitemaps for Angular / React projects.
19 |
--------------------------------------------------------------------------------
/angular-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "project": {
4 | "name": "angular-scaffolding"
5 | },
6 | "apps": [
7 | {
8 | "root": "src",
9 | "outDir": "public/dist/browser",
10 | "assets": ["assets", "favicon.ico"],
11 | "index": "index.html",
12 | "main": "main.ts",
13 | "polyfills": "polyfills.ts",
14 | "test": "test.ts",
15 | "tsconfig": "tsconfig.app.json",
16 | "testTsconfig": "tsconfig.spec.json",
17 | "prefix": "app",
18 | "serviceWorker": true,
19 | "styles": ["styles.css"],
20 | "scripts": [],
21 | "environmentSource": "environments/environment.ts",
22 | "environments": {
23 | "dev": "environments/environment.ts",
24 | "prod": "environments/environment.prod.ts"
25 | }
26 | },
27 | {
28 | "root": "src",
29 | "outDir": "public/dist/server",
30 | "assets": ["assets", "favicon.ico"],
31 | "platform": "server",
32 | "index": "index.html",
33 | "main": "main.server.ts",
34 | "test": "test.ts",
35 | "tsconfig": "tsconfig.server.json",
36 | "testTsconfig": "tsconfig.spec.json",
37 | "prefix": "app",
38 | "serviceWorker": true,
39 | "styles": ["styles.css"],
40 | "scripts": [],
41 | "environmentSource": "environments/environment.ts",
42 | "environments": {
43 | "dev": "environments/environment.ts",
44 | "prod": "environments/environment.prod.ts"
45 | }
46 | }
47 | ],
48 | "e2e": {
49 | "protractor": {
50 | "config": "./protractor.conf.js"
51 | }
52 | },
53 | "lint": [
54 | {
55 | "project": "src/tsconfig.app.json",
56 | "exclude": "**/node_modules/**"
57 | }
58 | ],
59 | "test": {
60 | "karma": {
61 | "config": "./karma.conf.js"
62 | }
63 | },
64 | "defaults": {
65 | "styleExt": "css",
66 | "component": {}
67 | },
68 | "warnings": {
69 | "typescriptMismatch": false
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-scaffolding",
3 | "version": "0.0.1",
4 | "license": "MIT",
5 | "scripts": {
6 | "ng": "Node ./node_modules/@angular/cli/bin/ng",
7 | "lint": "ng lint",
8 | "serve": "ng serve",
9 | "build:client": "ng build --prod --aot",
10 | "build:server": "ng build --prod --aot --app 1 --output-hashing=false",
11 | "build:webpack": "webpack --config webpack.server.config.js -d --progress --colors",
12 | "build:universal": "npm run build:client && npm run build:server && npm run build:webpack",
13 | "serve:universal": "npm start --prefix ./public/",
14 | "deploy:dev": "ng build --prod --aot --base-href https://www.abhijit-kar.com/angular-scaffolding/ && ngh --dir=public/dist/browser/",
15 | "deploy:prod": "npm run build:universal && ngh --dir=public/ --branch=prod"
16 | },
17 | "private": true,
18 | "dependencies": {
19 | "@angular/animations": "^5.2.10",
20 | "@angular/common": "^5.2.10",
21 | "@angular/compiler": "^5.2.10",
22 | "@angular/core": "^5.2.10",
23 | "@angular/forms": "^5.2.10",
24 | "@angular/http": "^5.2.10",
25 | "@angular/platform-browser": "^5.2.10",
26 | "@angular/platform-browser-dynamic": "^5.2.10",
27 | "@angular/platform-server": "^5.2.10",
28 | "@angular/router": "^5.2.10",
29 | "@angular/service-worker": "^5.2.10",
30 | "@nguniversal/express-engine": "^5.0.0-beta.6",
31 | "@nguniversal/module-map-ngfactory-loader": "^5.0.0-beta.6",
32 | "compression": "^1.7.2",
33 | "core-js": "^2.5.3",
34 | "global": "^4.3.2",
35 | "reflect-metadata": "^0.1.12",
36 | "rxjs": "^5.5.6",
37 | "ts-loader": "^4.0.0",
38 | "webpack": "^4.8.3",
39 | "zone.js": "^0.8.20"
40 | },
41 | "devDependencies": {
42 | "@angular/cli": "1.7.2",
43 | "@angular/compiler-cli": "^5.2.10",
44 | "@angular/language-service": "^5.2.10",
45 | "@types/node": "~9.4.6",
46 | "codelyzer": "~4.1.0",
47 | "ts-node": "~5.0.0",
48 | "tslint": "~5.9.1",
49 | "typescript": "~2.8.3",
50 | "webpack-cli": "^2.1.3"
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/public/app.yaml:
--------------------------------------------------------------------------------
1 | # [START app_yaml]
2 | runtime: nodejs
3 | env: flex
4 |
5 | # This sample incurs costs to run on the App Engine flexible environment.
6 | # The settings below are to reduce costs during testing and are not appropriate
7 | # for production use
8 | manual_scaling:
9 | instances: 1
10 | resources:
11 | cpu: 1
12 | memory_gb: 0.5
13 | disk_size_gb: 10
14 |
15 | # [END app_yaml]
--------------------------------------------------------------------------------
/public/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-scaffolding",
3 | "version": "0.0.0",
4 | "license": "MIT",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/abhijit-kar/angular-scaffolding"
8 | },
9 | "contributors": ["Abhijit Kar"],
10 | "scripts": {
11 | "deploy:gcloud": "gcloud app deploy -v prod",
12 | "start": "node ./dist/server.js"
13 | },
14 | "engines": {
15 | "node": "6.11.4",
16 | "npm": "3.10.10"
17 | },
18 | "dependencies": {
19 | "@angular/animations": "^5.2.10",
20 | "@angular/common": "^5.2.10",
21 | "@angular/compiler": "^5.2.10",
22 | "@angular/core": "^5.2.10",
23 | "@angular/forms": "^5.2.10",
24 | "@angular/http": "^5.2.10",
25 | "@angular/platform-browser": "^5.2.10",
26 | "@angular/platform-browser-dynamic": "^5.2.10",
27 | "@angular/platform-server": "^5.2.10",
28 | "@angular/router": "^5.2.10",
29 | "@angular/service-worker": "^5.2.10",
30 | "@nguniversal/express-engine": "^5.0.0-beta.5",
31 | "@nguniversal/module-map-ngfactory-loader": "^5.0.0-beta.5",
32 | "compression": "^1.7.1",
33 | "core-js": "^2.5.3",
34 | "express": "^4.16.2",
35 | "global": "^4.3.2",
36 | "gsap": "^1.20.3",
37 | "heap": "^0.2.6",
38 | "lodash": "^4.17.4",
39 | "reflect-metadata": "^0.1.10",
40 | "rxjs": "^5.5.6",
41 | "ts-loader": "^4.0.0",
42 | "zone.js": "^0.8.18"
43 | },
44 | "devDependencies": {
45 | "@google-cloud/nodejs-repo-tools": "1.4.17"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/public/server.ts:
--------------------------------------------------------------------------------
1 | import { renderModuleFactory } from "@angular/platform-server";
2 | import { enableProdMode } from "@angular/core";
3 | import { ngExpressEngine } from "@nguniversal/express-engine";
4 | import { provideModuleMap } from "@nguniversal/module-map-ngfactory-loader";
5 | import "zone.js/dist/zone-node";
6 | import "reflect-metadata";
7 |
8 | import * as express from "express";
9 | import { join } from "path";
10 | import { readFileSync } from "fs";
11 | const compression = require("compression");
12 |
13 | enableProdMode();
14 |
15 | const app = express();
16 | const PORT = process.env.PORT || 8080;
17 | const DIST_FOLDER = join(process.cwd(), "dist");
18 | const {
19 | AppServerModuleNgFactory,
20 | LAZY_MODULE_MAP
21 | } = require("./dist/server/main.bundle");
22 |
23 | app.use(compression());
24 | app.engine(
25 | "html",
26 | ngExpressEngine({
27 | bootstrap: AppServerModuleNgFactory,
28 | providers: [provideModuleMap(LAZY_MODULE_MAP)]
29 | })
30 | );
31 |
32 | app.set("view engine", "html");
33 | app.set("views", join(DIST_FOLDER, "browser"));
34 |
35 | app.use(
36 | express.static(join(DIST_FOLDER, "browser"), {
37 | index: false,
38 | maxAge: "1y"
39 | })
40 | );
41 |
42 | app.get("*", (req, res) => {
43 | res.render(join(DIST_FOLDER, "browser", "index.html"), { req });
44 | });
45 |
46 | app.listen(PORT, () => {
47 | console.log(`Node Express server listening on http://localhost:${PORT}`);
48 | });
49 |
--------------------------------------------------------------------------------
/src/app/app-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from "@angular/core";
2 | import { Routes, RouterModule } from "@angular/router";
3 |
4 | import { PageNotFoundComponent } from "./features/404/404.component";
5 |
6 | const routes: Routes = [
7 | { path: "", redirectTo: "home", pathMatch: "full" },
8 | { path: "**", component: PageNotFoundComponent, pathMatch: "full" }
9 | ];
10 |
11 | @NgModule({
12 | imports: [RouterModule.forRoot(routes)],
13 | exports: [RouterModule]
14 | })
15 | export class AppRoutingModule {}
16 |
--------------------------------------------------------------------------------
/src/app/app.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derpycoder/angular-scaffolding/3e5638e8d7306cb0d574c8dd67015c765f389566/src/app/app.component.css
--------------------------------------------------------------------------------
/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from "@angular/core";
2 | import { Title, Meta } from "@angular/platform-browser";
3 | import { Router, NavigationEnd } from "@angular/router";
4 |
5 | import { GoogleAnalyticsService } from "./shared/";
6 |
7 | @Component({
8 | selector: "app-root",
9 | templateUrl: "./app.component.html",
10 | styleUrls: ["./app.component.css"]
11 | })
12 | export class AppComponent {
13 | routes = {
14 | "/": {
15 | title: "Home Page",
16 | desc: "This is the description of Home Page"
17 | },
18 | "/home": {
19 | title: "Home Page",
20 | desc: "This is the description of Home Page"
21 | },
22 | "/about": {
23 | title: "About Us",
24 | desc: "This page will describe some things about us"
25 | },
26 | "/contact": {
27 | title: "Contact Us",
28 | desc: "This page will tell you how to contact us"
29 | }
30 | };
31 |
32 | constructor(
33 | public router: Router,
34 | private googleAnalyticsService: GoogleAnalyticsService,
35 | private titleService: Title,
36 | private meta: Meta
37 | ) {
38 | this.router.events.subscribe(event => {
39 | if (event instanceof NavigationEnd) {
40 | this.handleSEO(event);
41 |
42 | this.googleAnalyticsService.emitPageEvent(event);
43 | }
44 | });
45 | }
46 |
47 | handleSEO(event: NavigationEnd) {
48 | const desc = this.routes[event.url].desc;
49 |
50 | // Generic
51 | this.titleService.setTitle(this.routes[event.url].title);
52 | this.meta.addTag({ name: "description", content: desc });
53 |
54 | // Twitter Metadata
55 | this.meta.addTag({ name: "twitter:card", content: "summary_large_image" });
56 | this.meta.addTag({ name: "twitter:site", content: "@AbhijitKarDikha" });
57 | this.meta.addTag({ name: "twitter:creator", content: "@AbhijitKarDikha" });
58 | this.meta.addTag({ name: "twitter:title", content: desc });
59 | this.meta.addTag({ name: "twitter:description", content: desc });
60 | this.meta.addTag({ name: "twitter:text:description", content: desc });
61 | this.meta.addTag({ name: "twitter:image", content: "https://www.abhijit-kar.com/assets/meta/screenshot.png" });
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { BrowserModule } from "@angular/platform-browser";
2 | import { NgModule } from "@angular/core";
3 | import { ServiceWorkerModule } from "@angular/service-worker";
4 |
5 | import { environment } from "../environments/environment";
6 |
7 | import { AppRoutingModule } from "./app-routing.module";
8 | import { SharedModule } from "./shared/shared.module";
9 |
10 | import { FeaturesModule } from "./features/features.module";
11 | import { AppComponent, HeaderComponent, FooterComponent } from "./";
12 |
13 | @NgModule({
14 | declarations: [AppComponent, HeaderComponent, FooterComponent],
15 | imports: [
16 | BrowserModule.withServerTransition({ appId: "angular-scaffolding" }),
17 | ServiceWorkerModule.register("/ngsw-worker.js", {
18 | enabled: environment.production
19 | }),
20 | FeaturesModule,
21 | AppRoutingModule,
22 | SharedModule
23 | ],
24 | providers: [],
25 | bootstrap: [AppComponent]
26 | })
27 | export class AppModule {}
28 |
--------------------------------------------------------------------------------
/src/app/app.server.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from "@angular/core";
2 | import { ServerModule } from "@angular/platform-server";
3 | import { ModuleMapLoaderModule } from "@nguniversal/module-map-ngfactory-loader";
4 |
5 | import { AppModule } from "./app.module";
6 | import { AppComponent } from "./app.component";
7 |
8 | @NgModule({
9 | imports: [AppModule, ServerModule, ModuleMapLoaderModule],
10 | providers: [
11 | // Add universal-only providers here
12 | ],
13 | bootstrap: [AppComponent]
14 | })
15 | export class AppServerModule {}
16 |
--------------------------------------------------------------------------------
/src/app/features/404/404.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derpycoder/angular-scaffolding/3e5638e8d7306cb0d574c8dd67015c765f389566/src/app/features/404/404.component.css
--------------------------------------------------------------------------------
/src/app/features/404/404.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
404
4 |
A seed project that eases deployment to GitHub Pages, App Engine with Progressive Web Apps, Google Analytics, Angular
5 | Universal
6 |
7 |
8 | Source Code
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/app/features/404/404.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from "@angular/core";
2 |
3 | @Component({
4 | selector: "app-404",
5 | templateUrl: "404.component.html",
6 | styleUrls: ["404.component.css"]
7 | })
8 | export class PageNotFoundComponent {}
9 |
--------------------------------------------------------------------------------
/src/app/features/about/about-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from "@angular/core";
2 | import { Routes, RouterModule } from "@angular/router";
3 |
4 | import { AboutComponent } from "./";
5 |
6 | const routes: Routes = [
7 | { path: "", component: AboutComponent, pathMatch: "full" }
8 | ];
9 |
10 | @NgModule({
11 | imports: [RouterModule.forChild(routes)],
12 | exports: [RouterModule]
13 | })
14 | export class AboutRoutingModule {}
15 |
16 | export const AboutComponents = [AboutComponent];
17 |
--------------------------------------------------------------------------------
/src/app/features/about/about.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from "@angular/core";
2 | import { CommonModule } from "@angular/common";
3 |
4 | import {
5 | AboutRoutingModule,
6 | AboutComponents
7 | } from "./about-routing.module";
8 |
9 | @NgModule({
10 | imports: [CommonModule, AboutRoutingModule],
11 | declarations: AboutComponents
12 | })
13 | export class AboutModule {}
14 |
--------------------------------------------------------------------------------
/src/app/features/about/about/about.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derpycoder/angular-scaffolding/3e5638e8d7306cb0d574c8dd67015c765f389566/src/app/features/about/about/about.component.css
--------------------------------------------------------------------------------
/src/app/features/about/about/about.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
About
4 |
A seed project that eases deployment to GitHub Pages, App Engine with Google Analytics
5 |
6 | Source Code
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/app/features/about/about/about.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from "@angular/core";
2 |
3 | @Component({
4 | selector: "app-about",
5 | templateUrl: "about.component.html",
6 | styleUrls: ["about.component.css"]
7 | })
8 | export class AboutComponent {}
9 |
--------------------------------------------------------------------------------
/src/app/features/about/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./about/about.component";
2 |
--------------------------------------------------------------------------------
/src/app/features/contact/contact-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from "@angular/core";
2 | import { Routes, RouterModule } from "@angular/router";
3 |
4 | import { ContactComponent } from "./";
5 |
6 | const routes: Routes = [
7 | { path: "", component: ContactComponent, pathMatch: "full" }
8 | ];
9 |
10 | @NgModule({
11 | imports: [RouterModule.forChild(routes)],
12 | exports: [RouterModule]
13 | })
14 | export class ContactRoutingModule {}
15 |
16 | export const ContactComponents = [ContactComponent];
17 |
--------------------------------------------------------------------------------
/src/app/features/contact/contact.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from "@angular/core";
2 | import { CommonModule } from "@angular/common";
3 |
4 | import {
5 | ContactRoutingModule,
6 | ContactComponents
7 | } from "./contact-routing.module";
8 |
9 | @NgModule({
10 | imports: [CommonModule, ContactRoutingModule],
11 | declarations: ContactComponents
12 | })
13 | export class ContactModule {}
14 |
--------------------------------------------------------------------------------
/src/app/features/contact/contact/contact.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derpycoder/angular-scaffolding/3e5638e8d7306cb0d574c8dd67015c765f389566/src/app/features/contact/contact/contact.component.css
--------------------------------------------------------------------------------
/src/app/features/contact/contact/contact.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Contact
4 |
A seed project that eases deployment to GitHub Pages, App Engine with Angular Universal
5 |
6 | Source Code
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/app/features/contact/contact/contact.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from "@angular/core";
2 |
3 | @Component({
4 | selector: "app-contact",
5 | templateUrl: "contact.component.html",
6 | styleUrls: ["contact.component.css"]
7 | })
8 | export class ContactComponent {}
9 |
--------------------------------------------------------------------------------
/src/app/features/contact/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./contact/contact.component";
2 |
--------------------------------------------------------------------------------
/src/app/features/features-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from "@angular/core";
2 | import { Routes, RouterModule } from "@angular/router";
3 |
4 | const routes: Routes = [
5 | { path: "home", loadChildren: "./home/home.module#HomeModule" },
6 | { path: "about", loadChildren: "./about/about.module#AboutModule" },
7 | { path: "contact", loadChildren: "./contact/contact.module#ContactModule" }
8 | ];
9 |
10 | @NgModule({
11 | imports: [RouterModule.forChild(routes)],
12 | declarations: [],
13 | exports: [RouterModule]
14 | })
15 | export class FeaturesRoutingModule {}
16 |
--------------------------------------------------------------------------------
/src/app/features/features.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule, ErrorHandler } from "@angular/core";
2 | import { CommonModule } from "@angular/common";
3 |
4 | import { FeaturesRoutingModule } from "./features-routing.module";
5 |
6 | import { PageNotFoundComponent } from "./404/404.component";
7 |
8 | @NgModule({
9 | imports: [CommonModule, FeaturesRoutingModule],
10 | declarations: [PageNotFoundComponent],
11 | providers: [],
12 | exports: [PageNotFoundComponent]
13 | })
14 | export class FeaturesModule {}
15 |
--------------------------------------------------------------------------------
/src/app/features/home/home-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from "@angular/core";
2 | import { Routes, RouterModule } from "@angular/router";
3 |
4 | import { HomeComponent } from "./";
5 |
6 | const routes: Routes = [
7 | { path: "", component: HomeComponent, pathMatch: "full" }
8 | ];
9 |
10 | @NgModule({
11 | imports: [RouterModule.forChild(routes)],
12 | exports: [RouterModule]
13 | })
14 | export class HomeRoutingModule {}
15 |
16 | export const HomeComponents = [HomeComponent];
17 |
--------------------------------------------------------------------------------
/src/app/features/home/home.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from "@angular/core";
2 | import { CommonModule } from "@angular/common";
3 |
4 | import { HomeRoutingModule, HomeComponents } from "./home-routing.module";
5 |
6 | @NgModule({
7 | imports: [CommonModule, HomeRoutingModule],
8 | declarations: HomeComponents
9 | })
10 | export class HomeModule {}
11 |
--------------------------------------------------------------------------------
/src/app/features/home/home/home.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derpycoder/angular-scaffolding/3e5638e8d7306cb0d574c8dd67015c765f389566/src/app/features/home/home/home.component.css
--------------------------------------------------------------------------------
/src/app/features/home/home/home.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Home
4 |
A seed project that eases deployment to GitHub Pages, App Engine with Progressive Web Apps
5 |
6 | Source Code
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/app/features/home/home/home.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from "@angular/core";
2 |
3 | @Component({
4 | selector: "app-home",
5 | templateUrl: "home.component.html",
6 | styleUrls: ["home.component.css"]
7 | })
8 | export class HomeComponent {}
9 |
--------------------------------------------------------------------------------
/src/app/features/home/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./home/home.component";
2 |
--------------------------------------------------------------------------------
/src/app/footer/footer.component.css:
--------------------------------------------------------------------------------
1 | .footer {
2 | position: absolute;
3 | bottom: 0;
4 | width: 100%;
5 | height: 60px;
6 | line-height: 60px;
7 | background-color: #f5f5f5;
8 | }
9 |
--------------------------------------------------------------------------------
/src/app/footer/footer.component.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/footer/footer.component.ts:
--------------------------------------------------------------------------------
1 | // Library
2 | import { Component } from "@angular/core";
3 |
4 | @Component({
5 | selector: "app-footer",
6 | templateUrl: "footer.component.html",
7 | styleUrls: ["footer.component.css"]
8 | })
9 | export class FooterComponent {}
10 |
--------------------------------------------------------------------------------
/src/app/header/header.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derpycoder/angular-scaffolding/3e5638e8d7306cb0d574c8dd67015c765f389566/src/app/header/header.component.css
--------------------------------------------------------------------------------
/src/app/header/header.component.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/header/header.component.ts:
--------------------------------------------------------------------------------
1 | // Library
2 | import { Component } from "@angular/core";
3 |
4 | @Component({
5 | selector: "app-header",
6 | templateUrl: "header.component.html",
7 | styleUrls: ["header.component.css"]
8 | })
9 | export class HeaderComponent {
10 | isNavBarOpen: boolean;
11 | }
12 |
--------------------------------------------------------------------------------
/src/app/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./header/header.component";
2 | export * from "./footer/footer.component";
3 | export * from "./app.component";
4 |
--------------------------------------------------------------------------------
/src/app/shared/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./services/global-error-handler.service";
2 | export * from "./services/google-analytics.service";
3 |
--------------------------------------------------------------------------------
/src/app/shared/services/global-error-handler.service.ts:
--------------------------------------------------------------------------------
1 | import { ErrorHandler, Injectable, Injector, NgZone } from "@angular/core";
2 | import { GoogleAnalyticsService } from "./google-analytics.service";
3 |
4 | import { environment } from "../../../environments/environment";
5 |
6 | @Injectable()
7 | export class GlobalErrorHandlerService implements ErrorHandler {
8 | constructor(
9 | private injector: Injector,
10 | private googleAnalyticsService: GoogleAnalyticsService,
11 | private ngZone: NgZone
12 | ) {
13 | this.ngZone.onError.subscribe(error => {
14 | this.emitPrintAndLogError(error);
15 | });
16 | }
17 |
18 | handleError(error) {
19 | this.emitPrintAndLogError(error);
20 | }
21 |
22 | emitPrintAndLogError(error) {
23 | if (!environment.production) {
24 | throw error;
25 | } else {
26 | const errMsg = error.message || error.toString();
27 | this.googleAnalyticsService.emitEvent("Error", errMsg);
28 | console.log(errMsg);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/app/shared/services/google-analytics.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable, Inject, PLATFORM_ID } from "@angular/core";
2 | import { isPlatformServer } from "@angular/common";
3 |
4 | declare var ga;
5 |
6 | @Injectable()
7 | export class GoogleAnalyticsService {
8 | private googleAnalyticsKey = "UA-112417282-1";
9 |
10 | constructor(@Inject(PLATFORM_ID) private platformId: Object) {
11 | this.initGoogleAnalytics();
12 | }
13 |
14 | initGoogleAnalytics() {
15 | if (isPlatformServer(this.platformId)) {
16 | return;
17 | }
18 |
19 | try {
20 | window["ga"] =
21 | window["ga"] ||
22 | function() {
23 | (ga.q = ga.q || []).push(arguments);
24 | };
25 | ga.l = +new Date();
26 | ga("create", this.googleAnalyticsKey, "auto");
27 | } catch (e) {
28 | console.log(e);
29 | }
30 | }
31 |
32 | emitPageEvent(event) {
33 | if (isPlatformServer(this.platformId)) {
34 | return;
35 | }
36 |
37 | try {
38 | ga("set", "page", event.urlAfterRedirects);
39 | ga("send", "pageview");
40 | } catch (e) {
41 | console.log(e);
42 | }
43 | }
44 |
45 | emitEvent(
46 | eventCategory: string,
47 | eventAction: string,
48 | callback?: Function,
49 | eventValue?: number,
50 | eventLabel?: string
51 | ) {
52 | if (isPlatformServer(this.platformId)) {
53 | return;
54 | }
55 |
56 | try {
57 | ga("send", "event", {
58 | eventCategory: eventCategory,
59 | eventLabel: eventLabel,
60 | eventValue: eventValue,
61 | eventAction: eventAction,
62 | hitCallback: $ => {
63 | if (callback) {
64 | callback();
65 | }
66 | }
67 | });
68 | } catch (e) {
69 | console.log(e);
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/app/shared/shared.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule, ErrorHandler } from "@angular/core";
2 | import { CommonModule } from "@angular/common";
3 |
4 | import { GlobalErrorHandlerService, GoogleAnalyticsService } from "./";
5 |
6 | @NgModule({
7 | imports: [CommonModule],
8 | declarations: [],
9 | providers: [
10 | {
11 | provide: ErrorHandler,
12 | useClass: GlobalErrorHandlerService
13 | },
14 | GoogleAnalyticsService
15 | ],
16 | exports: []
17 | })
18 | export class SharedModule {}
19 |
--------------------------------------------------------------------------------
/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derpycoder/angular-scaffolding/3e5638e8d7306cb0d574c8dd67015c765f389566/src/assets/.gitkeep
--------------------------------------------------------------------------------
/src/assets/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Angular Scaffolding",
3 | "short_name": "Angular Scaffolding",
4 | "theme_color": "#333333",
5 | "background_color": "#333333",
6 | "display": "fullscreen",
7 | "scope": "/angular-scaffolding",
8 | "start_url": "/angular-scaffolding"
9 | }
10 |
--------------------------------------------------------------------------------
/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true
3 | };
4 |
--------------------------------------------------------------------------------
/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: false
3 | };
4 |
--------------------------------------------------------------------------------
/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derpycoder/angular-scaffolding/3e5638e8d7306cb0d574c8dd67015c765f389566/src/favicon.ico
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Angular Scaffolding
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/src/main.server.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from "@angular/core";
2 |
3 | import { environment } from "./environments/environment";
4 |
5 | if (environment.production) {
6 | enableProdMode();
7 | }
8 |
9 | export { AppServerModule } from "./app/app.server.module";
10 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from "@angular/core";
2 | import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
3 |
4 | import { environment } from "./environments/environment";
5 |
6 | import { AppModule } from "./app/app.module";
7 |
8 | if (environment.production) {
9 | enableProdMode();
10 | }
11 |
12 | document.addEventListener("DOMContentLoaded", () => {
13 | platformBrowserDynamic().bootstrapModule(AppModule);
14 | });
15 |
--------------------------------------------------------------------------------
/src/ngsw-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "index": "/index.html",
3 | "assetGroups": [
4 | {
5 | "name": "app",
6 | "installMode": "prefetch",
7 | "resources": {
8 | "files": ["/favicon.ico", "/index.html"],
9 | "versionedFiles": ["/*.bundle.css", "/*.bundle.js", "/*.chunk.js"]
10 | }
11 | },
12 | {
13 | "name": "assets",
14 | "installMode": "lazy",
15 | "updateMode": "prefetch",
16 | "resources": {
17 | "files": [
18 | "/assets/manifest.json"
19 | ],
20 | "urls": [
21 | "https://fonts.googleapis.com/**",
22 | "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css",
23 | "https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"
24 | ]
25 | }
26 | }
27 | ]
28 | }
29 |
--------------------------------------------------------------------------------
/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | // This file includes polyfills needed by Angular and is loaded before the app.
2 | // You can add your own extra polyfills to this file.
3 | import "core-js/es6/symbol";
4 | import "core-js/es6/object";
5 | import "core-js/es6/function";
6 | import "core-js/es6/parse-int";
7 | import "core-js/es6/parse-float";
8 | import "core-js/es6/number";
9 | import "core-js/es6/math";
10 | import "core-js/es6/string";
11 | import "core-js/es6/date";
12 | import "core-js/es6/array";
13 | import "core-js/es6/regexp";
14 | import "core-js/es6/map";
15 | import "core-js/es6/set";
16 | import "core-js/es6/reflect";
17 |
18 | import "core-js/es7/reflect";
19 | import "zone.js/dist/zone";
20 |
21 | // If you need to support the browsers/features below, uncomment the import
22 | // and run `npm install import-name-here';
23 | // Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
24 |
25 | // Needed for: IE9
26 | // import 'classlist.js';
27 |
28 | // Animations
29 | // Needed for: All but Chrome and Firefox, Not supported in IE9
30 | // import 'web-animations-js';
31 |
32 | // Date, currency, decimal and percent pipes
33 | // Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
34 | // import 'intl';
35 |
36 | // NgClass on SVG elements
37 | // Needed for: IE10, IE11
38 | // import 'classlist.js';
39 |
--------------------------------------------------------------------------------
/src/styles.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --pink: #e83e8c;
3 | }
4 |
5 | .pink {
6 | color: var(--pink);
7 | }
8 |
--------------------------------------------------------------------------------
/src/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/app",
5 | "baseUrl": "./",
6 | "module": "es2015",
7 | "types": []
8 | },
9 | "exclude": [
10 | "test.ts",
11 | "**/*.spec.ts"
12 | ]
13 | }
--------------------------------------------------------------------------------
/src/tsconfig.server.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/app",
5 | "baseUrl": "./",
6 | "module": "commonjs",
7 | "types": []
8 | },
9 | "exclude": ["test.ts", "**/*.spec.ts"],
10 | "angularCompilerOptions": {
11 | "entryModule": "app/app.server.module#AppServerModule"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/typings.d.ts:
--------------------------------------------------------------------------------
1 | /* SystemJS module definition */
2 | declare var module: NodeModule;
3 | interface NodeModule {
4 | id: string;
5 | }
6 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "outDir": "./dist/out-tsc",
5 | "sourceMap": true,
6 | "declaration": false,
7 | "moduleResolution": "node",
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "target": "es5",
11 | "typeRoots": [
12 | "node_modules/@types"
13 | ],
14 | "lib": [
15 | "es2017",
16 | "dom"
17 | ]
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rulesDirectory": ["node_modules/codelyzer"],
3 | "rules": {
4 | "arrow-return-shorthand": true,
5 | "callable-types": true,
6 | "class-name": true,
7 | "comment-format": [true, "check-space"],
8 | "curly": true,
9 | "eofline": true,
10 | "forin": true,
11 | "import-blacklist": [true, "rxjs"],
12 | "import-spacing": true,
13 | "indent": [true, "spaces"],
14 | "interface-over-type-literal": true,
15 | "label-position": true,
16 | "max-line-length": [true, 140],
17 | "member-access": false,
18 | "member-ordering": [
19 | true,
20 | {
21 | "order": [
22 | "static-field",
23 | "instance-field",
24 | "static-method",
25 | "instance-method"
26 | ]
27 | }
28 | ],
29 | "no-arg": true,
30 | "no-bitwise": true,
31 | "no-console": [true, "debug", "info", "time", "timeEnd", "trace"],
32 | "no-construct": true,
33 | "no-debugger": true,
34 | "no-duplicate-super": true,
35 | "no-empty": false,
36 | "no-empty-interface": true,
37 | "no-eval": true,
38 | "no-inferrable-types": [true, "ignore-params"],
39 | "no-misused-new": true,
40 | "no-non-null-assertion": true,
41 | "no-shadowed-variable": true,
42 | "no-string-literal": false,
43 | "no-string-throw": true,
44 | "no-switch-case-fall-through": true,
45 | "no-trailing-whitespace": true,
46 | "no-unnecessary-initializer": true,
47 | "no-unused-expression": true,
48 | "no-use-before-declare": true,
49 | "no-var-keyword": true,
50 | "object-literal-sort-keys": false,
51 | "one-line": [
52 | true,
53 | "check-open-brace",
54 | "check-catch",
55 | "check-else",
56 | "check-whitespace"
57 | ],
58 | "prefer-const": true,
59 | "quotemark": [true, "double"],
60 | "radix": true,
61 | "semicolon": [true, "always"],
62 | "triple-equals": [true, "allow-null-check"],
63 | "typedef-whitespace": [
64 | true,
65 | {
66 | "call-signature": "nospace",
67 | "index-signature": "nospace",
68 | "parameter": "nospace",
69 | "property-declaration": "nospace",
70 | "variable-declaration": "nospace"
71 | }
72 | ],
73 | "unified-signatures": true,
74 | "variable-name": false,
75 | "whitespace": [
76 | true,
77 | "check-branch",
78 | "check-decl",
79 | "check-operator",
80 | "check-separator",
81 | "check-type"
82 | ],
83 | "directive-selector": [true, "attribute", "app", "camelCase"],
84 | "component-selector": [true, "element", "app", "kebab-case"],
85 | "use-input-property-decorator": true,
86 | "use-output-property-decorator": true,
87 | "use-host-property-decorator": true,
88 | "no-input-rename": true,
89 | "no-output-rename": true,
90 | "use-life-cycle-interface": true,
91 | "use-pipe-transform-interface": true,
92 | "component-class-suffix": true,
93 | "directive-class-suffix": true
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/webpack.server.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const webpack = require("webpack");
3 |
4 | module.exports = {
5 | entry: { server: "./public/server.ts" },
6 | resolve: { extensions: [".js", ".ts"] },
7 | target: "node",
8 | // this makes sure we include node_modules and other 3rd party libraries
9 | externals: [/(node_modules|main\..*\.js)/],
10 | output: {
11 | path: path.join(__dirname, "./public/dist"),
12 | filename: "[name].js"
13 | },
14 | module: {
15 | rules: [{ test: /\.ts$/, loader: "ts-loader" }]
16 | },
17 | plugins: [
18 | // Temporary Fix for issue: https://github.com/angular/angular/issues/11580
19 | // for 'WARNING Critical dependency: the request of a dependency is an expression'
20 | new webpack.ContextReplacementPlugin(
21 | /(.+)?angular(\\|\/)core(.+)?/,
22 | path.join(__dirname, "src"), // location of your src
23 | {} // a map of your routes
24 | ),
25 | new webpack.ContextReplacementPlugin(
26 | /(.+)?express(\\|\/)(.+)?/,
27 | path.join(__dirname, "src"),
28 | {}
29 | )
30 | ]
31 | };
32 |
--------------------------------------------------------------------------------