parent
8a0e5659c0
commit
be9e8b99ff
|
@ -30,6 +30,7 @@ Here are the most important tasks you might need to use:
|
||||||
* `yarn generate-plunkers` - generate the plunker files that are used by the `live-example` tags in the docs.
|
* `yarn generate-plunkers` - generate the plunker files that are used by the `live-example` tags in the docs.
|
||||||
* `yarn generate-zips` - generate the zip files from the examples. Zip available via the `live-example` tags in the docs.
|
* `yarn generate-zips` - generate the zip files from the examples. Zip available via the `live-example` tags in the docs.
|
||||||
|
|
||||||
|
* `yarn build-ie-polyfills` - generates a js file of polyfills that can be loaded in Internet Explorer.
|
||||||
|
|
||||||
## Using ServiceWorker locally
|
## Using ServiceWorker locally
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
"test": "yarn check-env && ng test",
|
"test": "yarn check-env && ng test",
|
||||||
"pree2e": "yarn ~~update-webdriver",
|
"pree2e": "yarn ~~update-webdriver",
|
||||||
"e2e": "yarn check-env && ng e2e --no-webdriver-update",
|
"e2e": "yarn check-env && ng e2e --no-webdriver-update",
|
||||||
"setup": "yarn && yarn boilerplate:add && yarn generate-plunkers && yarn generate-zips && yarn docs",
|
"setup": "yarn && yarn build-ie-polyfills && yarn boilerplate:add && yarn generate-plunkers && yarn generate-zips && yarn docs",
|
||||||
"pretest-pwa-score-local": "yarn build",
|
"pretest-pwa-score-local": "yarn build",
|
||||||
"test-pwa-score-local": "concurrently --kill-others --success first \"http-server dist -p 4200 --silent\" \"yarn test-pwa-score -- http://localhost:4200 90\"",
|
"test-pwa-score-local": "concurrently --kill-others --success first \"http-server dist -p 4200 --silent\" \"yarn test-pwa-score -- http://localhost:4200 90\"",
|
||||||
"test-pwa-score": "node scripts/test-pwa-score",
|
"test-pwa-score": "node scripts/test-pwa-score",
|
||||||
|
@ -34,7 +34,8 @@
|
||||||
"generate-zips": "node ./tools/example-zipper/generateZips",
|
"generate-zips": "node ./tools/example-zipper/generateZips",
|
||||||
"sw-manifest": "ngu-sw-manifest --dist dist --in ngsw-manifest.json --out dist/ngsw-manifest.json",
|
"sw-manifest": "ngu-sw-manifest --dist dist --in ngsw-manifest.json --out dist/ngsw-manifest.json",
|
||||||
"sw-copy": "cp node_modules/@angular/service-worker/bundles/worker-basic.min.js dist/",
|
"sw-copy": "cp node_modules/@angular/service-worker/bundles/worker-basic.min.js dist/",
|
||||||
"postinstall": "PATCH_LOCK=node_modules/@angular/cli/models/webpack-configs/.patched; if [ ! -e $PATCH_LOCK ]; then touch $PATCH_LOCK; patch -p0 -i tools/cli-patches/ngo-loader.patch && patch -p0 -i node_modules/purify/angular-cli.patch; fi"
|
"postinstall": "PATCH_LOCK=node_modules/@angular/cli/models/webpack-configs/.patched; if [ ! -e $PATCH_LOCK ]; then touch $PATCH_LOCK; patch -p0 -i tools/cli-patches/ngo-loader.patch && patch -p0 -i node_modules/purify/angular-cli.patch; fi",
|
||||||
|
"build-ie-polyfills": "webpack -p src/ie-polyfills.js src/generated/ie-polyfills.min.js"
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -50,12 +51,14 @@
|
||||||
"@angular/platform-server": "next",
|
"@angular/platform-server": "next",
|
||||||
"@angular/router": "next",
|
"@angular/router": "next",
|
||||||
"@angular/service-worker": "^1.0.0-beta.12",
|
"@angular/service-worker": "^1.0.0-beta.12",
|
||||||
|
"classlist.js": "^1.1.20150312",
|
||||||
"core-js": "^2.4.1",
|
"core-js": "^2.4.1",
|
||||||
"ng-pwa-tools": "^0.0.10",
|
"ng-pwa-tools": "^0.0.10",
|
||||||
"ngo-loader": "alxhub/ngo",
|
"ngo-loader": "alxhub/ngo",
|
||||||
"purify": "igorminar/purify",
|
"purify": "igorminar/purify",
|
||||||
"rxjs": "^5.2.0",
|
"rxjs": "^5.2.0",
|
||||||
"tslib": "^1.7.0",
|
"tslib": "^1.7.0",
|
||||||
|
"web-animations-js": "^2.2.5",
|
||||||
"zone.js": "^0.8.4"
|
"zone.js": "^0.8.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -108,6 +111,7 @@
|
||||||
"unist-util-visit": "^1.1.1",
|
"unist-util-visit": "^1.1.1",
|
||||||
"vrsource-tslint-rules": "^4.0.1",
|
"vrsource-tslint-rules": "^4.0.1",
|
||||||
"watchr": "^3.0.1",
|
"watchr": "^3.0.1",
|
||||||
|
"webpack": "^2.5.1",
|
||||||
"yargs": "^7.0.2"
|
"yargs": "^7.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
159
aio/src/NOTES.md
159
aio/src/NOTES.md
|
@ -1,159 +0,0 @@
|
||||||
# Design Notes
|
|
||||||
|
|
||||||
## Application State
|
|
||||||
|
|
||||||
Apart from loading up the navigation and search data, there is only one significant state in the app, which is the document being viewed.
|
|
||||||
Other state, such as highlighting the current navigation items and bread crumbs can be derived from that state.
|
|
||||||
The simplest indication of this state is the current `Location#path`, which acts as the single point of truth in the application.
|
|
||||||
|
|
||||||
* The document to display is computed from the `path`.
|
|
||||||
* Navigation to display different documents is achieved by updating the `path`.
|
|
||||||
* Whether a navigation item should be highlighted as active is computed from the `path`
|
|
||||||
|
|
||||||
Navigation between documents can be achieved through changes to the `Location`.
|
|
||||||
|
|
||||||
## Concepts
|
|
||||||
|
|
||||||
There are three main concepts in the application: documents, navigation and search.
|
|
||||||
|
|
||||||
* The document data includes the contents of the document for rendering.
|
|
||||||
* The search data includes keywords used for building the search index.
|
|
||||||
* The navigation data contains information about the visual trees that can be rendered in the app to navigate to the documents.
|
|
||||||
|
|
||||||
### Documents
|
|
||||||
|
|
||||||
Information about documents to be displayed are provided as data that can be fetched from the server.
|
|
||||||
There are two parts to the data for each document: `DocumentContents`.
|
|
||||||
|
|
||||||
* `DocumentContents` contains the actual document that will be rendered. This can be loaded (and then cached) lazily only when the document is to be viewed.
|
|
||||||
|
|
||||||
Each document is uniquely identified by the `path` that is also used to fetch its `DocumentContents`.
|
|
||||||
The `DocumentContents` are stored in JSON files on the server. They are loaded lazily on demand and then cached.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
interface DocumentContents {
|
|
||||||
title: string;
|
|
||||||
contents: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
type DocumentContentsJSONFile = Array<DocumentContents>;
|
|
||||||
```
|
|
||||||
|
|
||||||
### Navigation
|
|
||||||
|
|
||||||
Within an application there can be multiple navigational views for displaying links to documents.
|
|
||||||
For example, there might be views for the top level `Toolbar` and for the more detailed `SideBar` navigation.
|
|
||||||
|
|
||||||
Each view is represented as a tree of `NavigationNode`s. Each `NavigationNode` may, optionally, have a `url`, a `path` and `children`.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
interface NavigationNode {
|
|
||||||
title: string;
|
|
||||||
url?: string;
|
|
||||||
path?: string;
|
|
||||||
tooltip?: string;
|
|
||||||
target?: string;
|
|
||||||
children?: NavigationNode[];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The `url` property represents a link to an external url outside of the app.
|
|
||||||
The `path` property identifies the document to display for this navigation `url`. It is used both as the URL segment in the browser and in the request to fetch the document contents.
|
|
||||||
It is not valid to have both `url` and `path` properties on a single node.
|
|
||||||
If neither `url` nor `path` properties are then the node is a pure container, in which case it ought to have
|
|
||||||
|
|
||||||
The `NavigationNode` data is stored in a JSON file that is fetched from the server at startup
|
|
||||||
|
|
||||||
```ts
|
|
||||||
interface NavigationViews {
|
|
||||||
[name: string]: NavigationNode;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The mapping of a URL back to `NavigationNode` is computed by inverting all the `NavigationNode` structures to produce a `NavigationMap` of URL to node.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
interface NavigationMap {
|
|
||||||
[url: string]: NavigationMapItem
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Each `NavigationMapItem` contains information for updating the current navigation views and also caches the `DocumentContents` once it has been loaded.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
interface NavigationMapItem {
|
|
||||||
node: NavigationNode;
|
|
||||||
parents: NavigationNode[];
|
|
||||||
document?: DocumentContents;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Search
|
|
||||||
|
|
||||||
The `SearchTerms` are stored in a single JSON file that is loaded by the search WebWorker at startup and used to generate the search index.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
interface SearchTerms {
|
|
||||||
url: string;
|
|
||||||
title: string;
|
|
||||||
body: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
type SearchTermsJSONFile = Array<SearchTerms>;
|
|
||||||
```
|
|
||||||
|
|
||||||
## LocationService
|
|
||||||
|
|
||||||
Since the core Angular `Location` service does not expose a subject, nor emits events when the location is changed programmatically,
|
|
||||||
we have our own `LocationService` that does this for us.
|
|
||||||
|
|
||||||
```
|
|
||||||
export class LocationService {
|
|
||||||
currentUrl: Observable<string>;
|
|
||||||
go(url: string): void
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You can subscribe to the `currentUrl` to be updated when location changes occur.
|
|
||||||
You should navigate to new documents by calling `go`.
|
|
||||||
|
|
||||||
## DocumentService
|
|
||||||
|
|
||||||
The `DocumentService` is responsible for monitoring the `LocationService.currentUrl` and updating the `currentDocument`.
|
|
||||||
When the `currentUrl` changes, the `DocumentService` will fetch the `DocumentContents` from the server if necessary and cache it for the future.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
export class DocumentService {
|
|
||||||
currentDocument: Observable<DocumentContents>;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The mapping of URL path to the path to fetch the document contents is simply:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
private computePath(url) {
|
|
||||||
url = url.startsWith('/') ? url : '/' + url;
|
|
||||||
return 'generated/docs' + url + '.json';
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## NavigationService
|
|
||||||
|
|
||||||
The `NavigationService` is responsible for:
|
|
||||||
|
|
||||||
* fetching and exposing the `NavigationViews` for use in displaying navigation UI.
|
|
||||||
* building the `NavigationMap` from the `NavigationNode` data.
|
|
||||||
* updating observables for the currently active `NavigationNode`s that can be used to render the navigation UI
|
|
||||||
when the `LocationService.currentUrl` changes.
|
|
||||||
|
|
||||||
|
|
||||||
```ts
|
|
||||||
class NavigationService {
|
|
||||||
navigationViews: Observable<NavigationViews>;
|
|
||||||
currentNode: Observable<NavigationNode>;
|
|
||||||
activeNodes: Observable<NavigationNode[]>;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
|
||||||
|
import 'core-js/es6/symbol';
|
||||||
|
import 'core-js/es6/object';
|
||||||
|
import 'core-js/es6/function';
|
||||||
|
import 'core-js/es6/parse-int';
|
||||||
|
import 'core-js/es6/parse-float';
|
||||||
|
import 'core-js/es6/number';
|
||||||
|
import 'core-js/es6/math';
|
||||||
|
import 'core-js/es6/string';
|
||||||
|
import 'core-js/es6/date';
|
||||||
|
import 'core-js/es6/array';
|
||||||
|
import 'core-js/es6/regexp';
|
||||||
|
import 'core-js/es6/map';
|
||||||
|
import 'core-js/es6/set';
|
||||||
|
|
||||||
|
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
|
||||||
|
import 'classlist.js';
|
||||||
|
|
||||||
|
/** IE10 and IE11 requires the following to support `@angular/animation`. */
|
||||||
|
import 'web-animations-js';
|
|
@ -23,7 +23,7 @@
|
||||||
<!-- NOTE: These need to be kept in sync with `ngsw-manifest.json`. -->
|
<!-- NOTE: These need to be kept in sync with `ngsw-manifest.json`. -->
|
||||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||||
<link href="https://fonts.googleapis.com/css?family=Droid+Sans+Mono" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css?family=Droid+Sans+Mono" rel="stylesheet">
|
||||||
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"rel="stylesheet">
|
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
|
||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
<link rel="manifest" href="pwa-manifest.json">
|
<link rel="manifest" href="pwa-manifest.json">
|
||||||
|
@ -35,8 +35,17 @@
|
||||||
</script>
|
</script>
|
||||||
<script async src='https://www.google-analytics.com/analytics.js'></script>
|
<script async src='https://www.google-analytics.com/analytics.js'></script>
|
||||||
<!-- End Google Analytics -->
|
<!-- End Google Analytics -->
|
||||||
|
|
||||||
|
<script>
|
||||||
|
if (window.document.documentMode) {
|
||||||
|
var script = document.createElement('script');
|
||||||
|
script.src = 'generated/ie-polyfills.min.js';
|
||||||
|
document.head.appendChild(script);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<aio-shell></aio-shell>
|
<aio-shell></aio-shell>
|
||||||
|
|
||||||
<noscript>
|
<noscript>
|
||||||
|
|
|
@ -18,27 +18,14 @@
|
||||||
* BROWSER POLYFILLS
|
* BROWSER POLYFILLS
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
|
/**
|
||||||
// import 'core-js/es6/symbol';
|
* INTERNET EXPLORER
|
||||||
// import 'core-js/es6/object';
|
*
|
||||||
// import 'core-js/es6/function';
|
* All the Internet Explorer polyfills are defined separately, in the `ie-polyfills.js` file.
|
||||||
// import 'core-js/es6/parse-int';
|
* They are also built separately from the main app, via the `yarn build-ie-polyfills` task.
|
||||||
// import 'core-js/es6/parse-float';
|
* The output of this build is conditionally loaded (only if we are running IE) in the browser,
|
||||||
// import 'core-js/es6/number';
|
* and executed before the rest of the application files are executed.
|
||||||
// import 'core-js/es6/math';
|
*/
|
||||||
// import 'core-js/es6/string';
|
|
||||||
// import 'core-js/es6/date';
|
|
||||||
// import 'core-js/es6/array';
|
|
||||||
// import 'core-js/es6/regexp';
|
|
||||||
// import 'core-js/es6/map';
|
|
||||||
// import 'core-js/es6/set';
|
|
||||||
|
|
||||||
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
|
|
||||||
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
|
||||||
|
|
||||||
/** IE10 and IE11 requires the following to support `@angular/animation`. */
|
|
||||||
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
|
||||||
|
|
||||||
|
|
||||||
/** HACK: force import of environment.ts/environment.prod.ts to load env specific polyfills */
|
/** HACK: force import of environment.ts/environment.prod.ts to load env specific polyfills */
|
||||||
import './environments/environment';
|
import './environments/environment';
|
||||||
|
|
|
@ -1085,6 +1085,10 @@ clap@^1.0.9:
|
||||||
dependencies:
|
dependencies:
|
||||||
chalk "^1.1.3"
|
chalk "^1.1.3"
|
||||||
|
|
||||||
|
classlist.js@^1.1.20150312:
|
||||||
|
version "1.1.20150312"
|
||||||
|
resolved "https://registry.yarnpkg.com/classlist.js/-/classlist.js-1.1.20150312.tgz#1d70842f7022f08d9ac086ce69e5b250f2c57789"
|
||||||
|
|
||||||
clean-css@4.0.x:
|
clean-css@4.0.x:
|
||||||
version "4.0.13"
|
version "4.0.13"
|
||||||
resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.0.13.tgz#feb2a176062d72a6c3e624d9213cac6a0c485e80"
|
resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.0.13.tgz#feb2a176062d72a6c3e624d9213cac6a0c485e80"
|
||||||
|
@ -7147,11 +7151,11 @@ typescript@2.1:
|
||||||
version "2.1.6"
|
version "2.1.6"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.1.6.tgz#40c7e6e9e5da7961b7718b55505f9cac9487a607"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.1.6.tgz#40c7e6e9e5da7961b7718b55505f9cac9487a607"
|
||||||
|
|
||||||
typescript@2.2.0:
|
typescript@2.2.0, "typescript@>=2.0.0 <2.4.0":
|
||||||
version "2.2.0"
|
version "2.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.2.0.tgz#626f2fc70087d2480f21ebb12c1888288c8614e3"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.2.0.tgz#626f2fc70087d2480f21ebb12c1888288c8614e3"
|
||||||
|
|
||||||
"typescript@>=2.0.0 <2.4.0", typescript@^2.2.1:
|
typescript@^2.2.1:
|
||||||
version "2.3.2"
|
version "2.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.3.2.tgz#f0f045e196f69a72f06b25fd3bd39d01c3ce9984"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.3.2.tgz#f0f045e196f69a72f06b25fd3bd39d01c3ce9984"
|
||||||
|
|
||||||
|
@ -7554,6 +7558,10 @@ wbuf@^1.1.0, wbuf@^1.4.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
minimalistic-assert "^1.0.0"
|
minimalistic-assert "^1.0.0"
|
||||||
|
|
||||||
|
web-animations-js@^2.2.5:
|
||||||
|
version "2.2.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/web-animations-js/-/web-animations-js-2.2.5.tgz#26ca1b34c1347332a0813f8b2bfe69664efa80aa"
|
||||||
|
|
||||||
webdriver-js-extender@^1.0.0:
|
webdriver-js-extender@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/webdriver-js-extender/-/webdriver-js-extender-1.0.0.tgz#81c533a9e33d5bfb597b4e63e2cdb25b54777515"
|
resolved "https://registry.yarnpkg.com/webdriver-js-extender/-/webdriver-js-extender-1.0.0.tgz#81c533a9e33d5bfb597b4e63e2cdb25b54777515"
|
||||||
|
@ -7636,6 +7644,32 @@ webpack-sources@^0.2.3:
|
||||||
source-list-map "^1.1.1"
|
source-list-map "^1.1.1"
|
||||||
source-map "~0.5.3"
|
source-map "~0.5.3"
|
||||||
|
|
||||||
|
webpack@^2.5.1:
|
||||||
|
version "2.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.5.1.tgz#61742f0cf8af555b87460a9cd8bba2f1e3ee2fce"
|
||||||
|
dependencies:
|
||||||
|
acorn "^5.0.0"
|
||||||
|
acorn-dynamic-import "^2.0.0"
|
||||||
|
ajv "^4.7.0"
|
||||||
|
ajv-keywords "^1.1.1"
|
||||||
|
async "^2.1.2"
|
||||||
|
enhanced-resolve "^3.0.0"
|
||||||
|
interpret "^1.0.0"
|
||||||
|
json-loader "^0.5.4"
|
||||||
|
json5 "^0.5.1"
|
||||||
|
loader-runner "^2.3.0"
|
||||||
|
loader-utils "^0.2.16"
|
||||||
|
memory-fs "~0.4.1"
|
||||||
|
mkdirp "~0.5.0"
|
||||||
|
node-libs-browser "^2.0.0"
|
||||||
|
source-map "^0.5.3"
|
||||||
|
supports-color "^3.1.0"
|
||||||
|
tapable "~0.2.5"
|
||||||
|
uglify-js "^2.8.5"
|
||||||
|
watchpack "^1.3.1"
|
||||||
|
webpack-sources "^0.2.3"
|
||||||
|
yargs "^6.0.0"
|
||||||
|
|
||||||
webpack@~2.4.0:
|
webpack@~2.4.0:
|
||||||
version "2.4.1"
|
version "2.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.4.1.tgz#15a91dbe34966d8a4b99c7d656efd92a2e5a6f6a"
|
resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.4.1.tgz#15a91dbe34966d8a4b99c7d656efd92a2e5a6f6a"
|
||||||
|
|
Loading…
Reference in New Issue