diff --git a/aio/tools/transforms/angular-api-package/index.js b/aio/tools/transforms/angular-api-package/index.js index af48da87f0..555ecd0645 100644 --- a/aio/tools/transforms/angular-api-package/index.js +++ b/aio/tools/transforms/angular-api-package/index.js @@ -107,6 +107,7 @@ module.exports = 'platform-browser-dynamic/index.ts', 'platform-browser-dynamic/testing/index.ts', 'platform-server/index.ts', + 'platform-server/init/index.ts', 'platform-server/testing/index.ts', 'platform-webworker/index.ts', 'platform-webworker-dynamic/index.ts', diff --git a/aio/tools/transforms/authors-package/api-package.js b/aio/tools/transforms/authors-package/api-package.js index cc23500436..a7d42bd103 100644 --- a/aio/tools/transforms/authors-package/api-package.js +++ b/aio/tools/transforms/authors-package/api-package.js @@ -18,7 +18,7 @@ const packageMap = { forms: ['forms/index.ts'], 'platform-browser': ['platform-browser/index.ts', 'platform-browser/animations/index.ts', 'platform-browser/testing/index.ts'], 'platform-browser-dynamic': ['platform-browser-dynamic/index.ts', 'platform-browser-dynamic/testing/index.ts'], - 'platform-server': ['platform-server/index.ts', 'platform-server/testing/index.ts'], + 'platform-server': ['platform-server/index.ts', 'platform-server/init/index.ts', 'platform-server/testing/index.ts'], router: ['router/index.ts', 'router/testing/index.ts', 'router/upgrade/index.ts'], 'service-worker': ['service-worker/index.ts'], upgrade: ['upgrade/index.ts', 'upgrade/static/index.ts', 'upgrade/static/testing/index.ts'] diff --git a/goldens/public-api/platform-server/init/init.d.ts b/goldens/public-api/platform-server/init/init.d.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/integration/cli-elements-universal/src/main.server.ts b/integration/cli-elements-universal/src/main.server.ts index 10150a7181..cb15695aa9 100644 --- a/integration/cli-elements-universal/src/main.server.ts +++ b/integration/cli-elements-universal/src/main.server.ts @@ -1,3 +1,4 @@ +import '@angular/platform-server/init'; import { enableProdMode } from '@angular/core'; import { environment } from './environments/environment'; diff --git a/integration/typings_test_ts40/include-all.ts b/integration/typings_test_ts40/include-all.ts index 7bf19f646c..86b57f2789 100644 --- a/integration/typings_test_ts40/include-all.ts +++ b/integration/typings_test_ts40/include-all.ts @@ -27,6 +27,7 @@ import * as platformBrowserDynamicTesting from '@angular/platform-browser-dynami import * as platformBrowserAnimations from '@angular/platform-browser/animations'; import * as platformBrowserTesting from '@angular/platform-browser/testing'; import * as platformServer from '@angular/platform-server'; +import * as platformServerInit from '@angular/platform-server/init'; import * as platformServerTesting from '@angular/platform-server/testing'; import * as router from '@angular/router'; import * as routerTesting from '@angular/router/testing'; @@ -56,6 +57,7 @@ export default { platformBrowserDynamicTesting, platformBrowserAnimations, platformServer, + platformServerInit, platformServerTesting, router, routerTesting, diff --git a/integration/typings_test_ts41/include-all.ts b/integration/typings_test_ts41/include-all.ts index 7bf19f646c..86b57f2789 100644 --- a/integration/typings_test_ts41/include-all.ts +++ b/integration/typings_test_ts41/include-all.ts @@ -27,6 +27,7 @@ import * as platformBrowserDynamicTesting from '@angular/platform-browser-dynami import * as platformBrowserAnimations from '@angular/platform-browser/animations'; import * as platformBrowserTesting from '@angular/platform-browser/testing'; import * as platformServer from '@angular/platform-server'; +import * as platformServerInit from '@angular/platform-server/init'; import * as platformServerTesting from '@angular/platform-server/testing'; import * as router from '@angular/router'; import * as routerTesting from '@angular/router/testing'; @@ -56,6 +57,7 @@ export default { platformBrowserDynamicTesting, platformBrowserAnimations, platformServer, + platformServerInit, platformServerTesting, router, routerTesting, diff --git a/packages/bazel/src/ng_package/ng_package.bzl b/packages/bazel/src/ng_package/ng_package.bzl index f0a07a848e..a73c066640 100644 --- a/packages/bazel/src/ng_package/ng_package.bzl +++ b/packages/bazel/src/ng_package/ng_package.bzl @@ -105,6 +105,7 @@ WELL_KNOWN_GLOBALS = {p: _global_name(p) for p in [ "@angular/forms", "@angular/core/testing", "@angular/core", + "@angular/platform-server/init", "@angular/platform-server/testing", "@angular/platform-server", "@angular/common/testing", diff --git a/packages/platform-server/BUILD.bazel b/packages/platform-server/BUILD.bazel index 85f6bbb88f..eade038378 100644 --- a/packages/platform-server/BUILD.bazel +++ b/packages/platform-server/BUILD.bazel @@ -30,6 +30,7 @@ ng_package( name = "npm_package", srcs = [ "package.json", + "//packages/platform-server/init:package.json", "//packages/platform-server/testing:package.json", ], entry_point = ":index.ts", @@ -44,6 +45,7 @@ ng_package( ], deps = [ ":platform-server", + "//packages/platform-server/init", "//packages/platform-server/testing", ], ) diff --git a/packages/platform-server/init/BUILD.bazel b/packages/platform-server/init/BUILD.bazel new file mode 100644 index 0000000000..a3dcc6c667 --- /dev/null +++ b/packages/platform-server/init/BUILD.bazel @@ -0,0 +1,18 @@ +load("//tools:defaults.bzl", "ng_module") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["package.json"]) + +ng_module( + name = "init", + srcs = glob( + [ + "*.ts", + "src/**/*.ts", + ], + ), + deps = [ + "//packages/platform-server", + ], +) diff --git a/packages/platform-server/init/PACKAGE.md b/packages/platform-server/init/PACKAGE.md new file mode 100644 index 0000000000..e503f53f09 --- /dev/null +++ b/packages/platform-server/init/PACKAGE.md @@ -0,0 +1,15 @@ +Initializes the server environment for rendering an Angular application. + +For example, it provides shims (such as DOM globals) for the server environment. + +The initialization happens as a [side effect of importing](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#import_a_module_for_its_side_effects_only) the entry point (i.e. there are no specific exports): + +```ts +import '@angular/platform-server/init'; +``` + +
+ + The import must come before any imports (direct or transitive) that rely on DOM built-ins being available. + +
diff --git a/packages/platform-server/init/index.ts b/packages/platform-server/init/index.ts new file mode 100644 index 0000000000..1f364dbd88 --- /dev/null +++ b/packages/platform-server/init/index.ts @@ -0,0 +1,14 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +// This file is not used to build this module. It is only used during editing +// by the TypeScript language service and during build for verifcation. `ngc` +// replaces this file with production index.ts when it rewrites private symbol +// names. + +export * from './public_api'; diff --git a/packages/platform-server/init/package.json b/packages/platform-server/init/package.json new file mode 100644 index 0000000000..55674a97d9 --- /dev/null +++ b/packages/platform-server/init/package.json @@ -0,0 +1,4 @@ +{ + "name": "@angular/platform-server/init", + "sideEffects": true +} diff --git a/packages/platform-server/init/public_api.ts b/packages/platform-server/init/public_api.ts new file mode 100644 index 0000000000..51cfd93d5a --- /dev/null +++ b/packages/platform-server/init/public_api.ts @@ -0,0 +1,14 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +/** + * @module + * @description + * Entry point for all public APIs of this package. + */ +export * from './src/init'; diff --git a/packages/platform-server/init/src/init.ts b/packages/platform-server/init/src/init.ts new file mode 100644 index 0000000000..9005b79073 --- /dev/null +++ b/packages/platform-server/init/src/init.ts @@ -0,0 +1,17 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +/** + * @module + * @description + * Entry point for all initialization APIs of the platform-server package. + */ + +import {applyShims} from './shims'; + +applyShims(); diff --git a/packages/platform-server/init/src/shims.ts b/packages/platform-server/init/src/shims.ts new file mode 100644 index 0000000000..3440e360ac --- /dev/null +++ b/packages/platform-server/init/src/shims.ts @@ -0,0 +1,16 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import {setDomTypes} from '../../src/domino_adapter'; + +/** + * Apply the necessary shims to make DOM globals (such as `Element`, `HTMLElement`, etc.) available + * on the environment. + */ +export function applyShims(): void { + setDomTypes(); +} diff --git a/packages/platform-server/init/test/BUILD.bazel b/packages/platform-server/init/test/BUILD.bazel new file mode 100644 index 0000000000..aeee41bd84 --- /dev/null +++ b/packages/platform-server/init/test/BUILD.bazel @@ -0,0 +1,25 @@ +load("//tools:defaults.bzl", "jasmine_node_test", "ts_library") +load("//tools/circular_dependency_test:index.bzl", "circular_dependency_test") + +circular_dependency_test( + name = "circular_deps_test", + entry_point = "angular/packages/platform-server/init/index.js", + deps = ["//packages/platform-server/init"], +) + +ts_library( + name = "test_lib", + testonly = True, + srcs = glob(["**/*.ts"]), + deps = [ + "//packages/platform-server/init", + ], +) + +jasmine_node_test( + name = "test", + bootstrap = ["//tools/testing:node_no_angular_es5"], + deps = [ + ":test_lib", + ], +) diff --git a/packages/platform-server/init/test/shims_spec.ts b/packages/platform-server/init/test/shims_spec.ts new file mode 100644 index 0000000000..3bc8b90d22 --- /dev/null +++ b/packages/platform-server/init/test/shims_spec.ts @@ -0,0 +1,41 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import {applyShims} from '../src/shims'; + +describe('applyShims()', () => { + if (isBrowser) return; // NODE only + + const domino = require('domino'); + const globalClone = {...global}; + + afterEach(() => { + // Un-patch `global`. + const currentProps = Object.keys(global) as (keyof NodeJS.Global)[]; + for (const prop of currentProps) { + if (globalClone.hasOwnProperty(prop)) { + (global as any)[prop] = globalClone[prop]; + } else { + delete (global as any)[prop]; + } + } + }); + + it('should load `domino.impl` onto `global`', () => { + expect(global).not.toEqual(jasmine.objectContaining(domino.impl)); + + applyShims(); + expect(global).toEqual(jasmine.objectContaining(domino.impl)); + }); + + it('should define `KeyboardEvent` on `global`', () => { + expect((global as any).KeyboardEvent).not.toBe((domino.impl as any).Event); + + applyShims(); + expect((global as any).KeyboardEvent).toBe((domino.impl as any).Event); + }); +}); diff --git a/packages/platform-server/package.json b/packages/platform-server/package.json index 6803eae500..e6e0eda4b0 100644 --- a/packages/platform-server/package.json +++ b/packages/platform-server/package.json @@ -25,7 +25,15 @@ "ng-update": { "packageGroup": "NG_UPDATE_PACKAGE_GROUP" }, - "sideEffects": false, + "sideEffects": [ + "./bundles/platform-server-init.umd.js", + "./bundles/platform-server-init.umd.min.js", + "./esm2015/init/src/init.js", + "./fesm2015/init.js", + "./__ivy_ngcc__/bundles/platform-server-init.umd.js", + "./__ivy_ngcc__/esm2015/init/src/init.js", + "./__ivy_ngcc__/fesm2015/init.js" + ], "engines": { "node": ">=8.0" }, diff --git a/packages/platform-server/src/domino_adapter.ts b/packages/platform-server/src/domino_adapter.ts index 232c644e5a..54256a2c19 100644 --- a/packages/platform-server/src/domino_adapter.ts +++ b/packages/platform-server/src/domino_adapter.ts @@ -14,8 +14,8 @@ function _notImplemented(methodName: string) { return new Error('This method is not implemented in DominoAdapter: ' + methodName); } -function setDomTypes() { - // Make all Domino types available as types in the global env. +export function setDomTypes() { + // Make all Domino types available in the global env. Object.assign(global, domino.impl); (global as any)['KeyboardEvent'] = domino.impl.Event; } diff --git a/test-main.js b/test-main.js index 7cc5f3323d..b935f6bf39 100644 --- a/test-main.js +++ b/test-main.js @@ -27,7 +27,7 @@ System.config({ 'domino': 'dist/all/@angular/empty.js', 'url': 'dist/all/@angular/empty.js', 'xhr2': 'dist/all/@angular/empty.js', - '@angular/platform-server/src/domino_adapter': 'dist/all/empty.js', + '@angular/platform-server/src/domino_adapter': 'dist/all/@angular/empty.js', 'angular-in-memory-web-api': 'dist/all/@angular/misc/angular-in-memory-web-api', 'rxjs': 'node_modules/rxjs', }, @@ -64,6 +64,7 @@ System.config({ '@angular/platform-browser': {main: 'index.js', defaultExtension: 'js'}, '@angular/platform-browser-dynamic/testing': {main: 'index.js', defaultExtension: 'js'}, '@angular/platform-browser-dynamic': {main: 'index.js', defaultExtension: 'js'}, + '@angular/platform-server/init': {main: 'index.js', defaultExtension: 'js'}, '@angular/platform-server/testing': {main: 'index.js', defaultExtension: 'js'}, '@angular/platform-server': {main: 'index.js', defaultExtension: 'js'}, '@angular/private/testing': {main: 'index.js', defaultExtension: 'js'},