diff --git a/aio/README.md b/aio/README.md index e6065e1cb8..bf34ce250a 100644 --- a/aio/README.md +++ b/aio/README.md @@ -4,7 +4,7 @@ Everything in this folder is part of the documentation project. This includes * the web site for displaying the documentation * the dgeni configuration for converting source files to rendered files that can be viewed in the web site. -* the tooling for setting up examples for development; and generating plunkers and zip files from the examples. +* the tooling for setting up examples for development; and generating live-example and zip files from the examples. ## Developer tasks @@ -13,7 +13,7 @@ You should run all these tasks from the `angular/aio` folder. Here are the most important tasks you might need to use: * `yarn` - install all the dependencies. -* `yarn setup` - install all the dependencies, boilerplate, plunkers, zips and run dgeni on the docs. +* `yarn setup` - install all the dependencies, boilerplate, stackblitz, zips and run dgeni on the docs. * `yarn setup-local` - same as `setup`, but use the locally built Angular packages for aio and docs examples boilerplate. * `yarn build` - create a production build of the application (after installing dependencies, boilerplate, etc). @@ -32,7 +32,7 @@ Here are the most important tasks you might need to use: * `yarn boilerplate:add` - generate all the boilerplate code for the examples, so that they can be run locally. Add the option `--local` to use your local version of Angular contained in the "dist" folder. * `yarn boilerplate:remove` - remove all the boilerplate code that was added via `yarn boilerplate:add`. -* `yarn generate-plunkers` - generate the plunker files that are used by the `live-example` tags in the docs. +* `yarn generate-stackblitz` - generate the stackblitz 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 example-e2e` - run all e2e tests for examples diff --git a/aio/content/examples/.gitignore b/aio/content/examples/.gitignore index aa10a7c858..fcc840006f 100644 --- a/aio/content/examples/.gitignore +++ b/aio/content/examples/.gitignore @@ -76,8 +76,8 @@ aot-compiler/**/*.factory.d.ts # universal !universal/webpack.server.config.js -# plunkers -*plnkr.no-link.html +# stackblitz +*stackblitz.no-link.html # ngUpgrade testing !upgrade-phonecat-*/**/karma.conf.js diff --git a/aio/content/examples/ajs-quick-reference/plnkr.json b/aio/content/examples/ajs-quick-reference/stackblitz.json similarity index 88% rename from aio/content/examples/ajs-quick-reference/plnkr.json rename to aio/content/examples/ajs-quick-reference/stackblitz.json index 1ff34275f7..6b91b367d2 100644 --- a/aio/content/examples/ajs-quick-reference/plnkr.json +++ b/aio/content/examples/ajs-quick-reference/stackblitz.json @@ -1,6 +1,5 @@ { "description": "AngularJS to Angular Quick Reference", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", diff --git a/aio/content/examples/animations/plnkr.json b/aio/content/examples/animations/stackblitz.json similarity index 80% rename from aio/content/examples/animations/plnkr.json rename to aio/content/examples/animations/stackblitz.json index f047395e7f..4fface319e 100644 --- a/aio/content/examples/animations/plnkr.json +++ b/aio/content/examples/animations/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Angular Animations", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js" diff --git a/aio/content/examples/architecture/plnkr.json b/aio/content/examples/architecture/stackblitz.json similarity index 58% rename from aio/content/examples/architecture/plnkr.json rename to aio/content/examples/architecture/stackblitz.json index b2f47131df..c2d31783ea 100644 --- a/aio/content/examples/architecture/plnkr.json +++ b/aio/content/examples/architecture/stackblitz.json @@ -1,9 +1,9 @@ { "description": "Intro to Angular", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", - "!app/hero-list.component.1.*" - ] + "!**/*.[1].*" + ], + "file": "src/app/app.module.ts" } diff --git a/aio/content/examples/attribute-directives/src/app/dummy.module.1.ts b/aio/content/examples/attribute-directives/src/app/dummy.module.1.ts index 7ba41d53bb..14f0216f05 100644 --- a/aio/content/examples/attribute-directives/src/app/dummy.module.1.ts +++ b/aio/content/examples/attribute-directives/src/app/dummy.module.1.ts @@ -1,4 +1,4 @@ -// Not used. Keep away from plunker +// Not used. Keep away from stackblitz // Keeps ATLS from complaining about undeclared directives. import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; diff --git a/aio/content/examples/attribute-directives/plnkr.json b/aio/content/examples/attribute-directives/stackblitz.json similarity index 73% rename from aio/content/examples/attribute-directives/plnkr.json rename to aio/content/examples/attribute-directives/stackblitz.json index b13ed925a4..32e9661d60 100644 --- a/aio/content/examples/attribute-directives/plnkr.json +++ b/aio/content/examples/attribute-directives/stackblitz.json @@ -1,10 +1,9 @@ { "description": "Attribute Directive", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", - "!app/*.[0,1,2,3].*" + "!**/*.[1,2,3].*" ], "tags": ["attribute", "directive"] } diff --git a/aio/content/examples/component-interaction/plnkr.json b/aio/content/examples/component-interaction/stackblitz.json similarity index 87% rename from aio/content/examples/component-interaction/plnkr.json rename to aio/content/examples/component-interaction/stackblitz.json index 03bd55cd1a..421ac6f973 100644 --- a/aio/content/examples/component-interaction/plnkr.json +++ b/aio/content/examples/component-interaction/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Component Communication Cookbook samples", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js" diff --git a/aio/content/examples/component-styles/plnkr.json b/aio/content/examples/component-styles/stackblitz.json similarity index 87% rename from aio/content/examples/component-styles/plnkr.json rename to aio/content/examples/component-styles/stackblitz.json index fa496c7fa8..53c9360839 100644 --- a/aio/content/examples/component-styles/plnkr.json +++ b/aio/content/examples/component-styles/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Component Styles", - "basePath": "src/", "files": [ "!**/*.d.ts", "!**/*.js", diff --git a/aio/content/examples/dependency-injection-in-action/plnkr.json b/aio/content/examples/dependency-injection-in-action/stackblitz.json similarity index 86% rename from aio/content/examples/dependency-injection-in-action/plnkr.json rename to aio/content/examples/dependency-injection-in-action/stackblitz.json index ff0aedca01..20569051c1 100644 --- a/aio/content/examples/dependency-injection-in-action/plnkr.json +++ b/aio/content/examples/dependency-injection-in-action/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Dependency Injection", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", diff --git a/aio/content/examples/dependency-injection/plnkr.json b/aio/content/examples/dependency-injection/stackblitz.json similarity index 88% rename from aio/content/examples/dependency-injection/plnkr.json rename to aio/content/examples/dependency-injection/stackblitz.json index b52578894a..d487673f5e 100644 --- a/aio/content/examples/dependency-injection/plnkr.json +++ b/aio/content/examples/dependency-injection/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Dependency Injection", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", diff --git a/aio/content/examples/displaying-data/plnkr.json b/aio/content/examples/displaying-data/stackblitz.json similarity index 88% rename from aio/content/examples/displaying-data/plnkr.json rename to aio/content/examples/displaying-data/stackblitz.json index b4572f0fb6..9f2f816f14 100644 --- a/aio/content/examples/displaying-data/plnkr.json +++ b/aio/content/examples/displaying-data/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Displaying Data", - "basePath": "src/", "files": [ "!**/*.d.ts", "!**/*.js", diff --git a/aio/content/examples/docs-style-guide/second.plnkr.json b/aio/content/examples/docs-style-guide/second.plnkr.json deleted file mode 100644 index 2d3735e21c..0000000000 --- a/aio/content/examples/docs-style-guide/second.plnkr.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "description": "Second authors style guide plunker (non-executing)", - "basePath": "src/", - "files": [ - "index.2.html" - ], - "main": "index.2.html", - "tags": ["author", "style guide"] -} diff --git a/aio/content/examples/docs-style-guide/second.stackblitz.json b/aio/content/examples/docs-style-guide/second.stackblitz.json new file mode 100644 index 0000000000..ca2bfdaf3b --- /dev/null +++ b/aio/content/examples/docs-style-guide/second.stackblitz.json @@ -0,0 +1,8 @@ +{ + "description": "Second authors style guide stackblitz (non-executing)", + "files": [ + "src/index.2.html" + ], + "main": "src/index.2.html", + "tags": ["author", "style guide"] +} diff --git a/aio/content/examples/docs-style-guide/plnkr.json b/aio/content/examples/docs-style-guide/stackblitz.json similarity index 87% rename from aio/content/examples/docs-style-guide/plnkr.json rename to aio/content/examples/docs-style-guide/stackblitz.json index 155da3e479..f19943ee1e 100644 --- a/aio/content/examples/docs-style-guide/plnkr.json +++ b/aio/content/examples/docs-style-guide/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Authors style guide", - "basePath": "src/", "files": [ "!**/*.d.ts", "!**/*.js", diff --git a/aio/content/examples/dynamic-component-loader/plnkr.json b/aio/content/examples/dynamic-component-loader/stackblitz.json similarity index 85% rename from aio/content/examples/dynamic-component-loader/plnkr.json rename to aio/content/examples/dynamic-component-loader/stackblitz.json index c43fb15c12..2b6c153129 100644 --- a/aio/content/examples/dynamic-component-loader/plnkr.json +++ b/aio/content/examples/dynamic-component-loader/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Dynamic Component Loader", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js" diff --git a/aio/content/examples/dynamic-form/plnkr.json b/aio/content/examples/dynamic-form/stackblitz.json similarity index 85% rename from aio/content/examples/dynamic-form/plnkr.json rename to aio/content/examples/dynamic-form/stackblitz.json index 1f50b4a992..9dd6ff0236 100644 --- a/aio/content/examples/dynamic-form/plnkr.json +++ b/aio/content/examples/dynamic-form/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Dynamic Form", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", diff --git a/aio/content/examples/form-validation/plnkr.json b/aio/content/examples/form-validation/stackblitz.json similarity index 79% rename from aio/content/examples/form-validation/plnkr.json rename to aio/content/examples/form-validation/stackblitz.json index c5656d77f7..4871b07c6e 100644 --- a/aio/content/examples/form-validation/plnkr.json +++ b/aio/content/examples/form-validation/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Validation", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js" diff --git a/aio/content/examples/forms/plnkr.json b/aio/content/examples/forms/stackblitz.json similarity index 78% rename from aio/content/examples/forms/plnkr.json rename to aio/content/examples/forms/stackblitz.json index 3f0abbfc3d..9e0797f0e9 100644 --- a/aio/content/examples/forms/plnkr.json +++ b/aio/content/examples/forms/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Forms", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js" diff --git a/aio/content/examples/hierarchical-dependency-injection/plnkr.json b/aio/content/examples/hierarchical-dependency-injection/stackblitz.json similarity index 86% rename from aio/content/examples/hierarchical-dependency-injection/plnkr.json rename to aio/content/examples/hierarchical-dependency-injection/stackblitz.json index 2bddf49a33..7bb2331163 100644 --- a/aio/content/examples/hierarchical-dependency-injection/plnkr.json +++ b/aio/content/examples/hierarchical-dependency-injection/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Hierarchical Dependency Injection", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js" diff --git a/aio/content/examples/http/plnkr.json b/aio/content/examples/http/stackblitz.json similarity index 85% rename from aio/content/examples/http/plnkr.json rename to aio/content/examples/http/stackblitz.json index fe966be012..db67bfd2e9 100644 --- a/aio/content/examples/http/plnkr.json +++ b/aio/content/examples/http/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Http", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", diff --git a/aio/content/examples/lifecycle-hooks/plnkr.json b/aio/content/examples/lifecycle-hooks/stackblitz.json similarity index 92% rename from aio/content/examples/lifecycle-hooks/plnkr.json rename to aio/content/examples/lifecycle-hooks/stackblitz.json index 49290aa804..be2e1f757b 100644 --- a/aio/content/examples/lifecycle-hooks/plnkr.json +++ b/aio/content/examples/lifecycle-hooks/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Lifecycle Hooks", - "basePath": "src/", "files":["!**/*.d.ts", "!**/*.js"], "tags": ["lifecycle", "hooks", "OnInit", "OnDestroy", "OnChange", "DoCheck", diff --git a/aio/content/examples/ngcontainer/plnkr.json b/aio/content/examples/ngcontainer/stackblitz.json similarity index 87% rename from aio/content/examples/ngcontainer/plnkr.json rename to aio/content/examples/ngcontainer/stackblitz.json index a6cdc4ba1a..c4cae8f663 100644 --- a/aio/content/examples/ngcontainer/plnkr.json +++ b/aio/content/examples/ngcontainer/stackblitz.json @@ -1,6 +1,5 @@ { "description": "", - "basePath": "src/", "files": [ "!**/*.d.ts", "!**/*.js" diff --git a/aio/content/examples/ngmodule-faq/src/index.0.html b/aio/content/examples/ngmodule-faq/src/index.0.html index 2da2e67b4b..4802670310 100644 --- a/aio/content/examples/ngmodule-faq/src/index.0.html +++ b/aio/content/examples/ngmodule-faq/src/index.0.html @@ -1,13 +1,15 @@ - - - NgModule Minimal - - - - - - + + + NgModule Minimal + + + + + + + + diff --git a/aio/content/examples/ngmodule/contact.1b.stackblitz.json b/aio/content/examples/ngmodule/contact.1b.stackblitz.json new file mode 100644 index 0000000000..2946183c0d --- /dev/null +++ b/aio/content/examples/ngmodule/contact.1b.stackblitz.json @@ -0,0 +1,24 @@ +{ + "description": "Contact NgModule v.1", + "files": [ + "src/app/app.component.1b.ts", + "src/app/app.module.1b.ts", + "src/app/highlight.directive.ts", + "src/app/title.component.html", + "src/app/title.component.ts", + "src/app/user.service.ts", + + "src/app/contact/awesome.pipe.ts", + "src/app/contact/contact.component.css", + "src/app/contact/contact.component.html", + "src/app/contact/contact.component.3.ts", + "src/app/contact/contact.service.ts", + "src/app/contact/contact-highlight.directive.ts", + + "src/main.1b.ts", + "src/styles.css", + "src/index.1b.html" + ], + "main": "src/index.1b.html", + "tags": ["NgModule"] +} diff --git a/aio/content/examples/ngmodule/contact.2.stackblitz.json b/aio/content/examples/ngmodule/contact.2.stackblitz.json new file mode 100644 index 0000000000..3aaf1474a6 --- /dev/null +++ b/aio/content/examples/ngmodule/contact.2.stackblitz.json @@ -0,0 +1,26 @@ +{ + "description": "Contact NgModule v.2", + "files": [ + "src/app/app.component.2.ts", + "src/app/app.module.2.ts", + "src/app/highlight.directive.ts", + "src/app/title.component.html", + "src/app/title.component.ts", + "src/app/user.service.ts", + + "src/app/contact/contact.component.css", + "src/app/contact/contact.component.html", + "src/app/contact/contact.service.ts", + + "src/app/contact/awesome.pipe.ts", + "src/app/contact/contact.component.3.ts", + "src/app/contact/contact.module.2.ts", + "src/app/contact/contact-highlight.directive.ts", + + "src/main.2.ts", + "src/styles.css", + "src/index.2.html" + ], + "main": "src/index.2.html", + "tags": ["NgModule"] +} diff --git a/aio/content/examples/ngmodule/minimal.0.stackblitz.json b/aio/content/examples/ngmodule/minimal.0.stackblitz.json new file mode 100644 index 0000000000..c1835325d8 --- /dev/null +++ b/aio/content/examples/ngmodule/minimal.0.stackblitz.json @@ -0,0 +1,12 @@ +{ + "description": "Minimal NgModule", + "files": [ + "src/app/app.component.0.ts", + "src/app/app.module.0.ts", + "src/main.0.ts", + "src/styles.css", + "src/index.0.html" + ], + "main": "src/index.0.html", + "tags": ["NgModule"] +} diff --git a/aio/content/examples/ngmodule/pre-shared.3.stackblitz.json b/aio/content/examples/ngmodule/pre-shared.3.stackblitz.json new file mode 100644 index 0000000000..39faaf229e --- /dev/null +++ b/aio/content/examples/ngmodule/pre-shared.3.stackblitz.json @@ -0,0 +1,40 @@ +{ + "description": "NgModule v.3", + "files": [ + "src/app/app.component.3.ts", + "src/app/app.module.3.ts", + "src/app/app-routing.module.3.ts", + + "src/app/highlight.directive.ts", + "src/app/title.component.html", + "src/app/title.component.ts", + "src/app/user.service.ts", + + "src/app/contact/contact.component.css", + "src/app/contact/contact.component.html", + "src/app/contact/contact.service.ts", + + "src/app/contact/awesome.pipe.ts", + "src/app/contact/contact.component.3.ts", + "src/app/contact/contact.module.3.ts", + "src/app/contact/contact-routing.module.3.ts", + "src/app/contact/contact-highlight.directive.ts", + + "src/app/crisis/*.ts", + + "src/app/hero/hero-detail.component.ts", + "src/app/hero/hero-list.component.ts", + "src/app/hero/hero.service.ts", + + "src/app/hero/hero.component.3.ts", + "src/app/hero/hero.module.3.ts", + "src/app/hero/hero-routing.module.3.ts", + "src/app/hero/highlight.directive.ts", + + "src/main.3.ts", + "src/styles.css", + "src/index.3.html" + ], + "main": "src/index.3.html", + "tags": ["NgModule"] +} diff --git a/aio/content/examples/ngmodule/stackblitz.json b/aio/content/examples/ngmodule/stackblitz.json new file mode 100644 index 0000000000..b56eaeebf8 --- /dev/null +++ b/aio/content/examples/ngmodule/stackblitz.json @@ -0,0 +1,40 @@ +{ + "description": "NgModule Final", + "files": [ + "src/app/app.component.ts", + "src/app/app.module.ts", + "src/app/app-routing.module.ts", + + "src/app/contact/contact.component.css", + "src/app/contact/contact.component.html", + "src/app/contact/contact.service.ts", + + "src/app/contact/contact.component.ts", + "src/app/contact/contact.module.ts", + "src/app/contact/contact-routing.module.ts", + + "src/app/crisis/*.ts", + + "src/app/hero/hero-detail.component.ts", + "src/app/hero/hero-list.component.ts", + "src/app/hero/hero.service.ts", + + "src/app/hero/hero.component.ts", + "src/app/hero/hero.module.ts", + "src/app/hero/hero-routing.module.ts", + + "src/app/core/*.css", + "src/app/core/*.html", + "src/app/core/*.ts", + + "src/app/shared/*.css", + "src/app/shared/*.html", + "src/app/shared/*.ts", + + "src/main.ts", + "src/styles.css", + "src/index.html" + ], + "main": "src/index.html", + "tags": ["NgModule"] +} diff --git a/aio/content/examples/pipes/plnkr.json b/aio/content/examples/pipes/stackblitz.json similarity index 81% rename from aio/content/examples/pipes/plnkr.json rename to aio/content/examples/pipes/stackblitz.json index 3c07266109..a27408cfec 100644 --- a/aio/content/examples/pipes/plnkr.json +++ b/aio/content/examples/pipes/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Pipes", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js"], diff --git a/aio/content/examples/reactive-forms/final.stackblitz.json b/aio/content/examples/reactive-forms/final.stackblitz.json new file mode 100644 index 0000000000..1f8d069787 --- /dev/null +++ b/aio/content/examples/reactive-forms/final.stackblitz.json @@ -0,0 +1,20 @@ +{ + "description": "Angular Reactive Forms (final)", + "files":[ + "src/styles.css", + + "src/app/app.component.ts", + "src/app/app.module.ts", + "src/app/data-model.ts", + "src/app/hero.service.ts", + "src/app/hero-detail.component.html", + "src/app/hero-detail.component.ts", + "src/app/hero-list.component.html", + "src/app/hero-list.component.ts", + + "src/main-final.ts", + "src/index-final.html" + ], + "main": "src/index-final.html", + "tags": ["reactive", "forms"] +} diff --git a/aio/content/examples/reactive-forms/src/index-final.html b/aio/content/examples/reactive-forms/src/index-final.html index 7121ad3455..13416ffe40 100644 --- a/aio/content/examples/reactive-forms/src/index-final.html +++ b/aio/content/examples/reactive-forms/src/index-final.html @@ -1,15 +1,17 @@ - - Hero Form - - - - - - - + + Hero Form + + + + + + + + + diff --git a/aio/content/examples/reactive-forms/plnkr.json b/aio/content/examples/reactive-forms/stackblitz.json similarity index 50% rename from aio/content/examples/reactive-forms/plnkr.json rename to aio/content/examples/reactive-forms/stackblitz.json index f0daeb4aad..2b325c037b 100644 --- a/aio/content/examples/reactive-forms/plnkr.json +++ b/aio/content/examples/reactive-forms/stackblitz.json @@ -1,15 +1,14 @@ { "description": "Angular Reactive Forms (Demo runner)", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", - "!app/app.component.1.ts", - "!app/hero-list.component.1.html", + "!src/app/app.component.1.ts", + "!src/app/hero-list.component.1.html", - "!app/main-final.ts", - "!index-final.html" + "!src/app/main-final.ts", + "!src/index-final.html" ], "tags": ["reactive", "forms"] } diff --git a/aio/content/examples/router/plnkr.json b/aio/content/examples/router/stackblitz.json similarity index 57% rename from aio/content/examples/router/plnkr.json rename to aio/content/examples/router/stackblitz.json index 23ed1a1606..c1f330ae39 100644 --- a/aio/content/examples/router/plnkr.json +++ b/aio/content/examples/router/stackblitz.json @@ -1,12 +1,11 @@ { "description": "Router", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", "!**/*.[0-9].*", - "!app/crisis-list.component.ts", - "!app/hero-list.component.ts" + "!src/app/crisis-list.component.ts", + "!src/app/hero-list.component.ts" ], "tags": ["router"] } diff --git a/aio/content/examples/security/plnkr.json b/aio/content/examples/security/stackblitz.json similarity index 83% rename from aio/content/examples/security/plnkr.json rename to aio/content/examples/security/stackblitz.json index 4c9e85ce1e..e66527cb6b 100644 --- a/aio/content/examples/security/plnkr.json +++ b/aio/content/examples/security/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Content Security", - "basePath": "src/", "files": [ "!**/*.d.ts", "!**/*.js" diff --git a/aio/content/examples/set-document-title/plnkr.json b/aio/content/examples/set-document-title/stackblitz.json similarity index 86% rename from aio/content/examples/set-document-title/plnkr.json rename to aio/content/examples/set-document-title/stackblitz.json index 020d5a1db2..fb6cf810f9 100644 --- a/aio/content/examples/set-document-title/plnkr.json +++ b/aio/content/examples/set-document-title/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Set The Document Title In Angular", - "basePath": "src/", "files": [ "!**/*.d.ts", "!**/*.js", diff --git a/aio/content/examples/structural-directives/plnkr.json b/aio/content/examples/structural-directives/stackblitz.json similarity index 81% rename from aio/content/examples/structural-directives/plnkr.json rename to aio/content/examples/structural-directives/stackblitz.json index 58a26d7b4f..ca13405583 100644 --- a/aio/content/examples/structural-directives/plnkr.json +++ b/aio/content/examples/structural-directives/stackblitz.json @@ -1,10 +1,9 @@ { "description": "Structural directives", - "basePath": "src/", "files": [ "!**/*.d.ts", "!**/*.js", - "!app/scrap.txt" + "!src/app/scrap.txt" ], "tags": [ "structural", "directives", "template", "ngIf", diff --git a/aio/content/examples/styleguide/plnkr.json b/aio/content/examples/styleguide/plnkr.json deleted file mode 100644 index bf9e9681c5..0000000000 --- a/aio/content/examples/styleguide/plnkr.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "description": "Style Guide", - "basePath": "src/", - "files":[ - "!**/*.d.ts", - "!**/*.js" - ], - "tags": ["style guide, styleguide"] -} diff --git a/aio/content/examples/template-syntax/plnkr.json b/aio/content/examples/template-syntax/stackblitz.json similarity index 83% rename from aio/content/examples/template-syntax/plnkr.json rename to aio/content/examples/template-syntax/stackblitz.json index 099616ad7c..5ba51f973b 100644 --- a/aio/content/examples/template-syntax/plnkr.json +++ b/aio/content/examples/template-syntax/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Template Syntax Collection", - "basePath": "src/", "files":["!**/*.d.ts", "!**/*.js"], "tags": ["template"] } diff --git a/aio/content/examples/testing/1st-specs.plnkr.json b/aio/content/examples/testing/1st-specs.plnkr.json deleted file mode 100644 index 9fe15ddef1..0000000000 --- a/aio/content/examples/testing/1st-specs.plnkr.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "description": "Testing - 1st.specs", - "basePath": "src/", - "files":[ - "browser-test-shim.js", - "styles.css", - - "app/1st.spec.ts", - "1st-specs.html" - ], - "main": "1st-specs.html", - "open": "app/1st.spec.ts", - "tags": ["testing"] -} diff --git a/aio/content/examples/testing/app-specs.plnkr.json b/aio/content/examples/testing/app-specs.plnkr.json deleted file mode 100644 index d97bf82c86..0000000000 --- a/aio/content/examples/testing/app-specs.plnkr.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "description": "Testing - app.specs", - "basePath": "src/", - "files":[ - "browser-test-shim.js", - "systemjs.config.extras.js", - "styles.css", - - "app/**/*.css", - "app/**/*.html", - "app/**/*.ts", - "app/**/*.spec.ts", - - "testing/*.ts", - - "!main.ts", - "!app/bag/*.*", - "!app/1st.spec.ts", - - "app-specs.html" - ], - "main": "app-specs.html", - "tags": ["testing"] -} diff --git a/aio/content/examples/testing/bag-specs.plnkr.json b/aio/content/examples/testing/bag-specs.plnkr.json deleted file mode 100644 index cd22e10c28..0000000000 --- a/aio/content/examples/testing/bag-specs.plnkr.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "description": "Testing - bag.specs", - "basePath": "src/", - "files":[ - "browser-test-shim.js", - "systemjs.config.extras.js", - "styles.css", - - "app/bag/**/*.html", - "app/bag/**/*.ts", - "app/bag/**/*.spec.ts", - - "!app/bag/bag-main.ts", - - "testing/*.ts", - - "bag-specs.html" - ], - "main": "bag-specs.html", - "tags": ["testing"] -} diff --git a/aio/content/examples/testing/bag.plnkr.json b/aio/content/examples/testing/bag.plnkr.json deleted file mode 100644 index 4bb0ac9c5b..0000000000 --- a/aio/content/examples/testing/bag.plnkr.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "description": "Running the bag", - "basePath": "src/", - "files":[ - "styles.css", - - "app/bag/bag.ts", - "app/bag/bag-external-template.html", - "app/bag/bag-main.ts", - "bag.html" - ], - "main": "bag.html", - "tags": ["testing"] -} diff --git a/aio/content/examples/testing/banner-inline-specs.plnkr.json b/aio/content/examples/testing/banner-inline-specs.plnkr.json deleted file mode 100644 index 77b8c212cf..0000000000 --- a/aio/content/examples/testing/banner-inline-specs.plnkr.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "description": "Testing - banner-inline.component.specs", - "basePath": "src/", - "files":[ - "browser-test-shim.js", - "systemjs.config.extras.js", - - "app/banner-inline.component.ts", - "app/banner-inline.component.spec.ts", - "banner-inline-specs.html" - ], - "main": "banner-inline-specs.html", - "open": "app/banner-inline.component.spec.ts", - "tags": ["testing"] -} diff --git a/aio/content/examples/testing/banner-specs.plnkr.json b/aio/content/examples/testing/banner-specs.plnkr.json deleted file mode 100644 index 6e5f20bccb..0000000000 --- a/aio/content/examples/testing/banner-specs.plnkr.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "description": "Testing - banner.component.specs", - "basePath": "src/", - "files":[ - "browser-test-shim.js", - "systemjs.config.extras.js", - - "app/banner.component.css", - "app/banner.component.html", - "app/banner.component.ts", - "app/banner.component.spec.ts", - "banner-specs.html" - ], - "main": "banner-specs.html", - "open": "app/banner.component.spec.ts", - "tags": ["testing"] -} diff --git a/aio/content/examples/testing/example-config.json b/aio/content/examples/testing/example-config.json index e69de29bb2..317e9458f3 100644 --- a/aio/content/examples/testing/example-config.json +++ b/aio/content/examples/testing/example-config.json @@ -0,0 +1,3 @@ +{ + "projectType": "testing" +} diff --git a/aio/content/examples/testing/plnkr.json b/aio/content/examples/testing/plnkr.json deleted file mode 100644 index 899867159f..0000000000 --- a/aio/content/examples/testing/plnkr.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "description": "Heroes Test App", - "basePath": "src/", - "files":[ - "styles.css", - "systemjs.config.extras.js", - - "app/**/*.css", - "app/**/*.html", - "app/**/*.ts", - - "!app/bag/*.*", - - "main.ts", - "index.html" - ], - "tags": ["testing"] -} diff --git a/aio/content/examples/testing/specs.stackblitz.json b/aio/content/examples/testing/specs.stackblitz.json new file mode 100644 index 0000000000..a133b0619f --- /dev/null +++ b/aio/content/examples/testing/specs.stackblitz.json @@ -0,0 +1,25 @@ +{ + "description": "Testing - app.specs", + "files":[ + "src/styles.css", + + "src/app/**/*.css", + "src/app/**/*.html", + "src/app/**/*.ts", + "src/app/**/*.spec.ts", + + "src/testing/*.ts", + + "!src/main.ts", + "!src/app/bag/*.*", + "!src/app/1st.spec.ts", + + "src/expected.ts", + "src/test.css", + "src/tests.sb.ts", + "src/main-specs.ts", + "src/index-specs.html" + ], + "main": "src/index-specs.html", + "tags": ["testing"] +} diff --git a/aio/content/examples/testing/src/1st-specs.html b/aio/content/examples/testing/src/1st-specs.html deleted file mode 100644 index 5876a65b9a..0000000000 --- a/aio/content/examples/testing/src/1st-specs.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - 1st Specs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/aio/content/examples/testing/src/app-specs.html b/aio/content/examples/testing/src/app-specs.html deleted file mode 100644 index 7b7292ed7c..0000000000 --- a/aio/content/examples/testing/src/app-specs.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - Sample App Specs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/aio/content/examples/testing/src/app/app.component.router.spec.ts b/aio/content/examples/testing/src/app/app.component.router.spec.ts index 226d6d1ff3..46bd1abce6 100644 --- a/aio/content/examples/testing/src/app/app.component.router.spec.ts +++ b/aio/content/examples/testing/src/app/app.component.router.spec.ts @@ -17,11 +17,11 @@ import { By } from '@angular/platform-browser'; import { DebugElement, Type } from '@angular/core'; import { Location } from '@angular/common'; -import { AppModule } from './app.module'; -import { AppComponent } from './app.component'; -import { AboutComponent } from './about.component'; -import { DashboardHeroComponent } from './dashboard/dashboard-hero.component'; -import { TwainService } from './shared/twain.service'; +import { AppModule } from './app.module'; +import { AppComponent } from './app.component'; +import { AboutComponent } from './about.component'; +import { DashboardComponent } from './dashboard/dashboard.component'; +import { TwainService } from './shared/twain.service'; let comp: AppComponent; let fixture: ComponentFixture; @@ -41,7 +41,7 @@ describe('AppComponent & RouterTestingModule', () => { it('should navigate to "Dashboard" immediately', fakeAsync(() => { createComponent(); expect(location.path()).toEqual('/dashboard', 'after initialNavigation()'); - expectElementOf(DashboardHeroComponent); + expectElementOf(DashboardComponent); })); it('should navigate to "About" on click', fakeAsync(() => { @@ -52,17 +52,12 @@ describe('AppComponent & RouterTestingModule', () => { advance(); expectPathToBe('/about'); expectElementOf(AboutComponent); - - page.expectEvents([ - [r.NavigationStart, '/about'], [r.RoutesRecognized, '/about'], - [r.NavigationEnd, '/about'] - ]); })); it('should navigate to "About" w/ browser location URL change', fakeAsync(() => { createComponent(); location.simulateHashChange('/about'); - // location.go('/about'); // also works ... except in plunker + // location.go('/about'); // also works ... except, perhaps, in Stackblitz advance(); expectPathToBe('/about'); expectElementOf(AboutComponent); diff --git a/aio/content/examples/testing/src/app/bag/bag.spec.ts b/aio/content/examples/testing/src/app/bag/bag.spec.ts index 503ae96c51..7b3a20cf95 100644 --- a/aio/content/examples/testing/src/app/bag/bag.spec.ts +++ b/aio/content/examples/testing/src/app/bag/bag.spec.ts @@ -450,7 +450,7 @@ describe('TestBed Component Overrides:', () => { tcProvider = fixture.debugElement.injector.get(FancyService); tpcProvider = fixture.debugElement.children[0].injector.get(FancyService) as FakeFancyService; - expect(testBedProvider).not.toBe(tcProvider, 'testBed/tc not same providers'); + expect(testBedProvider).not.toBe( tcProvider, 'testBed/tc not same providers'); expect(testBedProvider).not.toBe(tpcProvider, 'testBed/tpc not same providers'); expect(testBedProvider instanceof FancyService).toBe(true, 'testBedProvider is FancyService'); diff --git a/aio/content/examples/testing/src/app/bag/bag.ts b/aio/content/examples/testing/src/app/bag/bag.ts index 526b793b76..1b624786c7 100644 --- a/aio/content/examples/testing/src/app/bag/bag.ts +++ b/aio/content/examples/testing/src/app/bag/bag.ts @@ -235,7 +235,7 @@ export class MyIfComponent { providers: [FancyService] }) export class TestProvidersComponent { - constructor(private fancyService: FancyService) {} + constructor(public fancyService: FancyService) {} } @@ -245,7 +245,7 @@ export class TestProvidersComponent { viewProviders: [FancyService] }) export class TestViewProvidersComponent { - constructor(private fancyService: FancyService) {} + constructor(public fancyService: FancyService) {} } @Component({ @@ -271,14 +271,6 @@ export class ExternalTemplateComponent implements OnInit { }) export class InnerCompWithExternalTemplateComponent { } -@Component({ - selector: 'bad-template-comp', - templateUrl: './non-existent.html' -}) -export class BadTemplateUrlComponent { } - - - @Component({selector: 'needs-content', template: ''}) export class NeedsContentComponent { // children with #content local variable diff --git a/aio/content/examples/testing/src/app/hero/hero-detail.component.spec.ts b/aio/content/examples/testing/src/app/hero/hero-detail.component.spec.ts index 050fe46eec..9f66e1c841 100644 --- a/aio/content/examples/testing/src/app/hero/hero-detail.component.spec.ts +++ b/aio/content/examples/testing/src/app/hero/hero-detail.component.spec.ts @@ -123,7 +123,7 @@ function overrideSetup() { it('fixture injected service is not the component injected service', inject([HeroDetailService], (service: HeroDetailService) => { - expect(service).toEqual({}, 'service injected from fixture'); + expect(service).toEqual( {}, 'service injected from fixture'); expect(hdsSpy).toBeTruthy('service injected into component'); })); } diff --git a/aio/content/examples/testing/src/app/hero/hero-list.component.spec.ts b/aio/content/examples/testing/src/app/hero/hero-list.component.spec.ts index dbf9d37d71..b46492f443 100644 --- a/aio/content/examples/testing/src/app/hero/hero-list.component.spec.ts +++ b/aio/content/examples/testing/src/app/hero/hero-list.component.spec.ts @@ -42,7 +42,7 @@ describe('HeroListComponent', () => { it('1st hero should match 1st test hero', () => { const expectedHero = HEROES[0]; const actualHero = page.heroRows[0].textContent; - expect(actualHero).toContain(expectedHero.id, 'hero.id'); + expect(actualHero).toContain(expectedHero.id.toString(), 'hero.id'); expect(actualHero).toContain(expectedHero.name, 'hero.name'); }); @@ -118,7 +118,7 @@ class Page { /** Hero line elements */ heroRows: HTMLLIElement[]; - /** Highlighted element */ + /** Highlighted DebugElement */ highlightDe: DebugElement; /** Spy on router navigate method */ diff --git a/aio/content/examples/testing/src/app/model/index.ts b/aio/content/examples/testing/src/app/model/index.ts new file mode 100644 index 0000000000..694c333a87 --- /dev/null +++ b/aio/content/examples/testing/src/app/model/index.ts @@ -0,0 +1,3 @@ +export * from './hero'; +export * from './hero.service'; +export * from './user.service'; diff --git a/aio/content/examples/testing/src/app/model/testing/index.ts b/aio/content/examples/testing/src/app/model/testing/index.ts new file mode 100644 index 0000000000..6da76e67db --- /dev/null +++ b/aio/content/examples/testing/src/app/model/testing/index.ts @@ -0,0 +1 @@ +export * from './fake-hero.service'; diff --git a/aio/content/examples/testing/src/bag-specs.html b/aio/content/examples/testing/src/bag-specs.html deleted file mode 100644 index 89b46f7056..0000000000 --- a/aio/content/examples/testing/src/bag-specs.html +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - Specs Bag - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/aio/content/examples/testing/src/banner-inline-specs.html b/aio/content/examples/testing/src/banner-inline-specs.html deleted file mode 100644 index 2a512a5647..0000000000 --- a/aio/content/examples/testing/src/banner-inline-specs.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - Banner Component (inline template) Specs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/aio/content/examples/testing/src/banner-specs.html b/aio/content/examples/testing/src/banner-specs.html deleted file mode 100644 index d16dd977a4..0000000000 --- a/aio/content/examples/testing/src/banner-specs.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - Banner Component Specs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/aio/content/examples/testing/src/browser-test-shim.js b/aio/content/examples/testing/src/browser-test-shim.js deleted file mode 100644 index ee21831e22..0000000000 --- a/aio/content/examples/testing/src/browser-test-shim.js +++ /dev/null @@ -1,87 +0,0 @@ -// BROWSER TESTING SHIM -// Keep it in-sync with what karma-test-shim does -// #docregion -/*global jasmine, __karma__, window*/ -(function () { - -Error.stackTraceLimit = 0; // "No stacktrace"" is usually best for app testing. - -// Uncomment to get full stacktrace output. Sometimes helpful, usually not. -// Error.stackTraceLimit = Infinity; // - -jasmine.DEFAULT_TIMEOUT_INTERVAL = 3000; - -var baseURL = document.baseURI; -baseURL = baseURL + baseURL[baseURL.length-1] ? '' : '/'; - -System.config({ - baseURL: baseURL, - // Extend usual application package list with test folder - packages: { 'testing': { main: 'index.js', defaultExtension: 'js' } }, - - // Assume npm: is set in `paths` in systemjs.config - // Map the angular testing umd bundles - map: { - '@angular/core/testing': 'npm:@angular/core/bundles/core-testing.umd.js', - '@angular/common/testing': 'npm:@angular/common/bundles/common-testing.umd.js', - '@angular/compiler/testing': 'npm:@angular/compiler/bundles/compiler-testing.umd.js', - '@angular/platform-browser/testing': 'npm:@angular/platform-browser/bundles/platform-browser-testing.umd.js', - '@angular/platform-browser-dynamic/testing': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js', - '@angular/http/testing': 'npm:@angular/http/bundles/http-testing.umd.js', - '@angular/router/testing': 'npm:@angular/router/bundles/router-testing.umd.js', - '@angular/forms/testing': 'npm:@angular/forms/bundles/forms-testing.umd.js', - }, -}); - -System.import('systemjs.config.js') - .then(importSystemJsExtras) - .then(initTestBed) - .then(initTesting); - -/** Optional SystemJS configuration extras. Keep going w/o it */ -function importSystemJsExtras(){ - return System.import('systemjs.config.extras.js') - .catch(function(reason) { - console.log( - 'Note: System.import could not load "systemjs.config.extras.js" where you might have added more configuration. It is an optional file so we will continue without it.' - ); - console.log(reason); - }); -} - -function initTestBed(){ - return Promise.all([ - System.import('@angular/core/testing'), - System.import('@angular/platform-browser-dynamic/testing') - ]) - - .then(function (providers) { - var coreTesting = providers[0]; - var browserTesting = providers[1]; - - coreTesting.TestBed.initTestEnvironment( - browserTesting.BrowserDynamicTestingModule, - browserTesting.platformBrowserDynamicTesting()); - }) -} - -// Import all spec files defined in the html (__spec_files__) -// and start Jasmine testrunner -function initTesting () { - console.log('loading spec files: '+__spec_files__.join(', ')); - return Promise.all( - __spec_files__.map(function(spec) { - return System.import(spec); - }) - ) - // After all imports load, re-execute `window.onload` which - // triggers the Jasmine test-runner start or explain what went wrong - .then(success, console.error.bind(console)); - - function success () { - console.log('Spec files loaded; starting Jasmine testrunner'); - window.onload(); - } -} - -})(); diff --git a/aio/content/examples/testing/src/expected.ts b/aio/content/examples/testing/src/expected.ts new file mode 100644 index 0000000000..5339fa9725 --- /dev/null +++ b/aio/content/examples/testing/src/expected.ts @@ -0,0 +1 @@ +/* Ignore. Satisfies static analysis of router config in app.component.router.spec.ts */ diff --git a/aio/content/examples/testing/src/index-specs.html b/aio/content/examples/testing/src/index-specs.html new file mode 100644 index 0000000000..ca132f6cd0 --- /dev/null +++ b/aio/content/examples/testing/src/index-specs.html @@ -0,0 +1,4 @@ + diff --git a/aio/content/examples/testing/src/main-specs.ts b/aio/content/examples/testing/src/main-specs.ts new file mode 100644 index 0000000000..4bb1949ae9 --- /dev/null +++ b/aio/content/examples/testing/src/main-specs.ts @@ -0,0 +1,45 @@ +import './testing/global-jasmine'; +import 'jasmine-core/lib/jasmine-core/jasmine-html.js'; +import 'jasmine-core/lib/jasmine-core/boot.js'; + +declare var jasmine; + +import './polyfills'; + +import 'zone.js/dist/async-test'; +import 'zone.js/dist/fake-async-test'; +import 'zone.js/dist/long-stack-trace-zone'; +import 'zone.js/dist/proxy.js'; +import 'zone.js/dist/sync-test'; +import 'zone.js/dist/jasmine-patch'; + +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +// Spec files to include in the Stackblitz tests +import './tests.sb.ts'; + +// + +bootstrap(); + +// + +function bootstrap () { + if (window['jasmineRef']) { + location.reload(); + return; + } else { + window.onload(undefined); + window['jasmineRef'] = jasmine.getEnv(); + } + + // First, initialize the Angular testing environment. + getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() + ); +} diff --git a/aio/content/examples/testing/src/test.css b/aio/content/examples/testing/src/test.css new file mode 100644 index 0000000000..6010a5d9ba --- /dev/null +++ b/aio/content/examples/testing/src/test.css @@ -0,0 +1 @@ +@import "~jasmine-core/lib/jasmine-core/jasmine.css" diff --git a/aio/content/examples/testing/src/testing/global-jasmine.ts b/aio/content/examples/testing/src/testing/global-jasmine.ts new file mode 100644 index 0000000000..560ff97d66 --- /dev/null +++ b/aio/content/examples/testing/src/testing/global-jasmine.ts @@ -0,0 +1,3 @@ +import jasmineRequire from 'jasmine-core/lib/jasmine-core/jasmine.js'; + +window['jasmineRequire'] = jasmineRequire; diff --git a/aio/content/examples/testing/src/tests.sb.ts b/aio/content/examples/testing/src/tests.sb.ts new file mode 100644 index 0000000000..e424b91d4f --- /dev/null +++ b/aio/content/examples/testing/src/tests.sb.ts @@ -0,0 +1,18 @@ +// Import spec files individually for Stackblitz +import './app/about.component.spec.ts'; +import './app/app.component.spec.ts'; +import './app/app.component.router.spec.ts'; +import './app/banner.component.spec.ts'; +import './app/banner.component.detect-changes.spec.ts'; +import './app/banner-inline.component.spec.ts'; +import './app/dashboard/dashboard.component.spec.ts'; +import './app/dashboard/dashboard.component.no-testbed.spec.ts'; +import './app/dashboard/dashboard-hero.component.spec.ts'; +import './app/hero/hero-list.component.spec.ts'; +import './app/hero/hero-detail.component.spec.ts'; +import './app/hero/hero-detail.component.no-testbed.spec.ts'; +import './app/model/hero.spec.ts'; +import './app/model/http-hero.service.spec.ts'; +import './app/shared/title-case.pipe.spec.ts'; +import './app/shared/twain.component.spec.ts'; +import './app/welcome.component.spec.ts'; diff --git a/aio/content/examples/testing/stackblitz.json b/aio/content/examples/testing/stackblitz.json new file mode 100644 index 0000000000..d05e3dbb1a --- /dev/null +++ b/aio/content/examples/testing/stackblitz.json @@ -0,0 +1,19 @@ +{ + "description": "Heroes Test App", + "files":[ + "src/styles.css", + + "src/app/**/*.css", + "src/app/**/*.html", + "src/app/**/*.ts", + + "!src/app/bag/*.*", + + "!src/test.ts", + + "src/test.css", + "src/main.ts", + "src/index.html" + ], + "tags": ["testing"] +} diff --git a/aio/content/examples/toh-pt0/plnkr.json b/aio/content/examples/toh-pt0/stackblitz.json similarity index 87% rename from aio/content/examples/toh-pt0/plnkr.json rename to aio/content/examples/toh-pt0/stackblitz.json index 3caa575acd..c2cf48171f 100644 --- a/aio/content/examples/toh-pt0/plnkr.json +++ b/aio/content/examples/toh-pt0/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Tour of Heroes: Part 0", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", diff --git a/aio/content/examples/toh-pt1/plnkr.json b/aio/content/examples/toh-pt1/stackblitz.json similarity index 89% rename from aio/content/examples/toh-pt1/plnkr.json rename to aio/content/examples/toh-pt1/stackblitz.json index 5ac3b2d3ce..880b28fae6 100644 --- a/aio/content/examples/toh-pt1/plnkr.json +++ b/aio/content/examples/toh-pt1/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Tour of Heroes: Part 1", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", diff --git a/aio/content/examples/toh-pt2/plnkr.json b/aio/content/examples/toh-pt2/stackblitz.json similarity index 87% rename from aio/content/examples/toh-pt2/plnkr.json rename to aio/content/examples/toh-pt2/stackblitz.json index 08c7b9581a..8f3cefdaeb 100644 --- a/aio/content/examples/toh-pt2/plnkr.json +++ b/aio/content/examples/toh-pt2/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Tour of Heroes: Part 2", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", diff --git a/aio/content/examples/toh-pt3/plnkr.json b/aio/content/examples/toh-pt3/stackblitz.json similarity index 87% rename from aio/content/examples/toh-pt3/plnkr.json rename to aio/content/examples/toh-pt3/stackblitz.json index 829715877e..c4ef78dc9f 100644 --- a/aio/content/examples/toh-pt3/plnkr.json +++ b/aio/content/examples/toh-pt3/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Tour of Heroes: Part 3", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", diff --git a/aio/content/examples/toh-pt4/plnkr.json b/aio/content/examples/toh-pt4/stackblitz.json similarity index 87% rename from aio/content/examples/toh-pt4/plnkr.json rename to aio/content/examples/toh-pt4/stackblitz.json index 95987d95ce..1b3e442ac0 100644 --- a/aio/content/examples/toh-pt4/plnkr.json +++ b/aio/content/examples/toh-pt4/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Tour of Heroes: Part 4", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", diff --git a/aio/content/examples/toh-pt5/plnkr.json b/aio/content/examples/toh-pt5/stackblitz.json similarity index 88% rename from aio/content/examples/toh-pt5/plnkr.json rename to aio/content/examples/toh-pt5/stackblitz.json index df6999a611..17390ecfc6 100644 --- a/aio/content/examples/toh-pt5/plnkr.json +++ b/aio/content/examples/toh-pt5/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Tour of Heroes: Part 5", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", diff --git a/aio/content/examples/toh-pt6/plnkr.json b/aio/content/examples/toh-pt6/stackblitz.json similarity index 88% rename from aio/content/examples/toh-pt6/plnkr.json rename to aio/content/examples/toh-pt6/stackblitz.json index d355bc9ff2..777d9ad1f1 100644 --- a/aio/content/examples/toh-pt6/plnkr.json +++ b/aio/content/examples/toh-pt6/stackblitz.json @@ -1,6 +1,5 @@ { "description": "Tour of Heroes: Part 6", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", diff --git a/aio/content/examples/user-input/plnkr.json b/aio/content/examples/user-input/stackblitz.json similarity index 82% rename from aio/content/examples/user-input/plnkr.json rename to aio/content/examples/user-input/stackblitz.json index dd8f063d37..d60beb9e7e 100644 --- a/aio/content/examples/user-input/plnkr.json +++ b/aio/content/examples/user-input/stackblitz.json @@ -1,6 +1,5 @@ { "description": "User Input", - "basePath": "src/", "files": [ "!**/*.d.ts", "!**/*.js" diff --git a/aio/content/guide/component-styles.md b/aio/content/guide/component-styles.md index 9fd7d293fb..b9c473452d 100644 --- a/aio/content/guide/component-styles.md +++ b/aio/content/guide/component-styles.md @@ -9,8 +9,7 @@ with components, enabling a more modular design than regular stylesheets. This page describes how to load and apply these component styles. -You can run the in Plunker and download the code from there. - +You can run the in Stackblitz and download the code from there. ## Using component styles diff --git a/aio/content/guide/docs-style-guide.md b/aio/content/guide/docs-style-guide.md index b303f6e822..a0835749e0 100644 --- a/aio/content/guide/docs-style-guide.md +++ b/aio/content/guide/docs-style-guide.md @@ -23,7 +23,7 @@ The [aio/README.md](https://github.com/angular/angular/blob/master/aio/README.md Here are a few essential commands for guide page authors. -1. `yarn setup` — installs packages; builds docs, plunkers, and zips. +1. `yarn setup` — installs packages; builds docs, stackblitz, and zips. 1. `yarn docs-watch --watch-only` — watches for saved content changes and refreshes the browser. The (optional) `--watch-only` flag skips the initial docs rebuild. @@ -549,7 +549,7 @@ Different file types have different comment syntax so adjust accordingly. ``` The doc generation process erases these comments before displaying them in the doc viewer. -It also strips them from plunkers and sample code downloads. +It also strips them from stackblitz and sample code downloads.
@@ -711,24 +711,24 @@ app.component.2.ts You'll find many such files among the samples in the Angular documentation. -Remember to exclude these files from plunkers by listing them in the `plnkr.json` as illustrated here. +Remember to exclude these files from stackblitz by listing them in the `stackblitz.json` as illustrated here. + path="docs-style-guide/stackblitz.json" + title="stackblitz.json"> {@a live-examples} ## Live examples -By adding `` to the page you generate links that run sample code in the Plunker live coding environment and download that code to the reader's file system. +By adding `` to the page you generate links that run sample code in the Stackblitz live coding environment and download that code to the reader's file system. -Live examples (AKA "plunkers") are defined by one or more `plnkr.json` files in the root of a code sample folder. Each sample folder usually has a single unnamed definition file, the default `plnkr.json`. +Live examples (AKA "stackblitz") are defined by one or more `stackblitz.json` files in the root of a code sample folder. Each sample folder usually has a single unnamed definition file, the default `stackblitz.json`.
-You can create additional, named definition files in the form `name.plnkr.json`. See `content/examples/testing` for examples. +You can create additional, named definition files in the form `name.stackblitz.json`. See `content/examples/testing` for examples. -The schema for a `plnkr.json` hasn't been documented yet but looking at the `plnkr.json` files in the example folders should tell you most of what you need to know. +The schema for a `stackblitz.json` hasn't been documented yet but looking at the `stackblitz.json` files in the example folders should tell you most of what you need to know.
@@ -736,11 +736,11 @@ Adding `` to the page generates the two default lin -1. a link to the plunker defined by the default `plnkr.json` file located in the code sample folder with the same name as the guide page. +1. a link to the Stackblitz defined by the default `stackblitz.json` file located in the code sample folder with the same name as the guide page. 2. a link that downloads that sample. -Clicking the first link opens the code sample in a new browser tab in the "embedded plunker" style. +Clicking the first link opens the code sample in a new browser tab in the "embedded Stackblitz" style. You can change the appearance and behavior of the live example with attributes and classes. @@ -765,7 +765,7 @@ You can achieve the same effect by putting the label between the `

Live example from another guide

-To link to a plunker in a folder whose name is not the same as the current guide page, set the `name` attribute to the name of that folder. +To link to a Stackblitz in a folder whose name is not the same as the current guide page, set the `name` attribute to the name of that folder. Live Example from the Router guide @@ -773,29 +773,29 @@ To link to a plunker in a folder whose name is not the same as the current guide Live Example from the Router guide ``` -

