├── .gitignore
├── README.md
├── angular-app
├── .editorconfig
├── .gitignore
├── README.md
├── angular-cli.json
├── e2e
│ ├── app.e2e-spec.ts
│ ├── app.po.ts
│ └── tsconfig.json
├── karma.conf.js
├── package-lock.json
├── package.json
├── protractor.conf.js
├── src
│ ├── app
│ │ ├── app.component.css
│ │ ├── app.component.html
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ ├── app.module.ts
│ │ ├── counter
│ │ │ ├── counter.component.css
│ │ │ ├── counter.component.html
│ │ │ ├── counter.component.spec.ts
│ │ │ └── counter.component.ts
│ │ ├── header
│ │ │ ├── header.component.css
│ │ │ ├── header.component.html
│ │ │ ├── header.component.spec.ts
│ │ │ └── header.component.ts
│ │ └── iframe
│ │ │ ├── iframe.component.css
│ │ │ ├── iframe.component.html
│ │ │ ├── iframe.component.spec.ts
│ │ │ └── iframe.component.ts
│ ├── assets
│ │ └── .gitkeep
│ ├── environments
│ │ ├── environment.prod.ts
│ │ └── environment.ts
│ ├── favicon.ico
│ ├── index.html
│ ├── main.ts
│ ├── polyfills.ts
│ ├── styles.css
│ ├── test.ts
│ └── tsconfig.json
└── tslint.json
├── angularjs-app
├── .gitignore
└── src
│ ├── app
│ ├── app.main.js
│ ├── app.routes.js
│ ├── counter.controller.js
│ └── counter.html
│ ├── assets
│ └── style.css
│ └── index.html
├── package-lock.json
├── package.json
└── server.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # compiled output
4 | /dist
5 | /tmp
6 |
7 | # dependencies
8 | /node_modules
9 |
10 | # IDEs and editors
11 | /.idea
12 | .project
13 | .classpath
14 | .c9/
15 | *.launch
16 | .settings/
17 |
18 | # IDE - VSCode
19 | .vscode/*
20 | !.vscode/settings.json
21 | !.vscode/tasks.json
22 | !.vscode/launch.json
23 | !.vscode/extensions.json
24 |
25 | # misc
26 | /.sass-cache
27 | /connect.lock
28 | /coverage/*
29 | /libpeerconnection.log
30 | npm-debug.log
31 | testem.log
32 | /typings
33 |
34 | # e2e
35 | /e2e/*.js
36 | /e2e/*.map
37 |
38 | #System Files
39 | .DS_Store
40 | Thumbs.db
41 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Alternative AngularJS migration using iframes demo
2 |
3 | ## Introduction
4 |
5 | This sample app demonstrates how you can migrate an AngularJS application to Angular using iframes.
6 |
7 | This solution isn't for everyone, but if you have a particularly challenging AngularJS application, one that doesn't quite fit into the official migration strategy then this solution might be best for you.
8 |
9 | This is a great solution if:
10 |
11 | - If you AngularJS app depends on a lot of legacy 3rd party modules.
12 | - If your AngularJS app uses an old UI framework like Bootstrap 2 and at the same time you migrate to Angular you also want to move to a newer UI framework like Bootstrap 4.
13 | - If you have a very old AngularJS app, even pre 1.0, then this solution works.
14 | - If your AngularJS app is architected poorly, does not use current best practices, uses controllers over components, relies on scope inheritance, $scope.$watch, emit and broadcast.
15 | - Is not an SPA, this solution will work even if your AngularJS application is a Multi Page Application and you want to iteratively migrate to an Angular SPA.
16 |
17 | ## How it works
18 |
19 | We solve this by having Angular as the host application and them migrating one route at a time from AngularJS to Angular.
20 |
21 | If the route has been migrated to Angular then Angular handles the route and displays that page.
22 |
23 | if the route has not been migrated to Angular it instead iframes in the appropriate AngularJS app page.
24 |
25 | We use localStorage and StorageEvent to share state between our Angular and AngularJS applications.
26 |
27 | If we are displaying the AngularJS page and the user clicks on a route which AngularJS can't handle (it's been migrated to the host Angular app) then it propogates the route change request to the Angular app and lets it see if it can handle the route.
28 |
29 | ## Folder structure
30 |
31 | ```
32 | angular-app // this is the angular application
33 | angularjs-app // this is the legacy angularjs application we want to migrate from
34 | server.js // this is the webserver which serves both from the same host
35 | ```
36 |
37 | ## Setup & Run
38 |
39 | First we need to build the angular application using the Angular CLI
40 |
41 | ```
42 | cd angular-app
43 | npm install
44 | ng build
45 | ```
46 |
47 | - Run the main server.
48 |
49 | ```
50 | npm install
51 | npm start
52 | ```
53 |
54 | This launches a web-server running on http://localhost:8080
55 |
56 | The `/` path serves the angular application.
57 | The `/legacy` path serves the angularjs application.
58 |
59 |
60 |
--------------------------------------------------------------------------------
/angular-app/.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 |
--------------------------------------------------------------------------------
/angular-app/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # compiled output
4 | /dist
5 | /tmp
6 |
7 | # dependencies
8 | /node_modules
9 |
10 | # IDEs and editors
11 | /.idea
12 | .project
13 | .classpath
14 | .c9/
15 | *.launch
16 | .settings/
17 |
18 | # IDE - VSCode
19 | .vscode/*
20 | !.vscode/settings.json
21 | !.vscode/tasks.json
22 | !.vscode/launch.json
23 | !.vscode/extensions.json
24 |
25 | # misc
26 | /.sass-cache
27 | /connect.lock
28 | /coverage/*
29 | /libpeerconnection.log
30 | npm-debug.log
31 | testem.log
32 | /typings
33 |
34 | # e2e
35 | /e2e/*.js
36 | /e2e/*.map
37 |
38 | #System Files
39 | .DS_Store
40 | Thumbs.db
41 |
--------------------------------------------------------------------------------
/angular-app/README.md:
--------------------------------------------------------------------------------
1 | # HostApp
2 |
3 | This project was generated with [angular-cli](https://github.com/angular/angular-cli) version 1.0.0-beta.28.3.
4 |
5 | ## Development server
6 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
7 |
8 | ## Code scaffolding
9 |
10 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive/pipe/service/class/module`.
11 |
12 | ## Build
13 |
14 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.
15 |
16 | ## Running unit tests
17 |
18 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
19 |
20 | ## Running end-to-end tests
21 |
22 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
23 | Before running the tests make sure you are serving the app via `ng serve`.
24 |
25 | ## Deploying to GitHub Pages
26 |
27 | Run `ng github-pages:deploy` to deploy to GitHub Pages.
28 |
29 | ## Further help
30 |
31 | To get more help on the `angular-cli` use `ng help` or go check out the [Angular-CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
32 |
--------------------------------------------------------------------------------
/angular-app/angular-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "project": {
3 | "version": "1.0.0-beta.28.3",
4 | "name": "host-app"
5 | },
6 | "apps": [
7 | {
8 | "root": "src",
9 | "outDir": "dist",
10 | "assets": [
11 | "assets",
12 | "favicon.ico"
13 | ],
14 | "index": "index.html",
15 | "main": "main.ts",
16 | "polyfills": "polyfills.ts",
17 | "test": "test.ts",
18 | "tsconfig": "tsconfig.json",
19 | "prefix": "app",
20 | "styles": [
21 | "styles.css"
22 | ],
23 | "scripts": [],
24 | "environments": {
25 | "source": "environments/environment.ts",
26 | "dev": "environments/environment.ts",
27 | "prod": "environments/environment.prod.ts"
28 | }
29 | }
30 | ],
31 | "e2e": {
32 | "protractor": {
33 | "config": "./protractor.conf.js"
34 | }
35 | },
36 | "lint": [
37 | {
38 | "files": "src/**/*.ts",
39 | "project": "src/tsconfig.json"
40 | },
41 | {
42 | "files": "e2e/**/*.ts",
43 | "project": "e2e/tsconfig.json"
44 | }
45 | ],
46 | "test": {
47 | "karma": {
48 | "config": "./karma.conf.js"
49 | }
50 | },
51 | "defaults": {
52 | "styleExt": "css",
53 | "prefixInterfaces": false,
54 | "inline": {
55 | "style": false,
56 | "template": false
57 | },
58 | "spec": {
59 | "class": false,
60 | "component": true,
61 | "directive": true,
62 | "module": false,
63 | "pipe": true,
64 | "service": true
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/angular-app/e2e/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { HostAppPage } from './app.po';
2 |
3 | describe('host-app App', function() {
4 | let page: HostAppPage;
5 |
6 | beforeEach(() => {
7 | page = new HostAppPage();
8 | });
9 |
10 | it('should display message saying app works', () => {
11 | page.navigateTo();
12 | expect(page.getParagraphText()).toEqual('app works!');
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/angular-app/e2e/app.po.ts:
--------------------------------------------------------------------------------
1 | import { browser, element, by } from 'protractor';
2 |
3 | export class HostAppPage {
4 | navigateTo() {
5 | return browser.get('/');
6 | }
7 |
8 | getParagraphText() {
9 | return element(by.css('app-root h1')).getText();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/angular-app/e2e/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "declaration": false,
5 | "emitDecoratorMetadata": true,
6 | "experimentalDecorators": true,
7 | "module": "commonjs",
8 | "moduleResolution": "node",
9 | "outDir": "../dist/out-tsc-e2e",
10 | "sourceMap": true,
11 | "target": "es5",
12 | "typeRoots": [
13 | "../node_modules/@types"
14 | ]
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/angular-app/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/0.13/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | config.set({
6 | basePath: '',
7 | frameworks: ['jasmine', 'angular-cli'],
8 | plugins: [
9 | require('karma-jasmine'),
10 | require('karma-chrome-launcher'),
11 | require('karma-remap-istanbul'),
12 | require('angular-cli/plugins/karma')
13 | ],
14 | files: [
15 | { pattern: './src/test.ts', watched: false }
16 | ],
17 | preprocessors: {
18 | './src/test.ts': ['angular-cli']
19 | },
20 | mime: {
21 | 'text/x-typescript': ['ts','tsx']
22 | },
23 | remapIstanbulReporter: {
24 | reports: {
25 | html: 'coverage',
26 | lcovonly: './coverage/coverage.lcov'
27 | }
28 | },
29 | angularCli: {
30 | config: './angular-cli.json',
31 | environment: 'dev'
32 | },
33 | reporters: config.angularCli && config.angularCli.codeCoverage
34 | ? ['progress', 'karma-remap-istanbul']
35 | : ['progress'],
36 | port: 9876,
37 | colors: true,
38 | logLevel: config.LOG_INFO,
39 | autoWatch: true,
40 | browsers: ['Chrome'],
41 | singleRun: false
42 | });
43 | };
44 |
--------------------------------------------------------------------------------
/angular-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "host-app",
3 | "version": "0.0.0",
4 | "license": "MIT",
5 | "angular-cli": {},
6 | "scripts": {
7 | "ng": "ng",
8 | "start": "ng serve",
9 | "test": "ng test",
10 | "pree2e": "webdriver-manager update --standalone false --gecko false",
11 | "e2e": "protractor"
12 | },
13 | "private": true,
14 | "dependencies": {
15 | "@angular/common": "^2.3.1",
16 | "@angular/compiler": "^2.3.1",
17 | "@angular/core": "^2.3.1",
18 | "@angular/forms": "^2.3.1",
19 | "@angular/http": "^2.3.1",
20 | "@angular/platform-browser": "^2.3.1",
21 | "@angular/platform-browser-dynamic": "^2.3.1",
22 | "@angular/router": "^3.3.1",
23 | "core-js": "^2.4.1",
24 | "rxjs": "^5.0.1",
25 | "ts-helpers": "^1.1.1",
26 | "zone.js": "^0.7.2"
27 | },
28 | "devDependencies": {
29 | "@angular/compiler-cli": "^2.3.1",
30 | "@types/jasmine": "2.5.38",
31 | "@types/node": "^6.0.42",
32 | "angular-cli": "1.0.0-beta.28.3",
33 | "codelyzer": "~2.0.0-beta.1",
34 | "jasmine-core": "2.5.2",
35 | "jasmine-spec-reporter": "2.5.0",
36 | "karma": "1.2.0",
37 | "karma-chrome-launcher": "^2.0.0",
38 | "karma-cli": "^1.0.1",
39 | "karma-jasmine": "^1.0.2",
40 | "karma-remap-istanbul": "^0.2.1",
41 | "protractor": "~4.0.13",
42 | "ts-node": "1.2.1",
43 | "tslint": "^4.3.0",
44 | "typescript": "~2.0.3"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/angular-app/protractor.conf.js:
--------------------------------------------------------------------------------
1 | // Protractor configuration file, see link for more information
2 | // https://github.com/angular/protractor/blob/master/lib/config.ts
3 |
4 | /*global jasmine */
5 | var SpecReporter = require('jasmine-spec-reporter');
6 |
7 | exports.config = {
8 | allScriptsTimeout: 11000,
9 | specs: [
10 | './e2e/**/*.e2e-spec.ts'
11 | ],
12 | capabilities: {
13 | 'browserName': 'chrome'
14 | },
15 | directConnect: true,
16 | baseUrl: 'http://localhost:4200/',
17 | framework: 'jasmine',
18 | jasmineNodeOpts: {
19 | showColors: true,
20 | defaultTimeoutInterval: 30000,
21 | print: function() {}
22 | },
23 | useAllAngular2AppRoots: true,
24 | beforeLaunch: function() {
25 | require('ts-node').register({
26 | project: 'e2e'
27 | });
28 | },
29 | onPrepare: function() {
30 | jasmine.getEnv().addReporter(new SpecReporter());
31 | }
32 | };
33 |
--------------------------------------------------------------------------------
/angular-app/src/app/app.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawache/alt-angularjs-migration-using-iframes-demo/363cb3622136fc2ff7234a9ef8f581ff83e454fb/angular-app/src/app/app.component.css
--------------------------------------------------------------------------------
/angular-app/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/angular-app/src/app/app.component.spec.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable:no-unused-variable */
2 |
3 | import { TestBed, async } from '@angular/core/testing';
4 | import { AppComponent } from './app.component';
5 |
6 | describe('AppComponent', () => {
7 | beforeEach(() => {
8 | TestBed.configureTestingModule({
9 | declarations: [
10 | AppComponent
11 | ],
12 | });
13 | TestBed.compileComponents();
14 | });
15 |
16 | it('should create the app', async(() => {
17 | const fixture = TestBed.createComponent(AppComponent);
18 | const app = fixture.debugElement.componentInstance;
19 | expect(app).toBeTruthy();
20 | }));
21 |
22 | it(`should have as title 'app works!'`, async(() => {
23 | const fixture = TestBed.createComponent(AppComponent);
24 | const app = fixture.debugElement.componentInstance;
25 | expect(app.title).toEqual('app works!');
26 | }));
27 |
28 | it('should render title in a h1 tag', async(() => {
29 | const fixture = TestBed.createComponent(AppComponent);
30 | fixture.detectChanges();
31 | const compiled = fixture.debugElement.nativeElement;
32 | expect(compiled.querySelector('h1').textContent).toContain('app works!');
33 | }));
34 | });
35 |
--------------------------------------------------------------------------------
/angular-app/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-root',
5 | templateUrl: './app.component.html',
6 | styleUrls: ['./app.component.css']
7 | })
8 | export class AppComponent {
9 | title = 'app works!';
10 | }
11 |
--------------------------------------------------------------------------------
/angular-app/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import {BrowserModule} from '@angular/platform-browser';
2 | import {NgModule} from '@angular/core';
3 | import {FormsModule} from '@angular/forms';
4 | import {HttpModule} from '@angular/http';
5 |
6 | import {Routes, RouterModule} from "@angular/router";
7 | import {APP_BASE_HREF} from '@angular/common';
8 |
9 | import {AppComponent} from './app.component';
10 | import {HeaderComponent} from './header/header.component';
11 | import {IframeComponent} from './iframe/iframe.component';
12 | import {CounterComponent} from './counter/counter.component';
13 |
14 | const routes: Routes = [
15 | {path: '', redirectTo: 'angular', pathMatch: 'full'},
16 | {path: 'angular', component: CounterComponent},
17 | {component: IframeComponent, path: "**"} // Fallback route
18 | ];
19 |
20 | @NgModule({
21 | declarations: [
22 | AppComponent,
23 | HeaderComponent,
24 | IframeComponent,
25 | CounterComponent
26 | ],
27 | imports: [
28 | BrowserModule,
29 | FormsModule,
30 | HttpModule,
31 | RouterModule.forRoot(routes, {useHash: true})
32 | ],
33 | providers: [
34 | // In Angular 1.6 hash based routing now has #! for google ajax crawlers, we should match in Angular
35 | // https://docs.angularjs.org/guide/migration#commit-aa077e8
36 | {provide: APP_BASE_HREF, useValue: '!'}
37 | ],
38 | bootstrap: [AppComponent]
39 | })
40 | export class AppModule {
41 | }
42 |
--------------------------------------------------------------------------------
/angular-app/src/app/counter/counter.component.css:
--------------------------------------------------------------------------------
1 | #counter {
2 | padding: 20px;
3 | }
4 |
5 | #counter h1 {
6 | line-height: 300px;
7 | font-size: 200px;
8 | }
9 |
10 | #reset {
11 | margin-bottom: 20px;
12 | }
13 |
14 |
15 | .noselect {
16 | -webkit-touch-callout: none; /* iOS Safari */
17 | -webkit-user-select: none; /* Safari */
18 | -khtml-user-select: none; /* Konqueror HTML */
19 | -moz-user-select: none; /* Firefox */
20 | -ms-user-select: none; /* Internet Explorer/Edge */
21 | user-select: none; /* Non-prefixed version, currently
22 | supported by Chrome and Opera */
23 | }
24 |
--------------------------------------------------------------------------------
/angular-app/src/app/counter/counter.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
{{ counter }}
6 |
7 |
8 |
Click above to increment the counter, the same number is shared between Angular and AngularJS
9 |
10 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/angular-app/src/app/counter/counter.component.spec.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable:no-unused-variable */
2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
3 | import { By } from '@angular/platform-browser';
4 | import { DebugElement } from '@angular/core';
5 |
6 | import { CounterComponent } from './counter.component';
7 |
8 | describe('CounterComponent', () => {
9 | let component: CounterComponent;
10 | let fixture: ComponentFixture;
11 |
12 | beforeEach(async(() => {
13 | TestBed.configureTestingModule({
14 | declarations: [ CounterComponent ]
15 | })
16 | .compileComponents();
17 | }));
18 |
19 | beforeEach(() => {
20 | fixture = TestBed.createComponent(CounterComponent);
21 | component = fixture.componentInstance;
22 | fixture.detectChanges();
23 | });
24 |
25 | it('should create', () => {
26 | expect(component).toBeTruthy();
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/angular-app/src/app/counter/counter.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-counter',
5 | templateUrl: './counter.component.html',
6 | styleUrls: ['./counter.component.css']
7 | })
8 | export class CounterComponent implements OnInit {
9 |
10 | counter = 0;
11 |
12 | constructor() {
13 | }
14 |
15 | increment() {
16 | this.counter += 1;
17 | localStorage.setItem("counter", this.counter.toString())
18 | }
19 |
20 | reset() {
21 | this.counter = 0;
22 | localStorage.setItem("counter", this.counter.toString())
23 | }
24 |
25 | ngOnInit() {
26 | this.counter = parseInt(localStorage.getItem("counter")) || 0;
27 |
28 | window.addEventListener('storage', (e) => {
29 | if (e.key == "counter") {
30 | this.counter = parseInt(e.newValue);
31 | console.log("'counter' key updated to " + this.counter);
32 | }
33 | });
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/angular-app/src/app/header/header.component.css:
--------------------------------------------------------------------------------
1 | nav {
2 | margin-bottom: 2em;
3 | }
4 |
--------------------------------------------------------------------------------
/angular-app/src/app/header/header.component.html:
--------------------------------------------------------------------------------
1 |
31 |
--------------------------------------------------------------------------------
/angular-app/src/app/header/header.component.spec.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable:no-unused-variable */
2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
3 | import { By } from '@angular/platform-browser';
4 | import { DebugElement } from '@angular/core';
5 |
6 | import { HeaderComponent } from './header.component';
7 |
8 | describe('HeaderComponent', () => {
9 | let component: HeaderComponent;
10 | let fixture: ComponentFixture;
11 |
12 | beforeEach(async(() => {
13 | TestBed.configureTestingModule({
14 | declarations: [ HeaderComponent ]
15 | })
16 | .compileComponents();
17 | }));
18 |
19 | beforeEach(() => {
20 | fixture = TestBed.createComponent(HeaderComponent);
21 | component = fixture.componentInstance;
22 | fixture.detectChanges();
23 | });
24 |
25 | it('should create', () => {
26 | expect(component).toBeTruthy();
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/angular-app/src/app/header/header.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-header',
5 | templateUrl: './header.component.html',
6 | styleUrls: ['./header.component.css']
7 | })
8 | export class HeaderComponent implements OnInit {
9 |
10 | constructor() { }
11 |
12 | ngOnInit() {
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/angular-app/src/app/iframe/iframe.component.css:
--------------------------------------------------------------------------------
1 | /* This makes the iframe take up full width and height of the page */
2 | iframe {
3 | position: absolute;
4 | top: 0;
5 | left: 0;
6 | width: 100%;
7 | height: 100%;
8 | border:0;
9 | }
10 |
--------------------------------------------------------------------------------
/angular-app/src/app/iframe/iframe.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/angular-app/src/app/iframe/iframe.component.spec.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable:no-unused-variable */
2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
3 | import { By } from '@angular/platform-browser';
4 | import { DebugElement } from '@angular/core';
5 |
6 | import { IframeComponent } from './iframe.component';
7 |
8 | describe('IframeComponent', () => {
9 | let component: IframeComponent;
10 | let fixture: ComponentFixture;
11 |
12 | beforeEach(async(() => {
13 | TestBed.configureTestingModule({
14 | declarations: [ IframeComponent ]
15 | })
16 | .compileComponents();
17 | }));
18 |
19 | beforeEach(() => {
20 | fixture = TestBed.createComponent(IframeComponent);
21 | component = fixture.componentInstance;
22 | fixture.detectChanges();
23 | });
24 |
25 | it('should create', () => {
26 | expect(component).toBeTruthy();
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/angular-app/src/app/iframe/iframe.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, OnInit} from '@angular/core';
2 | import {ActivatedRoute, Router} from "@angular/router";
3 | import {DomSanitizer, SafeResourceUrl} from '@angular/platform-browser';
4 |
5 |
6 | @Component({
7 | selector: 'app-iframe',
8 | templateUrl: './iframe.component.html',
9 | styleUrls: ['./iframe.component.css']
10 | })
11 | export class IframeComponent implements OnInit {
12 | public url: SafeResourceUrl;
13 | private counter = 0;
14 |
15 |
16 | constructor(private route: ActivatedRoute, private sanitizer: DomSanitizer, private router: Router) {
17 | this.route.url.subscribe(urlSegments => {
18 | // Create a unique URL each time so the iframe will detect the change
19 | this.counter += 1;
20 | const requestedUrl = '/legacy/?counter=' + this.counter + '#!/' + urlSegments.join('');
21 | console.log(requestedUrl);
22 |
23 | // Angular by default sanitises a URL, we need to bypass that so the full URL is rendered
24 | // NOTE: Need to look into security considerations of this
25 | this.url = this.sanitizer.bypassSecurityTrustResourceUrl(requestedUrl);
26 | });
27 |
28 | this.listenForFallbackRoutingEvents();
29 | }
30 |
31 |
32 | /*
33 | If the iframed-in app can't resolve a URL itself it will post a message to the parent
34 | iframe (this app). Listen to those messages and attempt to navigate to that URL.
35 | */
36 | listenForFallbackRoutingEvents() {
37 | // Create IE + others compatible event handler
38 | const eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
39 | const eventer = window[eventMethod];
40 | const messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
41 |
42 |
43 | eventer(messageEvent, (e) => {
44 | if (e.data.navigateTo) {
45 | console.log('parent received message!: ', e.data);
46 | let url = e.data.navigateTo;
47 | console.log(url);
48 | this.router.navigateByUrl(url);
49 | }
50 | }, false);
51 | }
52 |
53 | ngOnInit() {
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/angular-app/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawache/alt-angularjs-migration-using-iframes-demo/363cb3622136fc2ff7234a9ef8f581ff83e454fb/angular-app/src/assets/.gitkeep
--------------------------------------------------------------------------------
/angular-app/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true
3 | };
4 |
--------------------------------------------------------------------------------
/angular-app/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // The file contents for the current environment will overwrite these during build.
2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do
3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead.
4 | // The list of which env maps to which file can be found in `angular-cli.json`.
5 |
6 | export const environment = {
7 | production: false
8 | };
9 |
--------------------------------------------------------------------------------
/angular-app/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jawache/alt-angularjs-migration-using-iframes-demo/363cb3622136fc2ff7234a9ef8f581ff83e454fb/angular-app/src/favicon.ico
--------------------------------------------------------------------------------
/angular-app/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Loading...
5 |
6 |
7 |
8 | Angular HostApp
9 |
10 |
11 |
13 |
14 |
16 |
17 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/angular-app/src/main.ts:
--------------------------------------------------------------------------------
1 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
2 | import { enableProdMode } from '@angular/core';
3 | import { environment } from './environments/environment';
4 | import { AppModule } from './app/app.module';
5 |
6 | if (environment.production) {
7 | enableProdMode();
8 | }
9 |
10 | platformBrowserDynamic().bootstrapModule(AppModule);
11 |
--------------------------------------------------------------------------------
/angular-app/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 |
--------------------------------------------------------------------------------
/angular-app/src/styles.css:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 | body {
3 | background-color: #5CB8E5 !important;
4 | color: white !important;
5 | }
6 |
--------------------------------------------------------------------------------
/angular-app/src/test.ts:
--------------------------------------------------------------------------------
1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files
2 |
3 | import 'zone.js/dist/long-stack-trace-zone';
4 | import 'zone.js/dist/proxy.js';
5 | import 'zone.js/dist/sync-test';
6 | import 'zone.js/dist/jasmine-patch';
7 | import 'zone.js/dist/async-test';
8 | import 'zone.js/dist/fake-async-test';
9 | import { getTestBed } from '@angular/core/testing';
10 | import {
11 | BrowserDynamicTestingModule,
12 | platformBrowserDynamicTesting
13 | } from '@angular/platform-browser-dynamic/testing';
14 |
15 | // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
16 | declare var __karma__: any;
17 | declare var require: any;
18 |
19 | // Prevent Karma from running prematurely.
20 | __karma__.loaded = function () {};
21 |
22 | // First, initialize the Angular testing environment.
23 | getTestBed().initTestEnvironment(
24 | BrowserDynamicTestingModule,
25 | platformBrowserDynamicTesting()
26 | );
27 | // Then we find all the tests.
28 | const context = require.context('./', true, /\.spec\.ts$/);
29 | // And load the modules.
30 | context.keys().map(context);
31 | // Finally, start Karma to run the tests.
32 | __karma__.start();
33 |
--------------------------------------------------------------------------------
/angular-app/src/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "",
4 | "declaration": false,
5 | "emitDecoratorMetadata": true,
6 | "experimentalDecorators": true,
7 | "lib": ["es6", "dom"],
8 | "mapRoot": "./",
9 | "module": "es6",
10 | "moduleResolution": "node",
11 | "outDir": "../dist/out-tsc",
12 | "sourceMap": true,
13 | "target": "es5",
14 | "typeRoots": [
15 | "../node_modules/@types"
16 | ]
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/angular-app/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rulesDirectory": [
3 | "node_modules/codelyzer"
4 | ],
5 | "rules": {
6 | "callable-types": true,
7 | "class-name": true,
8 | "comment-format": [
9 | true,
10 | "check-space"
11 | ],
12 | "curly": true,
13 | "eofline": true,
14 | "forin": true,
15 | "import-blacklist": [true, "rxjs"],
16 | "import-spacing": true,
17 | "indent": [
18 | true,
19 | "spaces"
20 | ],
21 | "interface-over-type-literal": true,
22 | "label-position": true,
23 | "max-line-length": [
24 | true,
25 | 140
26 | ],
27 | "member-access": false,
28 | "member-ordering": [
29 | true,
30 | "static-before-instance",
31 | "variables-before-functions"
32 | ],
33 | "no-arg": true,
34 | "no-bitwise": true,
35 | "no-console": [
36 | true,
37 | "debug",
38 | "info",
39 | "time",
40 | "timeEnd",
41 | "trace"
42 | ],
43 | "no-construct": true,
44 | "no-debugger": true,
45 | "no-duplicate-variable": true,
46 | "no-empty": false,
47 | "no-empty-interface": true,
48 | "no-eval": true,
49 | "no-inferrable-types": true,
50 | "no-shadowed-variable": true,
51 | "no-string-literal": false,
52 | "no-string-throw": true,
53 | "no-switch-case-fall-through": true,
54 | "no-trailing-whitespace": true,
55 | "no-unused-expression": true,
56 | "no-use-before-declare": true,
57 | "no-var-keyword": true,
58 | "object-literal-sort-keys": false,
59 | "one-line": [
60 | true,
61 | "check-open-brace",
62 | "check-catch",
63 | "check-else",
64 | "check-whitespace"
65 | ],
66 | "prefer-const": true,
67 | "quotemark": [
68 | true,
69 | "single"
70 | ],
71 | "radix": true,
72 | "semicolon": [
73 | "always"
74 | ],
75 | "triple-equals": [
76 | true,
77 | "allow-null-check"
78 | ],
79 | "typedef-whitespace": [
80 | true,
81 | {
82 | "call-signature": "nospace",
83 | "index-signature": "nospace",
84 | "parameter": "nospace",
85 | "property-declaration": "nospace",
86 | "variable-declaration": "nospace"
87 | }
88 | ],
89 | "typeof-compare": true,
90 | "unified-signatures": true,
91 | "variable-name": false,
92 | "whitespace": [
93 | true,
94 | "check-branch",
95 | "check-decl",
96 | "check-operator",
97 | "check-separator",
98 | "check-type"
99 | ],
100 |
101 | "directive-selector": [true, "attribute", "app", "camelCase"],
102 | "component-selector": [true, "element", "app", "kebab-case"],
103 | "use-input-property-decorator": true,
104 | "use-output-property-decorator": true,
105 | "use-host-property-decorator": true,
106 | "no-input-rename": true,
107 | "no-output-rename": true,
108 | "use-life-cycle-interface": true,
109 | "use-pipe-transform-interface": true,
110 | "component-class-suffix": true,
111 | "directive-class-suffix": true,
112 | "no-access-missing-member": true,
113 | "templates-use-public": true,
114 | "invoke-injectable": true
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/angularjs-app/.gitignore:
--------------------------------------------------------------------------------
1 | logs/*
2 | !.gitkeep
3 | node_modules/
4 | bower_components/
5 | tmp
6 | .DS_Store
7 | .idea
8 | src/libs
9 | data/db.json
--------------------------------------------------------------------------------
/angularjs-app/src/app/app.main.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | angular
3 | .module('legacy', [
4 | 'ngResource',
5 | 'ui.router'
6 | ]);
7 | })();
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/angularjs-app/src/app/app.routes.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | angular
3 | .module('legacy')
4 | .config(function ($stateProvider, $urlRouterProvider) {
5 | $stateProvider
6 | .state('cat', {
7 | url : "/angularjs",
8 | templateUrl: './app/counter.html',
9 | controller : 'CounterCtrl'
10 | });
11 |
12 | $urlRouterProvider.otherwise(function ($injector, $location) {
13 | // If this app can't handle the route, let the parent iframe, the host Angular app, try and handle it.
14 | var path = $location.path();
15 | console.log("The AngularJS app recieved a path it couldn't resolve, posting to parent iframe see if it can handle the path " + path);
16 | // parent is always the parent iframe, we can use the postMessage API to post the URL to the parent iframe here.
17 | // NOTE: Passing in * is a security vulnerability, need to think about and address this in a real production application.
18 | parent.postMessage({navigateTo: path}, "*");
19 | });
20 | });
21 | })();
--------------------------------------------------------------------------------
/angularjs-app/src/app/counter.controller.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | angular
3 | .module('legacy')
4 | .controller('CounterCtrl', function ($scope) {
5 | $scope.counter = parseInt(localStorage.getItem("counter")) || 0;
6 |
7 | $scope.increment = function () {
8 | $scope.counter += 1;
9 | console.log("Setting the counter to " + $scope.counter);
10 | localStorage.setItem("counter", $scope.counter)
11 | };
12 |
13 | $scope.reset = function () {
14 | $scope.counter = 0;
15 | console.log("Setting the counter to " + $scope.counter);
16 | localStorage.setItem("counter", 0)
17 | }
18 |
19 | });
20 | })();
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/angularjs-app/src/app/counter.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ counter }}
4 |
5 |
6 |
Click above to increment the counter, the same number is shared between Angular and AngularJS
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/angularjs-app/src/assets/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #DD6271;
3 | color: white;
4 | /*font-size: 24px;*/
5 | }
6 |
7 | #footer {
8 | padding-top: 50px;
9 | width: 100%;
10 | }
11 |
12 | #footer a {
13 | font-size: 16px;
14 | color: white;
15 | }
16 |
17 | #counter {
18 | padding: 20px;
19 | }
20 |
21 | #counter h1 {
22 | line-height: 300px;
23 | font-size: 200px;
24 | }
25 |
26 | #reset {
27 | margin-bottom: 20px;
28 | }
29 |
30 |
31 | .noselect {
32 | -webkit-touch-callout: none; /* iOS Safari */
33 | -webkit-user-select: none; /* Safari */
34 | -khtml-user-select: none; /* Konqueror HTML */
35 | -moz-user-select: none; /* Firefox */
36 | -ms-user-select: none; /* Internet Explorer/Edge */
37 | user-select: none; /* Non-prefixed version, currently
38 | supported by Chrome and Opera */
39 | }
--------------------------------------------------------------------------------
/angularjs-app/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | AngularJS Legacy App
6 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
32 |
33 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "alt-angularjs-migration",
3 | "version": "0.0.1",
4 | "lockfileVersion": 1,
5 | "dependencies": {
6 | "accepts": {
7 | "version": "1.3.4",
8 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz",
9 | "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8="
10 | },
11 | "array-flatten": {
12 | "version": "1.1.1",
13 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
14 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
15 | },
16 | "content-disposition": {
17 | "version": "0.5.2",
18 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
19 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ="
20 | },
21 | "content-type": {
22 | "version": "1.0.2",
23 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz",
24 | "integrity": "sha1-t9ETrueo3Se9IRM8TcJSnfFyHu0="
25 | },
26 | "cookie": {
27 | "version": "0.3.1",
28 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
29 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
30 | },
31 | "cookie-signature": {
32 | "version": "1.0.6",
33 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
34 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
35 | },
36 | "debug": {
37 | "version": "2.6.8",
38 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
39 | "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw="
40 | },
41 | "depd": {
42 | "version": "1.1.1",
43 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
44 | "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k="
45 | },
46 | "destroy": {
47 | "version": "1.0.4",
48 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
49 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
50 | },
51 | "ee-first": {
52 | "version": "1.1.1",
53 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
54 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
55 | },
56 | "encodeurl": {
57 | "version": "1.0.1",
58 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz",
59 | "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA="
60 | },
61 | "escape-html": {
62 | "version": "1.0.3",
63 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
64 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
65 | },
66 | "etag": {
67 | "version": "1.8.0",
68 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.0.tgz",
69 | "integrity": "sha1-b2Ma7zNtbEY2K1F2QETOIWvjwFE="
70 | },
71 | "express": {
72 | "version": "4.15.4",
73 | "resolved": "https://registry.npmjs.org/express/-/express-4.15.4.tgz",
74 | "integrity": "sha1-Ay4iU0ic+PzgJma+yj0R7XotrtE="
75 | },
76 | "finalhandler": {
77 | "version": "1.0.4",
78 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.4.tgz",
79 | "integrity": "sha512-16l/r8RgzlXKmFOhZpHBztvye+lAhC5SU7hXavnerC9UfZqZxxXl3BzL8MhffPT3kF61lj9Oav2LKEzh0ei7tg=="
80 | },
81 | "forwarded": {
82 | "version": "0.1.0",
83 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz",
84 | "integrity": "sha1-Ge+YdMSuHCl7zweP3mOgm2aoQ2M="
85 | },
86 | "fresh": {
87 | "version": "0.5.0",
88 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.0.tgz",
89 | "integrity": "sha1-9HTKXmqSRtb9jglTz6m5yAWvp44="
90 | },
91 | "http-errors": {
92 | "version": "1.6.2",
93 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz",
94 | "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY="
95 | },
96 | "inherits": {
97 | "version": "2.0.3",
98 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
99 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
100 | },
101 | "ipaddr.js": {
102 | "version": "1.4.0",
103 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.4.0.tgz",
104 | "integrity": "sha1-KWrKh4qCGBbluF0KKFqZvP9FgvA="
105 | },
106 | "media-typer": {
107 | "version": "0.3.0",
108 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
109 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
110 | },
111 | "merge-descriptors": {
112 | "version": "1.0.1",
113 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
114 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
115 | },
116 | "methods": {
117 | "version": "1.1.2",
118 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
119 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
120 | },
121 | "mime": {
122 | "version": "1.3.4",
123 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz",
124 | "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM="
125 | },
126 | "mime-db": {
127 | "version": "1.29.0",
128 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.29.0.tgz",
129 | "integrity": "sha1-SNJtI1WJZRcErFkWygYAGRQmaHg="
130 | },
131 | "mime-types": {
132 | "version": "2.1.16",
133 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.16.tgz",
134 | "integrity": "sha1-K4WKUuXs1RbbiXrCvodIeDBpjiM="
135 | },
136 | "ms": {
137 | "version": "2.0.0",
138 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
139 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
140 | },
141 | "negotiator": {
142 | "version": "0.6.1",
143 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
144 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
145 | },
146 | "on-finished": {
147 | "version": "2.3.0",
148 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
149 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc="
150 | },
151 | "parseurl": {
152 | "version": "1.3.1",
153 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz",
154 | "integrity": "sha1-yKuMkiO6NIiKpkopeyiFO+wY2lY="
155 | },
156 | "path-to-regexp": {
157 | "version": "0.1.7",
158 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
159 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
160 | },
161 | "proxy-addr": {
162 | "version": "1.1.5",
163 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.5.tgz",
164 | "integrity": "sha1-ccDuOxAt4/IC87ZPYI0XP8uhqRg="
165 | },
166 | "qs": {
167 | "version": "6.5.0",
168 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.0.tgz",
169 | "integrity": "sha512-fjVFjW9yhqMhVGwRExCXLhJKrLlkYSaxNWdyc9rmHlrVZbk35YHH312dFd7191uQeXkI3mKLZTIbSvIeFwFemg=="
170 | },
171 | "range-parser": {
172 | "version": "1.2.0",
173 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
174 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
175 | },
176 | "send": {
177 | "version": "0.15.4",
178 | "resolved": "https://registry.npmjs.org/send/-/send-0.15.4.tgz",
179 | "integrity": "sha1-mF+qPihLAnPHkzZKNcZze9k5Bbk="
180 | },
181 | "serve-static": {
182 | "version": "1.12.4",
183 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.12.4.tgz",
184 | "integrity": "sha1-m2qpjutyU8Tu3Ewfb9vKYJkBqWE="
185 | },
186 | "setprototypeof": {
187 | "version": "1.0.3",
188 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz",
189 | "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ="
190 | },
191 | "statuses": {
192 | "version": "1.3.1",
193 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
194 | "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4="
195 | },
196 | "type-is": {
197 | "version": "1.6.15",
198 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz",
199 | "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA="
200 | },
201 | "unpipe": {
202 | "version": "1.0.0",
203 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
204 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
205 | },
206 | "utils-merge": {
207 | "version": "1.0.0",
208 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz",
209 | "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg="
210 | },
211 | "vary": {
212 | "version": "1.1.1",
213 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.1.tgz",
214 | "integrity": "sha1-Z1Neu2lMHVIldFeYRmUyP1h+jTc="
215 | }
216 | }
217 | }
218 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "alt-angularjs-migration",
3 | "version": "0.0.1",
4 | "scripts": {
5 | "start": "node server.js"
6 | },
7 | "dependencies": {
8 | "express": "^4.15.4",
9 | "finalhandler": "^1.0.4",
10 | "serve-static": "^1.12.4"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const app = express();
3 | const port = process.env.PORT || 1337;
4 | app.use('/', express.static('angular-app/dist'));
5 | app.use('/legacy', express.static('angularjs-app/src'));
6 |
7 | app.listen(port, function () {
8 | console.log('Example app listening on port ' + port)
9 | });
--------------------------------------------------------------------------------