From be9e8b99ff43cec99ef6f5e5d55558c5e285e627 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Mon, 15 May 2017 21:22:06 +0100 Subject: [PATCH] fix(aio): support IE via conditionally loaded polyfills Closes #16519 --- aio/README.md | 1 + aio/package.json | 8 +- aio/src/NOTES.md | 159 ---------------------------------------- aio/src/ie-polyfills.js | 20 +++++ aio/src/index.html | 11 ++- aio/src/polyfills.ts | 29 ++------ aio/yarn.lock | 38 +++++++++- 7 files changed, 81 insertions(+), 185 deletions(-) delete mode 100644 aio/src/NOTES.md create mode 100644 aio/src/ie-polyfills.js diff --git a/aio/README.md b/aio/README.md index cbf6dcfbdc..15c818c4fc 100644 --- a/aio/README.md +++ b/aio/README.md @@ -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-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 diff --git a/aio/package.json b/aio/package.json index e6f5e06425..1049cd8f20 100644 --- a/aio/package.json +++ b/aio/package.json @@ -13,7 +13,7 @@ "test": "yarn check-env && ng test", "pree2e": "yarn ~~update-webdriver", "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", "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", @@ -34,7 +34,8 @@ "generate-zips": "node ./tools/example-zipper/generateZips", "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/", - "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, "dependencies": { @@ -50,12 +51,14 @@ "@angular/platform-server": "next", "@angular/router": "next", "@angular/service-worker": "^1.0.0-beta.12", + "classlist.js": "^1.1.20150312", "core-js": "^2.4.1", "ng-pwa-tools": "^0.0.10", "ngo-loader": "alxhub/ngo", "purify": "igorminar/purify", "rxjs": "^5.2.0", "tslib": "^1.7.0", + "web-animations-js": "^2.2.5", "zone.js": "^0.8.4" }, "devDependencies": { @@ -108,6 +111,7 @@ "unist-util-visit": "^1.1.1", "vrsource-tslint-rules": "^4.0.1", "watchr": "^3.0.1", + "webpack": "^2.5.1", "yargs": "^7.0.2" } } diff --git a/aio/src/NOTES.md b/aio/src/NOTES.md deleted file mode 100644 index 8c7cff296b..0000000000 --- a/aio/src/NOTES.md +++ /dev/null @@ -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; -``` - -### 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; -``` - -## 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; - 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; -} -``` - -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; - currentNode: Observable; - activeNodes: Observable; -} -``` - diff --git a/aio/src/ie-polyfills.js b/aio/src/ie-polyfills.js new file mode 100644 index 0000000000..f97391461d --- /dev/null +++ b/aio/src/ie-polyfills.js @@ -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'; diff --git a/aio/src/index.html b/aio/src/index.html index ef6cac7af1..940d8b82c4 100644 --- a/aio/src/index.html +++ b/aio/src/index.html @@ -23,7 +23,7 @@ - + @@ -35,8 +35,17 @@ + + +