Live Example for named plunker

+

Live Example for named Stackblitz

-To link to a plunker defined by a named `plnkr.json` file, set the `plnkr` attribute. The following example links to the plunker defined by `second.plnkr.json` in the current guide's directory. +To link to a Stackblitz defined by a named `stackblitz.json` file, set the `stackblitz` attribute. The following example links to the Stackblitz defined by `second.stackblitz.json` in the current guide's directory. - + ```html - + ```

Live Example without download

To skip the download link, add the `noDownload` attribute. -Just the plunker +Just the Stackblitz ```html -Just the plunker +Just the Stackblitz ```

Live Example with download-only

-To skip the live plunker link and only link to the download, add the `downloadOnly` attribute. +To skip the live Stackblitz link and only link to the download, add the `downloadOnly` attribute. Download only @@ -805,21 +805,21 @@ To skip the live plunker link and only link to the download, add the `downloadOn

Embedded live example

-By default, a live example link opens a plunker in a separate browser tab. -You can embed the plunker within the guide page itself by adding the `embedded` attribute. +By default, a live example link opens a Stackblitz in a separate browser tab. +You can embed the Stackblitz within the guide page itself by adding the `embedded` attribute. -For performance reasons, the plunker does not start right away. The reader sees an image instead. Clicking the image starts the sometimes-slow process of launching the embedded plunker within an iframe on the page. +For performance reasons, the Stackblitz does not start right away. The reader sees an image instead. Clicking the image starts the sometimes-slow process of launching the embedded Stackblitz within an iframe on the page. -You usually replace the default plunker image with a custom image that better represents the sample. +You usually replace the default Stackblitz image with a custom image that better represents the sample. Store that image in the `content/images` directory in a folder with a name matching the corresponding example folder. -Here's an embedded live example for this guide. It has a custom image created from a snapshot of the running app, overlayed with `content/images/plunker/unused/click-to-run.png`. +Here's an embedded live example for this guide. It has a custom image created from a snapshot of the running app, overlayed with `content/images/Stackblitz/unused/click-to-run.png`. ```html - + ``` - + {@a anchors} diff --git a/aio/content/guide/forms.md b/aio/content/guide/forms.md index 94e337c0a2..7dc58f3ca3 100644 --- a/aio/content/guide/forms.md +++ b/aio/content/guide/forms.md @@ -20,7 +20,7 @@ This page shows you how to build a simple form from scratch. Along the way you'l * Display validation errors to users and enable/disable form controls. * Share information across HTML elements using template reference variables. -You can run the in Plunker and download the code from there. +You can run the in Stackblitz and download the code from there. {@a template-driven} diff --git a/aio/content/guide/pipes.md b/aio/content/guide/pipes.md index 216d62702b..118502795b 100644 --- a/aio/content/guide/pipes.md +++ b/aio/content/guide/pipes.md @@ -16,7 +16,7 @@ In fact, you might like to apply them in your HTML templates as you do styles. Introducing Angular pipes, a way to write display-value transformations that you can declare in your HTML. -You can run the in Plunker and download the code from there. +You can run the in Stackblitz and download the code from there. ## Using pipes diff --git a/aio/content/guide/reactive-forms.md b/aio/content/guide/reactive-forms.md index 388a8921b6..65d4705c4f 100644 --- a/aio/content/guide/reactive-forms.md +++ b/aio/content/guide/reactive-forms.md @@ -6,9 +6,9 @@ This guide explains reactive forms as you follow the steps to build a "Hero Deta {@a toc} -Try the Reactive Forms live-example. +Try the Reactive Forms live-example. -You can also run the Reactive Forms Demo version +You can also run the Reactive Forms Demo version and choose one of the intermediate steps from the "demo picker" at the top. @@ -1390,7 +1390,7 @@ Clicking the revert button triggers a call to the component's `revert` method. Users now can save or revert changes. This is the final step in the demo. -Try the . +Try the . @@ -1456,4 +1456,4 @@ The key files of the final version are as follows: You can download the complete source for all steps in this guide -from the Reactive Forms Demo live example. +from the Reactive Forms Demo live example. diff --git a/aio/content/guide/router.md b/aio/content/guide/router.md index a44a541de8..e508076576 100644 --- a/aio/content/guide/router.md +++ b/aio/content/guide/router.md @@ -797,7 +797,7 @@ set the `href` value in **`index.html`** *exactly* as shown here. -A live coding environment like Plunker sets the application base address dynamically so you can't specify a fixed address. +A live coding environment like Stackblitz sets the application base address dynamically so you can't specify a fixed address. That's why the example code replaces the `` with a script that writes the `` tag on the fly. @@ -4039,7 +4039,7 @@ to see the finished route configuration. ## Wrap up and final app You've covered a lot of ground in this guide and the application is too big to reprint here. -Please visit the +Please visit the where you can download the final source code. diff --git a/aio/content/guide/security.md b/aio/content/guide/security.md index 6a2f37d33b..aa0dde3293 100644 --- a/aio/content/guide/security.md +++ b/aio/content/guide/security.md @@ -7,7 +7,7 @@ this user?_) and authorization (_What can this user do?_). For more information about the attacks and mitigations described below, see [OWASP Guide Project](https://www.owasp.org/index.php/Category:OWASP_Guide_Project). -You can run the in Plunker and download the code from there. +You can run the in Stackblitz and download the code from there. diff --git a/aio/content/guide/set-document-title.md b/aio/content/guide/set-document-title.md index da17c7aa94..3da8382760 100644 --- a/aio/content/guide/set-document-title.md +++ b/aio/content/guide/set-document-title.md @@ -7,16 +7,6 @@ This cookbook explains how to do it. See the . -
- pop out the window - pop out the window - - To see the browser title bar change in the live example, - open it again in the Plunker editor by clicking the icon in the upper right, - then pop out the preview window by clicking the blue 'X' button in the upper right corner. - -
- ## The problem with *<title>* The obvious approach is to bind a property of the component to the HTML `` like this: diff --git a/aio/content/guide/setup.md b/aio/content/guide/setup.md index f48517fa53..07dcae6af3 100644 --- a/aio/content/guide/setup.md +++ b/aio/content/guide/setup.md @@ -273,7 +273,7 @@ The following are all in `src/` [bootstraps](guide/bootstrapping) the application's main module (`AppModule`) to run in the browser. The JIT compiler is a reasonable choice during the development of most projects and - it's the only viable choice for a sample running in a _live-coding_ environment like Plunker. + it's the only viable choice for a sample running in a _live-coding_ environment like Stackblitz. You'll learn about alternative compiling and [deployment](guide/deployment) options later in the documentation. </td> @@ -326,7 +326,7 @@ use other versions of node and npm. ## Appendix: Why develop locally -<live-example title="QuickStart Seed in Plunker">Live coding</live-example> in the browser is a great way to explore Angular. +<live-example title="QuickStart Seed in Stackblitz">Live coding</live-example> in the browser is a great way to explore Angular. Links on almost every documentation page open completed samples in the browser. You can play with the sample code, share your changes with friends, and download and run the code on your own machine. @@ -338,12 +338,12 @@ The other samples are based on the QuickStart seed. As much fun as this is ... -* you can't ship your app in plunker +* you can't ship your app in Stackblitz * you aren't always online when writing code * transpiling TypeScript in the browser is slow * the type support, refactoring, and code completion only work in your local IDE -Use the <live-example title="QuickStart Seed in Plunker">live coding</live-example> environment as a _playground_, +Use the <live-example title="QuickStart Seed in Stackblitz">live coding</live-example> environment as a _playground_, a place to try the documentation samples and experiment on your own. It's the perfect place to reproduce a bug when you want to <a href="https://github.com/angular/angular/issues/new" title="File a documentation issue">file a documentation issue</a> or diff --git a/aio/content/guide/testing.md b/aio/content/guide/testing.md index 97eb5c1bbb..22a31252f6 100644 --- a/aio/content/guide/testing.md +++ b/aio/content/guide/testing.md @@ -12,13 +12,8 @@ the focus is on testing applications written with Angular. This guide presents tests of a sample application that is much like the [_Tour of Heroes_ tutorial](tutorial). The sample application and all tests in this guide are available as live examples for inspection, experiment, and download: -* <live-example plnkr="1st-specs" embedded-style>A spec to verify the test environment</live-example>. -* <live-example plnkr="banner-inline-specs" embedded-style>The first component spec with inline template</live-example>. -* <live-example plnkr="banner-specs" embedded-style>A component spec with external template</live-example>. -* <live-example name="setup" plnkr="quickstart-specs" embedded-style>The QuickStart seed's AppComponent spec</live-example>. * <live-example embedded-style>The sample application to be tested</live-example>. -* <live-example plnkr="app-specs" embedded-style>All specs that test the sample application</live-example>. -* <live-example plnkr="bag-specs" embedded-style>A grab bag of additional specs</live-example>. +* <live-example stackblitz="specs" embedded-style>All specs that test the sample application</live-example>. <hr/> @@ -352,15 +347,6 @@ Debug specs in the browser in the same way that you debug an application. </figure> - -{@a live-karma-example} - - -### Try the live example - -You can also try this test as a <live-example plnkr="1st-specs" title="First spec" embedded-style></live-example> in plunker. -All of the tests in this guide are available as [live examples](guide/testing#live-examples "Live examples of these tests"). - <hr/> @@ -554,14 +540,6 @@ It gives the tester an opportunity to inspect or change the state of the component _before Angular initiates data binding or calls lifecycle hooks_. -{@a try-example} - - -### Try the live example -Take a moment to explore this component spec as a <live-example plnkr="banner-inline-specs" title="Spec for component with inline template" embedded-style></live-example> and -lock in these fundamentals of component unit testing. - - {@a auto-detect-changes} @@ -748,21 +726,10 @@ into a `compileComponents().then(...)` callback and write only one `beforeEach`. Most developers find that hard to read. The two `beforeEach` calls are widely preferred. -{@a live-external-template-example} - -### Try the live example - -Take a moment to explore this component spec as a <live-example plnkr="banner-specs" title="Spec for component with external template" embedded-style></live-example>. - <div class="l-sub-section"> - -The [Quickstart seed](guide/setup) provides a similar test of its `AppComponent` -as you can see in _this_ <live-example name="setup" plnkr="quickstart-specs" title="QuickStart seed spec" embedded-style></live-example>. -It too calls `compileComponents` although it doesn't have to because the `AppComponent`'s template is inline. - There's no harm in it and you might call `compileComponents` anyway in case you decide later to re-factor the template into a separate file. The tests in this guide only call `compileComponents` when necessary. @@ -1664,7 +1631,8 @@ New heroes have `id=0` and a blank `name`. This test confirms that the component -Inspect and download _all_ of the guide's application test code with this <live-example plnkr="app-specs" embedded-style>live example</live-example>. +Inspect and download _all_ of the guide's application test code with this +<live-example stackblitz="specs" embedded-style>live example</live-example>. </div> diff --git a/aio/content/images/plunker/placeholder.png b/aio/content/images/plunker/placeholder.png deleted file mode 100644 index 54c3369ee2..0000000000 Binary files a/aio/content/images/plunker/placeholder.png and /dev/null differ diff --git a/aio/content/images/plunker/plunker-separate-window-button.png b/aio/content/images/plunker/plunker-separate-window-button.png deleted file mode 100644 index b1517a80c9..0000000000 Binary files a/aio/content/images/plunker/plunker-separate-window-button.png and /dev/null differ diff --git a/aio/content/images/plunker/plunker-switch-to-editor-button.png b/aio/content/images/plunker/plunker-switch-to-editor-button.png deleted file mode 100644 index 46263a4ab6..0000000000 Binary files a/aio/content/images/plunker/plunker-switch-to-editor-button.png and /dev/null differ diff --git a/aio/content/images/plunker/unused/click-to-run.png b/aio/content/images/stackblitz/unused/click-to-run.png similarity index 100% rename from aio/content/images/plunker/unused/click-to-run.png rename to aio/content/images/stackblitz/unused/click-to-run.png diff --git a/aio/content/marketing/docs.md b/aio/content/marketing/docs.md index 240f92538b..24f89329cc 100644 --- a/aio/content/marketing/docs.md +++ b/aio/content/marketing/docs.md @@ -3,7 +3,7 @@ Angular is a platform that makes it easy to build applications with the web. Angular combines declarative templates, dependency injection, end to end tooling, and integrated best practices to solve development challenges. Angular empowers developers to build applications that live on the web, mobile, or the desktop <div class="card-container"> - <a href="generated/live-examples/quickstart/eplnkr.html" target="_blank" class="docs-card" + <a href="generated/live-examples/toh-pt1/stackblitz.html" target="_blank" class="docs-card" title="Experience Angular in a live coding environment"> <section>Get a Glimpse of Angular</section> <p>A quick look at an Angular "hello world" application.</p> diff --git a/aio/ngsw-manifest.json b/aio/ngsw-manifest.json index 0c132723b9..c59ab0bdb9 100644 --- a/aio/ngsw-manifest.json +++ b/aio/ngsw-manifest.json @@ -19,7 +19,7 @@ "routing": { "index": "/index.html", "routes": { - "^(?!/docs/.|(?:/guide/(?:cli-quickstart|metadata|ngmodule|service-worker-(?:getstart|comm|configref)|learning-angular)|/news/?)$|/testing|/api/(?:common/NgModel|platform-browser/AnimationDriver|testing|api)).*/(?!e?plnkr|(?:NgFor|MaxLengthValidator)-|Control(?:Group)?|AnimationStateDeclarationMetadata|CORE_DIRECTIVES|PLATFORM_PIPES|DirectiveMetadata|HTTP_PROVIDERS)[^/.]*$": { + "^(?!/docs/.|(?:/guide/(?:cli-quickstart|metadata|ngmodule|service-worker-(?:getstart|comm|configref)|learning-angular)|/news/?)$|/testing|/api/(?:common/NgModel|platform-browser/AnimationDriver|testing|api)).*/(?!e?stackblitz|(?:NgFor|MaxLengthValidator)-|Control(?:Group)?|AnimationStateDeclarationMetadata|CORE_DIRECTIVES|PLATFORM_PIPES|DirectiveMetadata|HTTP_PROVIDERS)[^/.]*$": { "match": "regex" } } diff --git a/aio/package.json b/aio/package.json index 87ae31005a..dc21908d75 100644 --- a/aio/package.json +++ b/aio/package.json @@ -23,7 +23,7 @@ "preinstall": "node ../tools/yarn/check-yarn.js", "presetup": "yarn install --frozen-lockfile && yarn ~~check-env && yarn boilerplate:remove", "setup": "yarn aio-use-npm && yarn example-use-npm", - "postsetup": "yarn boilerplate:add && yarn build-ie-polyfills && yarn generate-plunkers && yarn generate-zips && yarn docs", + "postsetup": "yarn boilerplate:add && yarn build-ie-polyfills && yarn generate-stackblitz && yarn generate-zips && yarn docs", "presetup-local": "yarn presetup", "setup-local": "yarn aio-use-local && yarn example-use-local", "postsetup-local": "yarn postsetup", @@ -49,7 +49,7 @@ "boilerplate:add": "node ./tools/examples/example-boilerplate add", "boilerplate:remove": "node ./tools/examples/example-boilerplate remove", "boilerplate:test": "node tools/examples/test.js", - "generate-plunkers": "node ./tools/plunker-builder/generatePlunkers", + "generate-stackblitz": "node ./tools/stackblitz-builder/generateStackblitz", "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/", diff --git a/aio/scripts/_payload-limits.json b/aio/scripts/_payload-limits.json index 95c46c1a43..296081ad53 100755 --- a/aio/scripts/_payload-limits.json +++ b/aio/scripts/_payload-limits.json @@ -5,7 +5,7 @@ "inline": 1602, "main": 459119, "polyfills": 40264, - "embedded": 72537, + "embedded": 71711, "prettify": 14888 } } diff --git a/aio/src/app/embedded/embedded.module.ts b/aio/src/app/embedded/embedded.module.ts index ea13933b72..bc0a886dec 100644 --- a/aio/src/app/embedded/embedded.module.ts +++ b/aio/src/app/embedded/embedded.module.ts @@ -25,7 +25,7 @@ import { ContributorListComponent } from './contributor/contributor-list.compone import { ContributorComponent } from './contributor/contributor.component'; import { CurrentLocationComponent } from './current-location.component'; import { FileNotFoundSearchComponent } from './search/file-not-found-search.component'; -import { LiveExampleComponent, EmbeddedPlunkerComponent } from './live-example/live-example.component'; +import { LiveExampleComponent, EmbeddedStackblitzComponent } from './live-example/live-example.component'; import { ResourceListComponent } from './resource/resource-list.component'; import { ResourceService } from './resource/resource.service'; @@ -50,7 +50,7 @@ export const embeddedComponents: Type<any>[] = [ embeddedComponents, CodeComponent, ContributorComponent, - EmbeddedPlunkerComponent + EmbeddedStackblitzComponent ], providers: [ ApiService, diff --git a/aio/src/app/embedded/live-example/live-example.component.html b/aio/src/app/embedded/live-example/live-example.component.html index 4def108a78..b5da2b8c90 100644 --- a/aio/src/app/embedded/live-example/live-example.component.html +++ b/aio/src/app/embedded/live-example/live-example.component.html @@ -1,10 +1,9 @@ <span [ngSwitch]="mode"> <span *ngSwitchCase="'disabled'">{{title}} <em>(not available on this device)</em></span> <span *ngSwitchCase="'embedded'"> - <div *ngIf="showEmbedded" title="{{title}}"> - <aio-embedded-plunker [src]="plnkr"></aio-embedded-plunker> + <div title="{{title}}"> + <aio-embedded-stackblitz [src]="stackblitz"></aio-embedded-stackblitz> </div> - <img *ngIf="!showEmbedded" (click)="toggleEmbedded()" [src]="plnkrImg" alt="{{title}}"> <p *ngIf="enableDownload"> You can also <a [href]="zip" download title="Download example">download this example</a>. </p> @@ -13,7 +12,7 @@ <a [href]="zip" download title="{{title}}">{{title}}</a> </span> <span *ngSwitchDefault> - <a [href]="plnkr" target="_blank" title="{{title}}">{{title}}</a> + <a [href]="stackblitz" target="_blank" title="{{title}}">{{title}}</a> <span *ngIf="enableDownload"> / <a [href]="zip" download title="Download example">download example</a> </span> diff --git a/aio/src/app/embedded/live-example/live-example.component.spec.ts b/aio/src/app/embedded/live-example/live-example.component.spec.ts index 80bd4baff8..9879f0e69e 100644 --- a/aio/src/app/embedded/live-example/live-example.component.spec.ts +++ b/aio/src/app/embedded/live-example/live-example.component.spec.ts @@ -3,12 +3,11 @@ import { By } from '@angular/platform-browser'; import { Component, DebugElement } from '@angular/core'; import { Location } from '@angular/common'; -import { LiveExampleComponent, EmbeddedPlunkerComponent } from './live-example.component'; +import { LiveExampleComponent, EmbeddedStackblitzComponent } from './live-example.component'; const defaultTestPath = '/test'; describe('LiveExampleComponent', () => { - let hostComponent: HostComponent; let liveExampleDe: DebugElement; let liveExampleComponent: LiveExampleComponent; let fixture: ComponentFixture<HostComponent>; @@ -39,7 +38,6 @@ describe('LiveExampleComponent', () => { function testComponent(testFn: () => void) { fixture = TestBed.createComponent(HostComponent); - hostComponent = fixture.componentInstance; liveExampleDe = fixture.debugElement.children[0]; liveExampleComponent = liveExampleDe.componentInstance; @@ -57,13 +55,13 @@ describe('LiveExampleComponent', () => { //////// tests //////// beforeEach(() => { TestBed.configureTestingModule({ - declarations: [ HostComponent, LiveExampleComponent, EmbeddedPlunkerComponent ], + declarations: [ HostComponent, LiveExampleComponent, EmbeddedStackblitzComponent ], providers: [ { provide: Location, useClass: TestLocation } ] }) - // Disable the <iframe> within the EmbeddedPlunkerComponent - .overrideComponent(EmbeddedPlunkerComponent, {set: {template: 'NO IFRAME'}}); + // Disable the <iframe> within the EmbeddedStackblitzComponent + .overrideComponent(EmbeddedStackblitzComponent, {set: {template: 'NO IFRAME'}}); testPath = defaultTestPath; liveExampleContent = null; @@ -78,68 +76,68 @@ describe('LiveExampleComponent', () => { }); }); - it('should have expected plunker & download hrefs', () => { + it('should have expected stackblitz & download hrefs', () => { testPath = '/tutorial/toh-pt1'; testComponent(() => { const hrefs = getHrefs(); - expect(hrefs[0]).toContain('/toh-pt1/eplnkr.html'); + expect(hrefs[0]).toContain('/toh-pt1/stackblitz.html'); expect(hrefs[1]).toContain('/toh-pt1/toh-pt1.zip'); }); }); - it('should have expected plunker & download hrefs even when path has # frag', () => { + it('should have expected stackblitz & download hrefs even when path has # frag', () => { testPath = '/tutorial/toh-pt1#somewhere'; testComponent(() => { const hrefs = getHrefs(); - expect(hrefs[0]).toContain('/toh-pt1/eplnkr.html'); + expect(hrefs[0]).toContain('/toh-pt1/stackblitz.html'); expect(hrefs[1]).toContain('/toh-pt1/toh-pt1.zip'); }); }); - it('should have expected plunker & download hrefs even when path has ? params', () => { + it('should have expected stackblitz & download hrefs even when path has ? params', () => { testPath = '/tutorial/toh-pt1?foo=1&bar="bar"'; testComponent(() => { const hrefs = getHrefs(); - expect(hrefs[0]).toContain('/toh-pt1/eplnkr.html'); + expect(hrefs[0]).toContain('/toh-pt1/stackblitz.html'); expect(hrefs[1]).toContain('/toh-pt1/toh-pt1.zip'); }); }); - it('should have expected flat-style plunker when has `flat-style`', () => { + it('should have expected flat-style stackblitz when has `flat-style`', () => { testPath = '/tutorial/toh-pt1'; setHostTemplate('<live-example flat-style></live-example>'); testComponent(() => { - // The file should be "plnkr.html", not "eplnkr.html" - expect(getLiveExampleAnchor().href).toContain('/plnkr.html'); + // The file should be "stackblitz.html", not "stackblitz.html" + expect(getLiveExampleAnchor().href).toContain('/stackblitz.html'); }); }); - it('should have expected plunker & download hrefs when has example directory (name)', () => { + it('should have expected stackblitz & download hrefs when has example directory (name)', () => { testPath = '/guide/somewhere'; setHostTemplate('<live-example name="toh-pt1"></live-example>'); testComponent(() => { const hrefs = getHrefs(); - expect(hrefs[0]).toContain('/toh-pt1/eplnkr.html'); + expect(hrefs[0]).toContain('/toh-pt1/stackblitz.html'); expect(hrefs[1]).toContain('/toh-pt1/toh-pt1.zip'); }); }); - it('should have expected plunker & download hrefs when has `plnkr`', () => { + it('should have expected stackblitz & download hrefs when has `stackblitz`', () => { testPath = '/testing'; - setHostTemplate('<live-example plnkr="app-specs"></live-example>'); + setHostTemplate('<live-example stackblitz="app-specs"></live-example>'); testComponent(() => { const hrefs = getHrefs(); - expect(hrefs[0]).toContain('/testing/app-specs.eplnkr.html'); + expect(hrefs[0]).toContain('/testing/app-specs.stackblitz.html'); expect(hrefs[1]).toContain('/testing/app-specs.testing.zip'); }); }); - it('should have expected plunker & download hrefs when has `name` & `plnkr`', () => { + it('should have expected stackblitz & download hrefs when has `name` & `stackblitz`', () => { testPath = '/guide/somewhere'; - setHostTemplate('<live-example name="testing" plnkr="app-specs"></live-example>'); + setHostTemplate('<live-example name="testing" stackblitz="app-specs"></live-example>'); testComponent(() => { const hrefs = getHrefs(); - expect(hrefs[0]).toContain('/testing/app-specs.eplnkr.html'); + expect(hrefs[0]).toContain('/testing/app-specs.stackblitz.html'); expect(hrefs[1]).toContain('/testing/app-specs.testing.zip'); }); }); @@ -148,7 +146,7 @@ describe('LiveExampleComponent', () => { setHostTemplate('<live-example></live-example>'); testComponent(() => { const hrefs = getHrefs(); - expect(hrefs[0]).toContain(defaultTestPath + '/eplnkr.html'); + expect(hrefs[0]).toContain(defaultTestPath + '/stackblitz.html'); }); }); @@ -156,7 +154,7 @@ describe('LiveExampleComponent', () => { setHostTemplate('<live-example flat-style></live-example>'); testComponent(() => { const hrefs = getHrefs(); - expect(hrefs[0]).toContain(defaultTestPath + '/plnkr.html'); + expect(hrefs[0]).toContain(defaultTestPath + '/stackblitz.html'); }); }); @@ -164,8 +162,8 @@ describe('LiveExampleComponent', () => { setHostTemplate('<live-example noDownload></live-example>'); testComponent(() => { const hrefs = getHrefs(); - expect(hrefs.length).toBe(1, 'only the plunker live-example anchor'); - expect(hrefs[0]).toContain('plnkr.html'); + expect(hrefs.length).toBe(1, 'only the stackblitz live-example anchor'); + expect(hrefs[0]).toContain('stackblitz.html'); }); }); @@ -211,7 +209,7 @@ describe('LiveExampleComponent', () => { setHostTemplate('<live-example name="testing/ts"></live-example>'); testComponent(() => { const hrefs = getHrefs(); - expect(hrefs[0]).toContain('/testing/ts/eplnkr.html'); + expect(hrefs[0]).toContain('/testing/ts/stackblitz.html'); expect(hrefs[1]).toContain('/testing/ts/testing.zip'); }); }); @@ -224,77 +222,33 @@ describe('LiveExampleComponent', () => { return anchor && anchor.nativeElement as HTMLAnchorElement; } - function getEmbeddedPlunkerComponent() { - const compDe = liveExampleDe.query(By.directive(EmbeddedPlunkerComponent)); - return compDe && compDe.componentInstance as EmbeddedPlunkerComponent; + function getEmbeddedStackblitzComponent() { + const compDe = liveExampleDe.query(By.directive(EmbeddedStackblitzComponent)); + return compDe && compDe.componentInstance as EmbeddedStackblitzComponent; } - function getImg() { - const img = liveExampleDe.query(By.css('img')); - return img && img.nativeElement as HTMLImageElement; - } - - describe('before click', () => { - - it('should have hidden, embedded plunker', () => { - setHostTemplate('<live-example embedded></live-example>'); - testComponent(() => { - expect(liveExampleComponent.mode).toBe('embedded', 'component is embedded'); - expect(liveExampleComponent.showEmbedded).toBe(false, 'component.showEmbedded'); - expect(getEmbeddedPlunkerComponent()).toBeNull('no EmbeddedPlunkerComponent'); - }); + it('should have hidden, embedded stackblitz', () => { + setHostTemplate('<live-example embedded></live-example>'); + testComponent(() => { + expect(liveExampleComponent.mode).toBe('embedded', 'component is embedded'); + expect(getEmbeddedStackblitzComponent()).toBeTruthy('EmbeddedStackblitzComponent'); }); - - it('should have default plunker placeholder image', () => { - setHostTemplate('<live-example embedded></live-example>'); - testComponent(() => { - expect(getImg().src).toContain('plunker/placeholder.png'); - }); - }); - - it('should have specified plunker placeholder image', () => { - const expectedSrc = 'example/demo.png'; - setHostTemplate(`<live-example embedded img="${expectedSrc}"></live-example>`); - testComponent(() => { - expect(getImg().src).toContain(expectedSrc); - }); - }); - - it('should have download paragraph with expected anchor href', () => { - testPath = '/tutorial/toh-pt1'; - setHostTemplate('<live-example embedded></live-example>'); - testComponent(() => { - expect(getDownloadAnchor().href).toContain('/toh-pt1/toh-pt1.zip'); - }); - }); - - it('should not have download paragraph when has `nodownload`', () => { - testPath = '/tutorial/toh-pt1'; - setHostTemplate('<live-example embedded nodownload></live-example>'); - testComponent(() => { - expect(getDownloadAnchor()).toBeNull(); - }); - }); - }); - describe('after click', () => { - - function clickImg() { - getImg().click(); - fixture.detectChanges(); - } - - it('should show plunker in the page', () => { - setHostTemplate('<live-example embedded></live-example>'); - testComponent(() => { - clickImg(); - expect(liveExampleComponent.mode).toBe('embedded', 'component is embedded'); - expect(liveExampleComponent.showEmbedded).toBe(true, 'component.showEmbedded'); - expect(getEmbeddedPlunkerComponent()).toBeDefined('has EmbeddedPlunkerComponent'); - }); + it('should have download paragraph with expected anchor href', () => { + testPath = '/tutorial/toh-pt1'; + setHostTemplate('<live-example embedded></live-example>'); + testComponent(() => { + expect(getDownloadAnchor().href).toContain('/toh-pt1/toh-pt1.zip'); }); + }); + it('should not have download paragraph when has `nodownload`', () => { + testPath = '/tutorial/toh-pt1'; + setHostTemplate('<live-example embedded nodownload></live-example>'); + testComponent(() => { + expect(getDownloadAnchor()).toBeNull(); + }); }); }); @@ -306,7 +260,7 @@ describe('LiveExampleComponent', () => { liveExampleComponent.onResize(600); // narrow fixture.detectChanges(); const hrefs = getHrefs(); - expect(hrefs[0]).toContain(defaultTestPath + '/eplnkr.html'); + expect(hrefs[0]).toContain(defaultTestPath + '/stackblitz.html'); }); }); @@ -316,7 +270,7 @@ describe('LiveExampleComponent', () => { liveExampleComponent.onResize(600); // narrow fixture.detectChanges(); const hrefs = getHrefs(); - expect(hrefs[0]).toContain(defaultTestPath + '/eplnkr.html'); + expect(hrefs[0]).toContain(defaultTestPath + '/stackblitz.html'); }); }); }); diff --git a/aio/src/app/embedded/live-example/live-example.component.ts b/aio/src/app/embedded/live-example/live-example.component.ts index a0c3289c46..9a19663224 100644 --- a/aio/src/app/embedded/live-example/live-example.component.ts +++ b/aio/src/app/embedded/live-example/live-example.component.ts @@ -5,8 +5,6 @@ import { CONTENT_URL_PREFIX } from 'app/documents/document.service'; import { boolFromValue, getAttrs, getAttrValue } from 'app/shared/attribute-utils'; -const defaultPlnkrImg = 'plunker/placeholder.png'; -const imageBase = CONTENT_URL_PREFIX + 'images/'; const liveExampleBase = CONTENT_URL_PREFIX + 'live-examples/'; const zipBase = CONTENT_URL_PREFIX + 'zips/'; @@ -19,49 +17,38 @@ const zipBase = CONTENT_URL_PREFIX + 'zips/'; * * Usage: * <live-example -* [name="..."] // name of the example directory -* [plnkr="...""] // name of the plunker file (becomes part of zip file name as well) -* [embedded] // embed the plunker in the doc page, else display in new browser tab (default) -* [img="..."] // image to display if embedded in doc page -* [embedded-style] // show plnkr in embedded style (default and on narrow screens) -* [flat-style] // show plnkr in flat (original) style -* [noDownload] // no downloadable zip option -* [downloadOnly] // just the zip -* [title="..."]> // text for live example link and tooltip -* text // higher precedence way to specify text for live example link and tooltip +* [name="..."] // name of the example directory +* [stackblitz="...""] // name of the stackblitz file (becomes part of zip file name as well) +* [embedded] // embed the stackblitz in the doc page, else display in new browser tab (default) +* [noDownload] // no downloadable zip option +* [downloadOnly] // just the zip +* [title="..."]> // text for live example link and tooltip +* text // higher precedence way to specify text for live example link and tooltip * </live-example> * Example: * <p>Run <live-example>Try the live example</live-example></p>. -* // ~/resources/live-examples/{page}/plnkr.html +* // ~/resources/live-examples/{page}/stackblitz.json * * <p>Run <live-example name="toh-pt1">this example</live-example></p>. -* // ~/resources/live-examples/toh-pt1/plnkr.html +* // ~/resources/live-examples/toh-pt1/stackblitz.json * -* // Link to the default plunker in the toh-pt1 sample +* // Link to the default stackblitz in the toh-pt1 sample * // The title overrides default ("live example") with "Tour of Heroes - Part 1" * <p>Run <live-example name="toh-pt1" title="Tour of Heroes - Part 1"></live-example></p>. -* // ~/resources/live-examples/toh-pt1/plnkr.html +* // ~/resources/live-examples/toh-pt1/stackblitz.json * -* <p>Run <live-example plnkr="minimal"></live-example></p>. -* // ~/resources/live-examples/{page}/minimal.plnkr.html +* <p>Run <live-example stackblitz="minimal"></live-example></p>. +* // ~/resources/live-examples/{page}/minimal.stackblitz.json * -* // Embed the current page's default plunker +* // Embed the current page's default stackblitz * // Text within tag is "live example" * // No title (no tooltip) * <live-example embedded title=""></live-example> -* // ~/resources/live-examples/{page}/eplnkr.html +* // ~/resources/live-examples/{page}/stackblitz.json * -* // Links to a *new* browser tab as an embedded style plunker editor -* <live-example embedded-style>this example</live-example> -* // ~/resources/live-examples/{page}/eplnkr.html -* -* // Links to a *new* browser tab in the flat (original editor) style plunker editor -* <live-example flat-style>this example</live-example> -* // ~/resources/live-examples/{page}/plnkr.html -* -* // Displays within the document page as an embedded style plunker editor -* <live-example name="toh-pt1" embedded plnkr="minimal" img="toh>Tour of Heroes - Part 1</live-example> -* // ~/resources/live-examples/toh-pt1/minimal.eplnkr.html +* // Displays within the document page as an embedded style stackblitz editor +* <live-example name="toh-pt1" embedded stackblitz="minimal">Tour of Heroes - Part 1</live-example> +* // ~/resources/live-examples/toh-pt1/minimal.stackblitz.json */ @Component({ selector: 'live-example', @@ -78,10 +65,8 @@ export class LiveExampleComponent implements OnInit { exampleDir: string; isEmbedded = false; mode = 'disabled'; - plnkr: string; - plnkrName: string; - plnkrImg: string; - showEmbedded = false; + stackblitz: string; + stackblitzName: string; title: string; zip: string; zipName: string; @@ -98,46 +83,32 @@ export class LiveExampleComponent implements OnInit { } this.exampleDir = exampleDir.trim(); this.zipName = exampleDir.indexOf('/') === -1 ? this.exampleDir : exampleDir.split('/')[0]; - this.plnkrName = attrs.plnkr ? attrs.plnkr.trim() + '.' : ''; - this.zip = `${zipBase}${exampleDir}/${this.plnkrName}${this.zipName}.zip`; + this.stackblitzName = attrs.stackblitz ? attrs.stackblitz.trim() + '.' : ''; + this.zip = `${zipBase}${exampleDir}/${this.stackblitzName}${this.zipName}.zip`; this.enableDownload = !boolFromValue(getAttrValue(attrs, 'nodownload')); - this.plnkrImg = imageBase + (attrs.img || defaultPlnkrImg); - if (boolFromValue(getAttrValue(attrs, 'downloadonly'))) { this.mode = 'downloadOnly'; } } - calcPlnkrLink(width: number) { + calcStackblitzLink(width: number) { const attrs = this.attrs; const exampleDir = this.exampleDir; + let urlQuery = ''; - let plnkrStyle = 'eplnkr'; // embedded style by default this.mode = 'default'; // display in another browser tab by default this.isEmbedded = boolFromValue(attrs.embedded); if (this.isEmbedded) { this.mode = 'embedded'; // display embedded in the doc - } else { - // Not embedded in doc page; determine if is embedded- or flat-style in another browser tab. - // Embedded style if on tiny screen (reg. plunker no good on narrow screen) - // If wide enough, choose style based on style attributes - if (width > this.narrowWidth) { - // Make flat style with `flat-style` or `embedded-style="false`; support atty aliases - const flatStyle = getAttrValue(attrs, ['flat-style', 'flatstyle']); - const isFlatStyle = boolFromValue(flatStyle); - - const embeddedStyle = getAttrValue(attrs, ['embedded-style', 'embeddedstyle']); - const isEmbeddedStyle = boolFromValue(embeddedStyle, !isFlatStyle); - plnkrStyle = isEmbeddedStyle ? 'eplnkr' : 'plnkr'; - } + urlQuery = '?ctl=1'; } - this.plnkr = `${liveExampleBase}${exampleDir}/${this.plnkrName}${plnkrStyle}.html`; + this.stackblitz = `${liveExampleBase}${exampleDir}/${this.stackblitzName}stackblitz.html${urlQuery}`; } ngOnInit() { @@ -152,31 +123,29 @@ export class LiveExampleComponent implements OnInit { @HostListener('window:resize', ['$event.target.innerWidth']) onResize(width: number) { if (this.mode !== 'downloadOnly') { - this.calcPlnkrLink(width); + this.calcStackblitzLink(width); } } - - toggleEmbedded () { this.showEmbedded = !this.showEmbedded; } } -///// EmbeddedPlunkerComponent /// +///// EmbeddedStackblitzComponent /// /** * Hides the <iframe> so we can test LiveExampleComponent without actually triggering - * a call to plunker to load the iframe + * a call to stackblitz to load the iframe */ @Component({ - selector: 'aio-embedded-plunker', + selector: 'aio-embedded-stackblitz', template: `<iframe #iframe frameborder="0" width="100%" height="100%"></iframe>`, styles: [ 'iframe { min-height: 400px; }'] }) -export class EmbeddedPlunkerComponent implements AfterViewInit { +export class EmbeddedStackblitzComponent implements AfterViewInit { @Input() src: string; @ViewChild('iframe') iframe: ElementRef; ngAfterViewInit() { // DEVELOPMENT TESTING ONLY - // this.src = 'https://angular.io/resources/live-examples/quickstart/ts/eplnkr.html'; + // this.src = 'https://angular.io/resources/live-examples/quickstart/ts/stackblitz.json'; if (this.iframe) { // security: the `src` is always authored by the documentation team diff --git a/aio/tools/README.md b/aio/tools/README.md index 15dd370b31..fa0d40b364 100644 --- a/aio/tools/README.md +++ b/aio/tools/README.md @@ -44,14 +44,13 @@ runnable project packaged as a zip file. These zip files are generated by the ut See the [README.md](example-zipper/README.md) for more details. -## plunker-builder +## stackblitz-builder -In the AIO application, we can embed a running version of the example as a [Plunker](http://plnkr.co/). -We can also provide a link to create a runnable version of the example in the [Plunker](http://plnkr.co/edit) +In the AIO application, we can embed a running version of the example as a [Stackblitz](https://stackblitz.com/) session. +We can also provide a link to create a runnable version of the example in the [Stackblitz](https://stackblitz.com/) editor. -This folder contains three utilities: `regularPlunker.js`, `embeddedPlunker.js`, `generatePlunkers.js`. -See the [README.md](plunker-builder/README.md) for more details. +See the [README.md](stackblitz-builder/README.md) for more details. ## transforms diff --git a/aio/tools/RELEASE.md b/aio/tools/RELEASE.md index 2171bdf6d6..df8bb9831a 100644 --- a/aio/tools/RELEASE.md +++ b/aio/tools/RELEASE.md @@ -14,6 +14,11 @@ There, select all the packages that are updated on the new Angular release. **2)** Changes to the tsconfig.json? There is one to update at `/aio/tools/examples/shared/boilerplate/src/tsconfig.json` -**3)** The file `/aio/tools/examples/shared/boilerplate/src/systemjs.config.web.js` contains the configuration for plunkers. It has some hardcoded versions that could be updated. +**3)** The file `/aio/tools/examples/shared/boilerplate/src/systemjs.config.web.js` contains the configuration for plunkers. It has some hardcoded versions that could be updated. + +>N.B.: Plunkers have been replaced by Stackblitz and (almost) all examples have be replaced by CLI/WebPack-based examples that do not use SystemJS. +The upgrade examples may still rely on SystemJS. **4)** As in step 3, more hardcoded versions at `/aio/tools/plunker-builder/translator/rules/indexHtml.js` + +>Note the same caveat about migration from plunker to Stackblitz. diff --git a/aio/tools/example-zipper/README.md b/aio/tools/example-zipper/README.md index 8202383ab3..2351fe2cff 100644 --- a/aio/tools/example-zipper/README.md +++ b/aio/tools/example-zipper/README.md @@ -5,14 +5,13 @@ runnable project packaged as a zip file. These zip files are generated by the ut ## Example zipper -The `exampleZipper.js` tool is very similar to the Plunker's `builder.js`. The latter creates an HTML file -with all the examples' files and the former creates a zip file instead. They both use the `plnkr.json` file -to flag an example as something to plunker or zip. For example: +The `exampleZipper.js` tool is very similar to the Stackblitz's `builder.js`. The latter creates an HTML file +with all the examples' files and the former creates a zip file instead. They both use the `stackblitz.json` file +to flag an example as something to stackblitz or zip. For example: ```json { "description": "Tour of Heroes: Part 6", - "basePath": "src/", "files":[ "!**/*.d.ts", "!**/*.js", @@ -55,15 +54,15 @@ The tool will also give some standard names to the scripts. ## The zipper.json -As mentioned, the tool uses the `plnkr.json` as a flag and also a configuration file for the zipper. -The problem is that not all examples have a plunker but they could offer a zip instead. +As mentioned, the tool uses the `stackblitz.json` as a flag and also a configuration file for the zipper. +The problem is that not all examples have a stackblitz but they could offer a zip instead. In those cases, you can create a `zipper.json` file with the same syntax. It will be ignored by the -plunker tool. +stackblitz tool. ## Choosing the zip "type" -In both `plnkr.json` and `zipper.json` you can use two extra properties for the zipper configuration: +In both `stackblitz.json` and `zipper.json` you can use two extra properties for the zipper configuration: ``` { @@ -78,7 +77,7 @@ SystemJS. ## Executing the zip generation -`generateZips.js` will create a zip for each `plnkr.json` or `zipper.json` it finds. +`generateZips.js` will create a zip for each `stackblitz.json` or `zipper.json` it finds. Where? At `src/generated/zips/`. diff --git a/aio/tools/example-zipper/customizer/package-json/cli.json b/aio/tools/example-zipper/customizer/package-json/cli.json index 92d69b7ae9..92f1609f1a 100644 --- a/aio/tools/example-zipper/customizer/package-json/cli.json +++ b/aio/tools/example-zipper/customizer/package-json/cli.json @@ -7,9 +7,7 @@ { "name": "lint", "command": "ng lint" }, { "name": "e2e", "command": "ng e2e" } ], - "dependencies": [ - "web-animations-js" - ], + "dependencies": [], "devDependencies": [ "@angular/cli", "@types/jasminewd2", diff --git a/aio/tools/example-zipper/customizer/package-json/i18n.json b/aio/tools/example-zipper/customizer/package-json/i18n.json index 531385d2a8..deb97a37b6 100644 --- a/aio/tools/example-zipper/customizer/package-json/i18n.json +++ b/aio/tools/example-zipper/customizer/package-json/i18n.json @@ -9,9 +9,7 @@ { "name": "e2e", "command": "ng e2e --aot --i18nFile=src/locale/messages.fr.xlf --i18nFormat=xlf --locale=fr" }, { "name": "extract", "command": "ng xi18n --outputPath=src/locale" } ], - "dependencies": [ - "web-animations-js" - ], + "dependencies": [], "devDependencies": [ "@angular/cli", "@types/jasminewd2", diff --git a/aio/tools/example-zipper/customizer/package-json/testing.json b/aio/tools/example-zipper/customizer/package-json/testing.json new file mode 100644 index 0000000000..ca5fc2be05 --- /dev/null +++ b/aio/tools/example-zipper/customizer/package-json/testing.json @@ -0,0 +1,19 @@ +{ + "scripts": [ + { "name": "ng", "command": "ng" }, + { "name": "build", "command": "ng build" }, + { "name": "start", "command": "ng serve" }, + { "name": "test", "command": "ng test" }, + { "name": "lint", "command": "ng lint" }, + { "name": "e2e", "command": "ng e2e" } + ], + "dependencies": [ + "web-animations-js" + ], + "devDependencies": [ + "@angular/cli", + "@types/jasminewd2", + "karma-coverage-istanbul-reporter", + "ts-node" + ] +} diff --git a/aio/tools/example-zipper/customizer/package-json/universal.json b/aio/tools/example-zipper/customizer/package-json/universal.json index 06d609e421..cfc12263ae 100644 --- a/aio/tools/example-zipper/customizer/package-json/universal.json +++ b/aio/tools/example-zipper/customizer/package-json/universal.json @@ -11,7 +11,6 @@ { "name": "webpack:server", "command": "webpack --config webpack.server.config.js --progress --colors" } ], "dependencies": [ - "web-animations-js", "@nguniversal/express-engine", "@nguniversal/module-map-ngfactory-loader", "ts-loader" diff --git a/aio/tools/example-zipper/exampleZipper.js b/aio/tools/example-zipper/exampleZipper.js index 26af7dfd08..5660f1c37b 100644 --- a/aio/tools/example-zipper/exampleZipper.js +++ b/aio/tools/example-zipper/exampleZipper.js @@ -19,9 +19,9 @@ class ExampleZipper { this.exampleTsconfig = path.join(__dirname, '../examples/shared/boilerplate/systemjs/src/tsconfig.json'); this.customizer = new PackageJsonCustomizer(); - let gpathPlnkr = path.join(sourceDirName, '**/*plnkr.json'); + let gpathStackblitz = path.join(sourceDirName, '**/*stackblitz.json'); let gpathZipper = path.join(sourceDirName, '**/zipper.json'); - let configFileNames = globby.sync([gpathPlnkr, gpathZipper], { ignore: ['**/node_modules/**'] }); + let configFileNames = globby.sync([gpathStackblitz, gpathZipper], { ignore: ['**/node_modules/**'] }); configFileNames.forEach((configFileName) => { this._zipExample(configFileName, sourceDirName, outputDirName); }); @@ -77,7 +77,7 @@ class ExampleZipper { if (relativeDirName.indexOf('/') !== -1) { // Special example exampleZipName = relativeDirName.split('/').join('-'); } else { - exampleZipName = jsonFileName.replace(/(plnkr|zipper).json/, relativeDirName); + exampleZipName = jsonFileName.replace(/(stackblitz|zipper).json/, relativeDirName); } const exampleDirName = path.dirname(configFileName); @@ -103,7 +103,7 @@ class ExampleZipper { ]; var alwaysExcludes = [ '!**/bs-config.e2e.json', - '!**/*plnkr.*', + '!**/*stackblitz.*', '!**/*zipper.*', '!**/systemjs.config.js', '!**/npm-debug.log', diff --git a/aio/tools/examples/README.md b/aio/tools/examples/README.md index c85aedc573..2328c72863 100644 --- a/aio/tools/examples/README.md +++ b/aio/tools/examples/README.md @@ -28,15 +28,15 @@ in any Angular application using System.js. This is the boilerplate that will be Among these files, there are a few special ones: * **src/systemjs.config.js** - This is the configuration of System.js used to run the example locally. -* **src/systemjs.config.web.js** - This configuration replaces the previous one on Plunkers. +* **src/systemjs.config.web.js** - This configuration replaces the previous one on Stackblitz. * **src/systemjs.config.web.build.js** - Same as the previous one but for using angular's `-builds` versions. * **src/systemjs-angular-loader.js** - It is a System.js plugin that removes the need of `moduleId`. * **package.json** - This package.json only contains scripts, no dependencies. It contains the different tasks needed to run any example. Doesn't matter if CLI, System.js or Webpack. -* **plnkr.json** - This file is used by the Plunker tool to generate a plunker for an example. This +* **stackblitz.json** - This file is used by the Stackblitz tool to generate a stackblitz for an example. This concrete file is just a placeholder. Authors needs to tweak it for each guide. More at the - [plunker docs](../plunker-builder/README.md). + [stackblitz docs](../stackblitz-builder/README.md). * **example-config.json** - This file serves as a flag to indicate that the current folder is an example. This concrete file is just a placeholder. More on this later in this readme. @@ -88,7 +88,7 @@ as shown earlier. This script installs all the dependencies that are shared among all the examples, creates the `node_modules` symlinks and copy all the boilerplate files where needed. It won't do anything -about plunkers nor e2e tests. +about stackblitz nor e2e tests. It also contains a function to remove all the boilerplate. It uses a `git clean -xdf` to do the job. It will remove all files that don't exist in the git repository, **including any diff --git a/aio/tools/examples/example-boilerplate.js b/aio/tools/examples/example-boilerplate.js index 4a86512116..af3135529c 100644 --- a/aio/tools/examples/example-boilerplate.js +++ b/aio/tools/examples/example-boilerplate.js @@ -60,6 +60,11 @@ BOILERPLATE_PATHS.universal = [ 'package.json' ]; +BOILERPLATE_PATHS.testing = [ + ...cliRelativePath, + '.angular-cli.json' +]; + const EXAMPLE_CONFIG_FILENAME = 'example-config.json'; class ExampleBoilerPlate { diff --git a/aio/tools/examples/shared/boilerplate/cli/package.json b/aio/tools/examples/shared/boilerplate/cli/package.json index 41bbb4a01f..cf519b8216 100644 --- a/aio/tools/examples/shared/boilerplate/cli/package.json +++ b/aio/tools/examples/shared/boilerplate/cli/package.json @@ -21,6 +21,7 @@ "@angular/platform-browser": "^5.0.0", "@angular/platform-browser-dynamic": "^5.0.0", "@angular/router": "^5.0.0", + "angular-in-memory-web-api": "~0.5.0", "core-js": "^2.4.1", "rxjs": "^5.5.2", "zone.js": "^0.8.14" diff --git a/aio/tools/examples/shared/boilerplate/cli/src/polyfills.ts b/aio/tools/examples/shared/boilerplate/cli/src/polyfills.ts index 99b3322129..ccf3ac1fba 100644 --- a/aio/tools/examples/shared/boilerplate/cli/src/polyfills.ts +++ b/aio/tools/examples/shared/boilerplate/cli/src/polyfills.ts @@ -50,7 +50,7 @@ import 'core-js/es7/reflect'; * Required to support Web Animations `@angular/platform-browser/animations`. * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation **/ -import 'web-animations-js'; +// import 'web-animations-js'; diff --git a/aio/tools/examples/shared/boilerplate/testing/.angular-cli.json b/aio/tools/examples/shared/boilerplate/testing/.angular-cli.json new file mode 100644 index 0000000000..8e9fd66a57 --- /dev/null +++ b/aio/tools/examples/shared/boilerplate/testing/.angular-cli.json @@ -0,0 +1,61 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "project": { + "name": "angular.io-example" + }, + "apps": [ + { + "root": "src", + "outDir": "dist", + "assets": [ + "assets", + "favicon.ico" + ], + "index": "index.html", + "main": "main.ts", + "polyfills": "polyfills.ts", + "test": "test.ts", + "tsconfig": "tsconfig.app.json", + "testTsconfig": "tsconfig.spec.json", + "prefix": "app", + "styles": [ + "test.css", + "styles.css" + ], + "scripts": [], + "environmentSource": "environments/environment.ts", + "environments": { + "dev": "environments/environment.ts", + "prod": "environments/environment.prod.ts" + } + } + ], + "e2e": { + "protractor": { + "config": "./protractor.conf.js" + } + }, + "lint": [ + { + "project": "src/tsconfig.app.json", + "exclude": "**/node_modules/**" + }, + { + "project": "src/tsconfig.spec.json", + "exclude": "**/node_modules/**" + }, + { + "project": "e2e/tsconfig.e2e.json", + "exclude": "**/node_modules/**" + } + ], + "test": { + "karma": { + "config": "./karma.conf.js" + } + }, + "defaults": { + "styleExt": "css", + "component": {} + } +} diff --git a/aio/tools/plunker-builder/README.md b/aio/tools/plunker-builder/README.md deleted file mode 100644 index 9a7088ce89..0000000000 --- a/aio/tools/plunker-builder/README.md +++ /dev/null @@ -1,78 +0,0 @@ -# Overview - -[Plunker](http://plnkr.co) is an online tool for creating, collaborating and sharing ideas. In AIO -we use it to share one or more runnable versions of our examples. - -Plunker comes in two flavours. The [classic UI](http://plnkr.co/edit) and an [embedded UI](http://embed.plnkr.co). -The latter can be used both in a new tab or embedded within a guide. The AIO project uses the -embedded version in both ways. - -* `regularPlunker.js` - generates an HTML file for each example that will post to Plunker to create - a new editable project, when rendered. -* `embeddedPlunker.js` - generates an HTML file for each example that can be used in an iframe to - render an embedded Plunker project. -* `generatePlunkers.js` - executes each of the `regularPlunker.js` and `embeddedPlunker.js` utilities - to generate all the example plunker files. - -## Plunker generation - -Both flavours are created within `builder.js`. How is a plunker created? What is the process from a -directory with files to a link with a plunker. - -An "executable" plunker is an HTML file with a `<form>` that makes a post to plunker on submit. It -contains an `<input>` element for each file we need in the plunker. - -The form will be submitted on load, so you can either double click the HTML file or open it with an -anchor tag to open the plunker. - -So the `builder.js` job is to get all the needed files from an example and build this HTML file for you. - -For plunkers, we use a special `systemjs.config` that exists in -`/aio/tools/examples/shared/boilerplate/src/systemjs.config.web.js` and we also add the Google's copyright -to each file. - -## Customizing the generation per example basis - -How does this tool know what is an example and what is not? It will look for all folders containing a -`plnkr.json` file. If found, all files within the folder and subfolders will be used in the plunker, with -a few generic exceptions that you can find at `builder.js`. - -You can use the `plnkr.json` to customize the plunker generation. For example: - -```json -{ - "description": "Tour of Heroes: Part 6", - "basePath": "src/", - "files":[ - "!**/*.d.ts", - "!**/*.js", - "!**/*.[1,2].*" - ], - "tags": ["tutorial", "tour", "heroes", "http"] -} -``` - -Here you can specify a description for the plunker, some tags, a basePath and also a files array where you -can specify extra files to add or to ignore. - -## Classic plunkers and embedded ones - -Luckily, both kind of plunkers are very similar, they are created in the same way with minor exceptions. - -To handle those exceptions, we have the `embeddedPlunker.js` and the `regularPlunker.js`. Thanks to them, -the `builder.js` is as generic as possible. - -## Executing the plunker generation - -`generatePlunkers.js` will create a classic plunker and an embedded plunker for each `plnkr.json` it finds. - -Where? At `src/generated/live-examples/`. - -Then the `<live-example>` embedded component will look at this folder to get the plunker it needs for the -example. - -## Appendix: Why not generating plunkers at runtime? - -At AngularJS, all the plunkers were generated a runtime. The downside is that all the example codes would -need to be deployed as well and they won't be no longer useful after the plunker is generated. This tool -takes a few seconds to run, and the end result is only 3mb~. diff --git a/aio/tools/plunker-builder/embeddedPlunker.js b/aio/tools/plunker-builder/embeddedPlunker.js deleted file mode 100644 index f1819e7f84..0000000000 --- a/aio/tools/plunker-builder/embeddedPlunker.js +++ /dev/null @@ -1,34 +0,0 @@ -var PlunkerBuilder = require('./builder'); - -function buildPlunkers(basePath, destPath, options = {}) { - configureBuilder(options); - var builder = new PlunkerBuilder(basePath, destPath, options); - builder.buildPlunkers(); -} - -function configureBuilder(options) { - options.addField = addField; - options.plunkerFileName = 'eplnkr'; - options.url = 'https://embed.plnkr.co?show=preview'; - options.writeNoLink = false; - options.embedded = true; - options.extraData = extraData; -} - -function extraData(postData, config) { - postData['source[type]'] = config.description || 'Angular example'; - postData['source[url]'] = 'https://angular.io' -} - -function addField(postData, name, content) { - var encoding = 'utf8'; - if (name.split('.').pop() === 'png') { - encoding = 'base64'; - } - postData[`entries[${name}][content]`] = content; - postData[`entries[${name}][encoding]`] = encoding; -} - -module.exports = { - buildPlunkers: buildPlunkers -}; diff --git a/aio/tools/plunker-builder/generatePlunkers.js b/aio/tools/plunker-builder/generatePlunkers.js deleted file mode 100644 index ed02f7c508..0000000000 --- a/aio/tools/plunker-builder/generatePlunkers.js +++ /dev/null @@ -1,9 +0,0 @@ -const path = require('path'); -const regularPlunker = require('./regularPlunker'); -const embeddedPlunker = require('./embeddedPlunker'); - -const EXAMPLES_PATH = path.join(__dirname, '../../content/examples'); -const LIVE_EXAMPLES_PATH = path.join(__dirname, '../../src/generated/live-examples'); - -regularPlunker.buildPlunkers(EXAMPLES_PATH, LIVE_EXAMPLES_PATH); -embeddedPlunker.buildPlunkers(EXAMPLES_PATH, LIVE_EXAMPLES_PATH); diff --git a/aio/tools/plunker-builder/regularPlunker.js b/aio/tools/plunker-builder/regularPlunker.js deleted file mode 100644 index 6b7ad1b308..0000000000 --- a/aio/tools/plunker-builder/regularPlunker.js +++ /dev/null @@ -1,23 +0,0 @@ -var PlunkerBuilder = require('./builder'); - -function buildPlunkers(basePath, destPath, options = {}) { - configureBuilder(options); - var builder = new PlunkerBuilder(basePath, destPath, options); - builder.buildPlunkers(); -} - -function configureBuilder(options) { - options.addField = addField; - options.plunkerFileName = 'plnkr'; - options.url = 'http://plnkr.co/edit/?p=preview'; - options.writeNoLink = true; - options.embedded = false; -} - -function addField(postData, name, content) { - postData[`files[${name}]`] = content; -} - -module.exports = { - buildPlunkers: buildPlunkers -}; diff --git a/aio/tools/plunker-builder/translator/fileTranslator.js b/aio/tools/plunker-builder/translator/fileTranslator.js deleted file mode 100644 index 6f45476333..0000000000 --- a/aio/tools/plunker-builder/translator/fileTranslator.js +++ /dev/null @@ -1,51 +0,0 @@ -// var first_time = true; // DIAGNOSTIC - -function translate(html, rulesFile) { - rulesFile.rulesToApply.forEach(function(rxDatum) { - var rxRule = rulesFile.rules[rxDatum.pattern]; - // rxFrom is a rexexp - var rxFrom = rxRule.from; - // check if there is an exception - if (rxDatum.exceptIf) { - if (html.indexOf(rxDatum.exceptIf) !== -1) return; - } - if (rxDatum.from) { - var from = rxDatum.from.replace('/', '\/'); - var rxTemp = rxFrom.toString(); - rxTemp = rxTemp.replace('%tag%', from); - rxFrom = rxFromString(rxTemp); - } - // rxTo is a string - var rxTo = rxRule.to; - if (rxDatum.to) { - var to = rxDatum.to; - to = Array.isArray(to) ? to : [to]; - to = to.map(function (toItem) { - return rxTo.replace("%tag%", toItem); - }); - rxTo = to.join("\n "); - } - - /* DIAGNOSTIC - if (first_time && rxDatum.pattern === 'zone_pkg') { - first_time = false; - - console.log('zone_pkg'); - console.log(' rxFrom: '+rxFrom); - console.log(' rxTo: '+rxTo); - console.log(' replace: ' + html.replace(rxFrom, rxTo )); - } - */ - html = html.replace(rxFrom, rxTo); - }); - - return html; -} - -function rxFromString(rxString) { - var rx = /^\/(.*)\/(.*)/; - var pieces = rx.exec(rxString); - return RegExp(pieces[1], pieces[2]); -} - -module.exports = {translate: translate}; diff --git a/aio/tools/plunker-builder/translator/rules/indexHtml.js b/aio/tools/plunker-builder/translator/rules/indexHtml.js deleted file mode 100644 index aabd39f371..0000000000 --- a/aio/tools/plunker-builder/translator/rules/indexHtml.js +++ /dev/null @@ -1,133 +0,0 @@ -var rules = { - basehref: { - from: /<base href=".*"[/]?>/, - to: '<script>document.write(\'<base href="\' + document.location + \'" />\');</script>' - }, - angular_pkg: { - from: /src=".?node_modules\/@angular/g, - to: 'src="https://unpkg.com/@angular' - }, - script: { - from: /<script.*".*%tag%".*>.*<\/script>/, - to: '<script src="%tag%"></script>' - }, - link: { - from: '/<link rel="stylesheet" href=".*%tag%".*>/', - to: '<link rel="stylesheet" href="%tag%">' - }, - // Clear script like this: - // <script> - // System.import('app').catch(function(err){ console.error(err); }); - // </script> - system_strip_import_app: { - from: /<script>[^]?\s*System.import\('app'\)[^]*\/script>/, - to: '' - }, - system_extra_main: { - from: /main:\s*[\'|\"]index.js[\'|\"]/, - to: 'main: "index.ts"' - }, - system_extra_defaultExtension: { - from: /defaultExtension:\s*[\'|\"]js[\'|\"]/, - to: 'defaultExtension: "ts"' - }, - zone_pkg: { - from: /src=".?node_modules\/zone.js\/dist\/(.*)"/g, - to: 'src="https://unpkg.com/zone.js/dist/$1?main=browser"' - }, - system_js_header: { - from: '</head>', - to: ` - <link rel="stylesheet" href="styles.css"> - <script src="node_modules/core-js/client/shim.min.js"></script> - <script src="node_modules/zone.js/dist/zone.js"></script> - <script src="node_modules/systemjs/dist/system.src.js"></script> - <script src="systemjs.config.js"></script> - <script> - System.import('main.js').catch(function(err){ console.error(err); }); - </script> - </head> - ` - } -}; - -var rulesToApply = [ - { - pattern: 'system_js_header', - exceptIf: 'system.src.js' - }, - { - pattern: 'basehref', - }, - { - pattern: 'script', - from: 'node_modules/core-js/client/shim.min.js', - to: 'https://unpkg.com/core-js/client/shim.min.js' - }, - { - pattern: 'script', - from: 'node_modules/zone.js/dist/zone.js', - to: 'https://unpkg.com/zone.js@0.7.4?main=browser' - }, - { - pattern: 'script', - from: 'node_modules/rxjs/bundles/Rx.js', - to: 'https://unpkg.com/rxjs@5.5.2/bundles/Rx.js' - }, - { - pattern: 'script', - from: 'node_modules/systemjs/dist/system.src.js', - to: 'https://unpkg.com/systemjs@0.19.39/dist/system.src.js' - }, - { - pattern: 'script', - from: 'node_modules/angular/in-memory-web-api/web-api.js', - to: 'https://unpkg.com/angular/in-memory-web-api/web-api.js' - }, - - // Test libraries - - // Plunker recommends getting jasmine from cloudfare - // Don't upgrade to 2.5.x until following issue resolved - // https://github.com/jasmine/jasmine/issues/1231 - { - pattern: 'script', - from: 'node_modules/jasmine-core/lib/jasmine-core/jasmine.js', - to: 'https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/jasmine.js' - }, - { - pattern: 'script', - from: 'node_modules/jasmine-core/lib/jasmine-core/jasmine-html.js', - to: 'https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/jasmine-html.js' - }, - { - pattern: 'script', - from: 'node_modules/jasmine-core/lib/jasmine-core/boot.js', - to: 'https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/boot.js' - }, - { - pattern: 'link', - from: 'node_modules/jasmine-core/lib/jasmine-core/jasmine.css', - to: 'https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/jasmine.css' - }, - { - pattern: 'angular_pkg', - }, - { - pattern: 'zone_pkg', - }, - // { - // pattern: 'system_strip_import_app', - // }, - { - pattern: 'system_extra_main' - }, - { - pattern: 'system_extra_defaultExtension' - } -]; - -module.exports = { - rules: rules, - rulesToApply: rulesToApply -}; diff --git a/aio/tools/plunker-builder/translator/rules/mainTs.js b/aio/tools/plunker-builder/translator/rules/mainTs.js deleted file mode 100644 index 24b31851f1..0000000000 --- a/aio/tools/plunker-builder/translator/rules/mainTs.js +++ /dev/null @@ -1,24 +0,0 @@ -var rules = { - environment_import: { - from: `import { environment } from './environments/environment';`, - to: '' - }, - environment_check: { - from: /if \(environment\.production\)\s*{\n*\s*enableProdMode\(\);\s*}/g, - to: '' - } -}; - -var rulesToApply = [ - { - pattern: 'environment_import' - }, - { - pattern: 'environment_check' - } -]; - -module.exports = { - rules: rules, - rulesToApply: rulesToApply -}; diff --git a/aio/tools/plunker-builder/translator/rules/systemjsConfigExtras.js b/aio/tools/plunker-builder/translator/rules/systemjsConfigExtras.js deleted file mode 100644 index d774197eac..0000000000 --- a/aio/tools/plunker-builder/translator/rules/systemjsConfigExtras.js +++ /dev/null @@ -1,24 +0,0 @@ -var rules = { - system_extra_main: { - from: /main:\s*[\'|\"]index.js[\'|\"]/g, - to: 'main: "index.ts"' - }, - system_extra_defaultExtension: { - from: /defaultExtension:\s*[\'|\"]js[\'|\"]/g, - to: 'defaultExtension: "ts"' - } -}; - -var rulesToApply = [ - { - pattern: 'system_extra_main' - }, - { - pattern: 'system_extra_defaultExtension' - } -]; - -module.exports = { - rules: rules, - rulesToApply: rulesToApply -}; diff --git a/aio/tools/stackblitz-builder/README.md b/aio/tools/stackblitz-builder/README.md new file mode 100644 index 0000000000..dc39dce253 --- /dev/null +++ b/aio/tools/stackblitz-builder/README.md @@ -0,0 +1,59 @@ +# Overview + +[Stackblitz](https://stackblitz.com/) is an online tool for creating, collaborating and sharing ideas. +In AIO we use it to share one or more runnable versions of our examples. + +Stackblitz can be used both in a separate page and in an embedded form. +* `generateStackblitz.js` - executes each of the the StackblitzBuilder to generate a stackblitz file for each example. + +## Stackblitz generation + +Both forms are created within `builder.js`. How is a stackblitz created? What is the process from a +directory with files to a link with a stackblitz. + +An "executable" stackblitz is an HTML file with a `<form>` that makes a post to stackblitz on submit. It +contains an `<input>` element for each file we need in the stackblitz. + +The form will be submitted on load, so you can either double click the HTML file or open it with an +anchor tag to open the stackblitz. + +So the `builder.js` job is to get all the needed files from an example and build this HTML file for you. + +## Customizing the generation per example basis + +How does this tool know what is an example and what is not? It will look for all folders containing a +`stackblitz.json` file. If found, all files within the folder and subfolders will be used in the stackblitz, with +a few generic exceptions that you can find at `builder.js`. + +You can use the `stackblitz.json` to customize the stackblitz generation. For example: + +```json +{ + "description": "Tour of Heroes: Part 6", + "files":[ + "!**/*.d.ts", + "!**/*.js", + "!**/*.[1,2].*" + ], + "tags": ["tutorial", "tour", "heroes", "http"] +} +``` + +Here you can specify a description for the stackblitz, some tags and also a files array where you +can specify extra files to add or to ignore. + +## Executing the stackblitz generation + +`generateStackblitz.js` will create a stackblitz for each `stackblitz.json` it finds. + +Where? At `src/generated/live-examples/`. + +Then the `<live-example>` embedded component will look at this folder to get the stackblitz it needs for the +example. + +## Appendix: Why not generating stackblitz at runtime? + +At AngularJS, all the plunker examples were generated a runtime. The downside was that all the example code had to be +deployed as well and would no longer be useful after the plunker was generated. + +This `StackblitzBuilder` tool takes a few seconds to run, and the end result is only 3mb~. diff --git a/aio/tools/plunker-builder/builder.js b/aio/tools/stackblitz-builder/builder.js similarity index 51% rename from aio/tools/plunker-builder/builder.js rename to aio/tools/stackblitz-builder/builder.js index 8876520066..71801cb791 100644 --- a/aio/tools/plunker-builder/builder.js +++ b/aio/tools/stackblitz-builder/builder.js @@ -8,40 +8,43 @@ var jsdom = require("jsdom"); var fs = require("fs-extra"); var globby = require('globby'); -var fileTranslator = require('./translator/fileTranslator'); -var indexHtmlRules = require('./translator/rules/indexHtml'); -var systemjsConfigExtrasRules = require('./translator/rules/systemjsConfigExtras'); -var mainTsRules = require('./translator/rules/mainTs'); var regionExtractor = require('../transforms/examples-package/services/region-parser'); -class PlunkerBuilder { - constructor(basePath, destPath, options) { +class StackblitzBuilder { + constructor(basePath, destPath) { this.basePath = basePath; this.destPath = destPath; - this.options = options; - this.boilerplate = path.join(__dirname, '../examples/shared/boilerplate/systemjs'); + + // Extract npm package dependencies + var packageJson = require(path.join(__dirname, '../examples/shared/boilerplate/cli/package.json')); + this.examplePackageDependencies = packageJson.dependencies; + + // Add jasmine-core (which is a devDependency) for unit test examples. + var devDependencies = packageJson.devDependencies; + this.examplePackageDependencies['jasmine-core'] = devDependencies['jasmine-core']; + this.copyrights = {}; this._buildCopyrightStrings(); } - buildPlunkers() { - this._getPlunkerFiles(); - var errFn = this.options.errFn || function(e) { console.log(e); }; - var plunkerPaths = path.join(this.basePath, '**/*plnkr.json'); - var fileNames = globby.sync(plunkerPaths, { ignore: ['**/node_modules/**'] }); + build() { + // When testing it sometimes helps to look a just one example directory like so: + // var stackblitzPaths = path.join(this.basePath, '**/testing/*stackblitz.json'); + var stackblitzPaths = path.join(this.basePath, '**/*stackblitz.json'); + var fileNames = globby.sync(stackblitzPaths, { ignore: ['**/node_modules/**'] }); fileNames.forEach((configFileName) => { try { - this._buildPlunkerFrom(configFileName); + // console.log('***'+configFileName) + this._buildStackblitzFrom(configFileName); } catch (e) { - errFn(e); + console.log(e); } }); } - _addPlunkerFiles(postData) { - this.options.addField(postData, 'systemjs.config.js', this.systemjsConfig); - this.options.addField(postData, 'systemjs-angular-loader.js', this.systemjsModulePlugin); + _addDependencies(postData) { + postData['dependencies'] = JSON.stringify(this.examplePackageDependencies); } _buildCopyrightStrings() { @@ -53,17 +56,17 @@ class PlunkerBuilder { this.copyrights.html = `${pad}<!-- \n${copyright}\n-->`; } - // Build plunker from JSON configuration file (e.g., plnkr.json): + // Build stackblitz from JSON configuration file (e.g., stackblitz.json): // all properties are optional // files: string[] - array of globs - defaults to all js, ts, html, json, css and md files (with certain files removed) - // description: string - description of this plunker - defaults to the title in the index.html page. - // tags: string[] - optional array of plunker tags (for searchability) - // main: string - name of file that will become index.html in the plunker - defaults to index.html - // open: string - name of file to display within the plunker as in "open": "app/app.module.ts" - _buildPlunkerFrom(configFileName) { - // replace ending 'plnkr.json' with 'plnkr.no-link.html' to create output file name; - var outputFileName = `${this.options.plunkerFileName}.no-link.html`; - outputFileName = configFileName.replace(/plnkr\.json$/, outputFileName); + // description: string - description of this stackblitz - defaults to the title in the index.html page. + // tags: string[] - optional array of stackblitz tags (for searchability) + // main: string - name of file that will become index.html in the stackblitz - defaults to index.html + // file: string - name of file to display within the stackblitz as in "open": "app/app.module.ts" + _buildStackblitzFrom(configFileName) { + // replace ending 'stackblitz.json' with 'stackblitz.no-link.html' to create output file name; + var outputFileName = `stackblitz.no-link.html`; + outputFileName = configFileName.replace(/stackblitz\.json$/, outputFileName); var altFileName; if (this.destPath && this.destPath.length > 0) { var partPath = path.dirname(path.relative(this.basePath, outputFileName)); @@ -72,11 +75,9 @@ class PlunkerBuilder { try { var config = this._initConfigAndCollectFileNames(configFileName); var postData = this._createPostData(config); - this._addPlunkerFiles(postData); - var html = this._createPlunkerHtml(config, postData); - if (this.options.writeNoLink) { - fs.writeFileSync(outputFileName, html, 'utf-8'); - } + this._addDependencies(postData); + var html = this._createStackblitzHtml(config, postData); + fs.writeFileSync(outputFileName, html, 'utf-8'); if (altFileName) { var altDirName = path.dirname(altFileName); fs.ensureDirSync(altDirName); @@ -94,20 +95,30 @@ class PlunkerBuilder { } } - _createBasePlunkerHtml(config, embedded) { - var open = ''; + _createBaseStackblitzHtml(config) { + var file = ''; - if (config.open) { - open = embedded ? `&show=${config.open}` : `&open=${config.open}`; + // TODO: Doesn't work properly yet + if (config.file) { + file = `?file=${config.file}`; } - var action = `${this.options.url}${open}`; - var html = '<!DOCTYPE html><html lang="en"><body>'; - html += `<form id="mainForm" method="post" action="${action}" target="_self">`; + var action = `https://run.stackblitz.com/api/angular/v1${file}`; + var html = `<!DOCTYPE html><html lang="en"><body> + <form id="mainForm" method="post" action="${action}" target="_self"></form> + <script> + var embedded = 'ctl=1'; + var isEmbedded = window.location.search.indexOf(embedded) > -1; - // html += '<div class="button"><button id="formButton" type="submit">Create Plunker</button></div>' - // html += '</form><script>document.getElementById("formButton").click();</script>' - html += '</form><script>document.getElementById("mainForm").submit();</script>'; - html += '</body></html>'; + if (isEmbedded) { + var form = document.getElementById('mainForm'); + var action = form.action; + var actionHasParams = action.indexOf('?') > -1; + var symbol = actionHasParams ? '&' : '?' + form.action = form.action + symbol + embedded; + } + document.getElementById("mainForm").submit(); + </script> + </body></html>`; return html; } @@ -119,8 +130,6 @@ class PlunkerBuilder { if (extn == '.png') { content = this._encodeBase64(fileName); fileName = fileName.substr(0, fileName.length - 4) + '.base64.png' - } else if (-1 < fileName.indexOf('systemjs.config.extras')) { - content = this._getSystemjsConfigExtras(config); } else { content = fs.readFileSync(fileName, 'utf-8'); } @@ -134,12 +143,17 @@ class PlunkerBuilder { var relativeFileName = path.relative(config.basePath, fileName); + // Is the main a custom index-xxx.html file? Rename it if (relativeFileName == config.main) { - relativeFileName = 'index.html'; + relativeFileName = 'src/index.html'; + } + + // A custom main.ts file? Rename it + if (/src\/main[-.]\w+\.ts$/.test(relativeFileName)) { + relativeFileName = 'src/main.ts' } if (relativeFileName == 'index.html') { - content = fileTranslator.translate(content, indexHtmlRules); if (config.description == null) { // set config.description to title from index.html var matches = /<title>(.*)<\/title>/.exec(content); @@ -149,19 +163,9 @@ class PlunkerBuilder { } } - // Matches main.ts or main.1.ts - if (/^main(?:[.-]\w+)?\.ts$/.test(relativeFileName)) { - content = fileTranslator.translate(content, mainTsRules); - relativeFileName = 'main.ts'; - } - - if (relativeFileName == 'systemjs.config.extras.js') { - content = fileTranslator.translate(content, systemjsConfigExtrasRules); - } - content = regionExtractor()(content, extn.substr(1)).contents; - this.options.addField(postData, relativeFileName, content); + postData[`files[${relativeFileName}]`] = content; }); var tags = ['angular', 'example'].concat(config.tags || []); @@ -169,23 +173,13 @@ class PlunkerBuilder { postData['tags[' + ix + ']'] = tag; }); - if (!this.options.embedded) { - postData.private = true; + postData.description = "Angular Example - " + config.description; - postData.description = "Angular Example - " + config.description; - } else { - postData.title = "Angular Example - " + config.description; - } - - // Embedded needs to add more content, so if the callback is available, we call it - if (this.options.extraData) { - this.options.extraData(postData, config); - } return postData; } - _createPlunkerHtml(config, postData) { - var baseHtml = this._createBasePlunkerHtml(config, this.options.embedded); + _createStackblitzHtml(config, postData) { + var baseHtml = this._createBaseStackblitzHtml(config); var doc = jsdom.jsdom(baseHtml); var form = doc.querySelector('form'); _.forEach(postData, (value, key) => { @@ -214,39 +208,6 @@ class PlunkerBuilder { } } - _getPlunkerFiles() { - var systemJsModulePlugin = '/src/systemjs-angular-loader.js'; - var systemJsConfigPath = '/src/systemjs.config.web.js'; - if (this.options.build) { - systemJsConfigPath = '/src/systemjs.config.web.build.js'; - } - this.systemjsConfig = fs.readFileSync(this.boilerplate + systemJsConfigPath, 'utf-8'); - this.systemjsModulePlugin = fs.readFileSync(this.boilerplate + systemJsModulePlugin, 'utf-8'); - - // Copyright already added to web versions of systemjs.config - // this.systemjsConfig += this.copyrights.jsCss; - } - - // Try to replace `systemjs.config.extras.js` with the - // `systemjs.config.extras.web.js` web version that - // should default SystemJS barrels to `.ts` files rather than `.js` files - // Example: see docs `testing`. - // HACK-O-MATIC! - _getSystemjsConfigExtras(config) { - var extras = config.basePath + '/systemjs.config.extras.js'; - var webExtras = config.basePath + '/systemjs.config.extras.web.js'; - if (this._existsSync(webExtras)) { - // console.log('** Substituted "' + webExtras + '" for "' + extras + '".'); - return fs.readFileSync(webExtras, 'utf-8'); - } else if (this._existsSync(extras)){ - console.log('** WARNING: no "' + webExtras + '" replacement for "' + extras + '".'); - return fs.readFileSync(extras, 'utf-8'); - } else { - console.log('** WARNING: no "' + extras + '" file; returning empty content.'); - return ''; - } - } - _htmlToElement(document, html) { var div = document.createElement('div'); div.innerHTML = html; @@ -258,12 +219,13 @@ class PlunkerBuilder { var configSrc = fs.readFileSync(configFileName, 'utf-8'); try { var config = (configSrc && configSrc.trim().length) ? JSON.parse(configSrc) : {}; - config.basePath = config.basePath ? path.resolve(configDir, config.basePath) : configDir; + config.basePath = configDir; // assumes 'stackblitz.json' is at `/src` level. } catch (e) { - throw new Error(`Plunker config - unable to parse json file: ${configFileName}\n${e}`); + throw new Error(`Stackblitz config - unable to parse json file: ${configFileName}\n${e}`); } var defaultIncludes = ['**/*.ts', '**/*.js', '**/*.css', '**/*.html', '**/*.md', '**/*.json', '**/*.png']; + var boilerplateIncludes = ['src/environments/*.*', '.angular-cli.json', 'src/polyfills.ts']; if (config.files) { if (config.files.length > 0) { if (config.files[0].substr(0, 1) == '!') { @@ -273,11 +235,13 @@ class PlunkerBuilder { } else { config.files = defaultIncludes; } + config.files = config.files.concat(boilerplateIncludes); + var includeSpec = false; var gpaths = config.files.map(function(fileName) { fileName = fileName.trim(); if (fileName.substr(0,1) == '!') { - return "!" + path.join(config.basePath, fileName.substr(1)); + return '!' + path.join(config.basePath, fileName.substr(1)); } else { includeSpec = includeSpec || /\.spec\.(ts|js)$/.test(fileName); return path.join(config.basePath, fileName); @@ -285,23 +249,18 @@ class PlunkerBuilder { }); var defaultExcludes = [ + '!**/e2e/**/*.*', '!**/tsconfig.json', - '!**/*plnkr.*', '!**/package.json', '!**/example-config.json', '!**/tslint.json', '!**/.editorconfig', - '!**/systemjs.config.js', '!**/wallaby.js', '!**/karma-test-shim.js', '!**/karma.conf.js', '!**/test.ts', - '!**/polyfills.ts', '!**/tsconfig.app.json', - '!**/environments/**', - // AoT related files - '!**/aot/**/*.*', - '!**/*-aot.*' + '!**/*stackblitz.*' ]; // exclude all specs if no spec is mentioned in `files[]` @@ -317,4 +276,4 @@ class PlunkerBuilder { } } -module.exports = PlunkerBuilder; +module.exports = StackblitzBuilder; diff --git a/aio/tools/stackblitz-builder/generateStackblitz.js b/aio/tools/stackblitz-builder/generateStackblitz.js new file mode 100644 index 0000000000..0b80089ce0 --- /dev/null +++ b/aio/tools/stackblitz-builder/generateStackblitz.js @@ -0,0 +1,8 @@ +const path = require('path'); +const StackblitzBuilder = require('./builder'); + +const EXAMPLES_PATH = path.join(__dirname, '../../content/examples'); +const LIVE_EXAMPLES_PATH = path.join(__dirname, '../../src/generated/live-examples'); + +new StackblitzBuilder(EXAMPLES_PATH, LIVE_EXAMPLES_PATH).build(); + diff --git a/aio/tools/transforms/examples-package/file-readers/example-reader.js b/aio/tools/transforms/examples-package/file-readers/example-reader.js index 7f06bf33a5..f7ff368675 100644 --- a/aio/tools/transforms/examples-package/file-readers/example-reader.js +++ b/aio/tools/transforms/examples-package/file-readers/example-reader.js @@ -2,7 +2,7 @@ * The point of this reader is to tag all the files that are going to be used as examples in the * documentation. * Later on we can extract the regions, via "shredding"; and we can also construct runnable examples - * for passing to plunker and the like. + * for passing to Stackblitz and the like. */ module.exports = function exampleFileReader() { return {