From 50ce8323052ffe891ac0b4b7d8ad29088871b356 Mon Sep 17 00:00:00 2001 From: wessberg Date: Thu, 18 Oct 2018 20:55:52 +0200 Subject: [PATCH] feat(SystemJS): adds support for SystemJS 2.0 SystemJS 2.0 comes in two variants: A minimal 's' variant, and a more feature complete 'system' variant. A new option, 'variant', can now be passed to systemjs within a polyfill query to select one of those variants. For example: 'system|variant=s' selects the 's' variant. --- README.md | 12 +++++- package.json | 22 +++++----- src/bl/static/static-bl.ts | 5 ++- src/constant/constant.ts | 6 ++- .../polyfill-builder-service.ts | 15 +++++-- src/util/ensure-array/ensure-array.ts | 8 ++++ src/util/html/generate-html.ts | 6 +++ test/server/server.test.ts | 40 ++++++++++--------- 8 files changed, 78 insertions(+), 36 deletions(-) create mode 100644 src/util/ensure-array/ensure-array.ts diff --git a/README.md b/README.md index dd58525..95316c4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Logo for @wessberg/polyfiller
+Logo for @wessberg/polyfiller
Downloads per month Dependencies NPM Version @@ -100,6 +100,7 @@ An `option` is some data associated with a `feature`. It is associated with a feature using the `|` (pipe) operator. For example, here's how to associate the `force` option with a `feature`: `animation|force`. + Some `option`s apply to all `feature`s while others only apply to specific `feature`s. For example: `intl|locales=en` @@ -111,7 +112,7 @@ In order to do so, associate the `force` option with a `feature`. For example: `animation|force` This will force-apply a polyfill for `Web Animations`. -#### The `locales` option +#### The `locales` option for `Intl` **This option only works with `Intl`**. The `Intl` polyfill relies on locale data for it to work. There are over 600 different locale files shipped with Intl. Sending all of them back over the network would take way too much bandwidth. @@ -123,6 +124,13 @@ You can ask for as many you want by separating the locales with the `~` operator `intl|locales=en~da~fr` This will return a bundle of `Intl` along with locale data for `en` (English), `da` (Danish), and `fr` (French). +#### The `variant` option for `SystemJS` + +SystemJS comes in two base versions, a [minimal version called *s*](https://github.com/systemjs/systemjs#1-sjs-minimal-loader), and a [more feature-complete version called *system*](https://github.com/systemjs/systemjs#2-systemjs-loader). +By default, the *system* variant will be used. You can decide which one to use with the `variant` option. + +For example: `systemjs|variant=s` selects the *s* variant, while `systemjs|variant=system` selects the *system* variant. + ## Install `Polyfiller` is already hosted at `https://polyfill.app/api` as a **free** web service, but you can install it, for example if diff --git a/package.json b/package.json index 2cf1319..c3c14db 100644 --- a/package.json +++ b/package.json @@ -47,14 +47,14 @@ "@wessberg/rollup-plugin-di": "^1.0.87", "@wessberg/scaffold": "^1.0.4", "@wessberg/ts-config": "^0.0.30", - "rollup": "^0.66.2", + "rollup": "^0.66.6", "standard-changelog": "^2.0.1", "tslint": "^5.11.0", - "typescript": "^3.0.3", + "typescript": "^3.1.3", "useragent-generator": "^1.1.0" }, "dependencies": { - "@babel/core": "^7.1.0", + "@babel/core": "^7.1.2", "@babel/preset-env": "^7.1.0", "@babel/preset-stage-3": "^7.0.0", "@babel/preset-typescript": "^7.1.0", @@ -62,17 +62,17 @@ "@types/iltorb": "^2.3.0", "@types/memory-fs": "^0.3.2", "@types/mime": "^2.0.0", - "@types/node": "^10.10.3", + "@types/node": "^10.12.0", "@types/semver": "^5.5.0", - "@webcomponents/custom-elements": "^1.2.0", + "@webcomponents/custom-elements": "^1.2.1", "@webcomponents/shadydom": "^1.2.0", "@webcomponents/template": "^1.4.0", - "@wessberg/browserslist-generator": "0.0.47", + "@wessberg/browserslist-generator": "0.0.48", "@wessberg/di": "^1.1.0", "@wessberg/fileloader": "^1.1.9", "@wessberg/filesaver": "^1.0.8", "@wessberg/pointer-events": "^1.0.5", - "@wessberg/rollup-plugin-ts": "0.0.40", + "@wessberg/rollup-plugin-ts": "1.0.8", "Base64": "^1.0.1", "ava": "^0.25.0", "blob-polyfill": "^3.0.20180112", @@ -82,7 +82,7 @@ "core-js-builder": "^3.0.0-beta.3", "devcert": "^1.0.0", "events-polyfill": "^2.0.7", - "file-type": "^9.0.0", + "file-type": "^10.0.0", "http-status-codes": "^1.3.0", "iltorb": "^2.4.0", "intersection-observer": "^0.5.0", @@ -100,9 +100,9 @@ "requestanimationframe": "0.0.23", "requestidlecallback": "^0.3.0", "resize-observer": "^1.0.0-alpha.1", - "semver": "^5.5.1", + "semver": "^5.6.0", "setimmediate": "^1.0.5", - "systemjs": "^0.21.5", + "systemjs": "^2.0.2", "temp-dir": "^1.0.0", "toposort": "^2.0.2", "tslib": "^1.9.3", @@ -136,7 +136,7 @@ "license": "MIT", "scaffold": { "patreonUserId": "11315442", - "logo": "./documentation/asset/logo-color-text.png", + "logo": "https://raw.githubusercontent.com/wessberg/Polyfiller/master/documentation/asset/logo-color-text.png", "contributorMeta": { "Frederik Wessberg": { "imageUrl": "https://avatars2.githubusercontent.com/u/20454213?s=460&v=4", diff --git a/src/bl/static/static-bl.ts b/src/bl/static/static-bl.ts index 963d10d..aeb19c4 100644 --- a/src/bl/static/static-bl.ts +++ b/src/bl/static/static-bl.ts @@ -12,7 +12,10 @@ export class StaticBl implements IStaticBl { */ public async getWelcomeMessage (): Promise { return generateHtml(` -

Welcome to ${constant.meta.name} v${constant.meta.version}

+
+ logo +

Welcome to ${constant.meta.name} v${constant.meta.version}

+

To use it, please send a request to the path: ${constant.endpoint.polyfill} instead.

For API reference, please see Github

`); diff --git a/src/constant/constant.ts b/src/constant/constant.ts index aa38962..e9b9527 100644 --- a/src/constant/constant.ts +++ b/src/constant/constant.ts @@ -25,7 +25,11 @@ export const constant: IConstant = { polyfill: { systemjs: { library: "systemjs", - relativePaths: ["dist/system-production.js"], + relativePaths: ["dist/system.min.js"], + meta: { + system: "dist/system.min.js", + s: "dist/s.min.js" + }, features: [], version: environment.NPM_PACKAGE_DEPENDENCIES_SYSTEMJS, dependencies: [] diff --git a/src/service/polyfill-builder/polyfill-builder-service.ts b/src/service/polyfill-builder/polyfill-builder-service.ts index 4a1b532..a5384a8 100644 --- a/src/service/polyfill-builder/polyfill-builder-service.ts +++ b/src/service/polyfill-builder/polyfill-builder-service.ts @@ -12,6 +12,7 @@ import builder from "core-js-builder"; import {IPolyfillLibraryDictEntry} from "../../polyfill/polyfill-dict"; import {ICacheRegistryService} from "../registry/cache-registry/i-cache-registry-service"; import {ILoggerService} from "../logger/i-logger-service"; +import {ensureArray} from "../../util/ensure-array/ensure-array"; /** * A service that can load and cache all polyfills @@ -83,13 +84,21 @@ export class PolyfillBuilderService implements IPolyfillBuilderService { // Resolve the directory of the package.json file const packageDirectory = join(nodeModulesDirectory, library); - // For each of the relative paths, compute the absolute path - absolutePaths.push(...relativePaths.map(path => join(packageDirectory, path))); + // If SystemJS is requested, the variant to use may be provided as metadata. If so, we should use that one, rather than the relativePaths + if (polyfillFeature.name === "systemjs" && meta != null && polyfillFeature.meta != null && "variant" in polyfillFeature.meta && (polyfillFeature.meta.variant === "s" || polyfillFeature.meta.variant === "system")) { + absolutePaths.push(join(packageDirectory, meta[polyfillFeature.meta.variant])); + } + + // Otherwise, use all of the given relativePaths + else { + // For each of the relative paths, compute the absolute path + absolutePaths.push(...relativePaths.map(path => join(packageDirectory, path))); + } // If the Polyfill is "intl" and a localeDir is associated with it, also resolve the requested locales (if any) if (polyfillFeature.name === "intl" && meta != null && "localeDir" in meta && polyfillFeature.meta.locale != null) { // Normalize the requested locales to make sure we have an array to work with - const requestedLocales: string[] = typeof polyfillFeature.meta.locale === "string" ? [polyfillFeature.meta.locale] : polyfillFeature.meta.locale; + const requestedLocales: string[] = ensureArray(polyfillFeature.meta.locale); // Loop through all of the requested locales in parallel await Promise.all(requestedLocales.map(async requestedLocale => { diff --git a/src/util/ensure-array/ensure-array.ts b/src/util/ensure-array/ensure-array.ts new file mode 100644 index 0000000..2fff83b --- /dev/null +++ b/src/util/ensure-array/ensure-array.ts @@ -0,0 +1,8 @@ +/** + * Ensures that the given item is in fact an array + * @param {T[] | T} item + * @returns {T[]} + */ +export function ensureArray (item: T|T[]): T[] { + return Array.isArray(item) ? item : [item]; +} \ No newline at end of file diff --git a/src/util/html/generate-html.ts b/src/util/html/generate-html.ts index ce681b8..2571a0a 100644 --- a/src/util/html/generate-html.ts +++ b/src/util/html/generate-html.ts @@ -13,6 +13,12 @@ export function generateHtml (message: string): string { ${constant.meta.name} v${constant.meta.version} + ${message} diff --git a/test/server/server.test.ts b/test/server/server.test.ts index b71f6cf..4f899c8 100644 --- a/test/server/server.test.ts +++ b/test/server/server.test.ts @@ -10,7 +10,10 @@ import {initializeTests} from "./setup"; // @ts-ignore import {chrome, ie} from "useragent-generator"; import {ContentEncodingKind} from "../../src/encoding/content-encoding-kind"; -import {writeFileSync} from "fs"; +import {getPolyfillRequestFromUrl} from "../../src/util/polyfill/polyfill-util"; +import {URL} from "url"; + +// tslint:disable:no-identical-functions const config = DIContainer.get(); @@ -26,10 +29,6 @@ test("Delegates requests to '/' to the StaticController", async t => { path: (Array.isArray(constant.endpoint.index) ? constant.endpoint.index[0] : constant.endpoint.index) }); - if ("body" in result) { - console.log("body length:", result.body.length); - } - t.true(result.statusCode === constants.HTTP_STATUS_OK); }); @@ -45,10 +44,6 @@ test("Delegates requests to '/polyfill' to the PolyfillController", async t => { acceptEncoding: new Set([ContentEncodingKind.BROTLI]) }); - if ("body" in result) { - console.log("checksum:", result.checksum); - console.log("body length:", result.body.length); - } t.true(result.statusCode === constants.HTTP_STATUS_OK); }); @@ -64,10 +59,6 @@ test("Will not generate polyfills for 'Element' on Chrome 69 for a Galaxy S5", a acceptEncoding: new Set([ContentEncodingKind.BROTLI]) }); - if ("body" in result) { - console.log("checksum:", result.checksum); - console.log("body length:", result.body.length); - } t.true(result.statusCode === constants.HTTP_STATUS_OK); }); @@ -83,10 +74,23 @@ test("Will generate correct polyfills for IE11", async t => { acceptEncoding: undefined }); - if ("body" in result) { - writeFileSync("/Users/wessberg/desktop/foo.js",result.body); - console.log("checksum:", result.checksum); - console.log("body length:", result.body.length); - } t.true(result.statusCode === constants.HTTP_STATUS_OK); +}); + +test("Will correctly parse meta information for SystemJS. #1", async t => { + + const polyfillRequest = getPolyfillRequestFromUrl( + new URL("/api/polyfill?features=systemjs|variant=s", "https://polyfill.app"), + chrome(70) + ); + t.true([...polyfillRequest.features].some(({meta, name}) => name === "systemjs" && meta != null && meta.variant === "s")); +}); + +test("Will correctly parse meta information for SystemJS. #2", async t => { + + const polyfillRequest = getPolyfillRequestFromUrl( + new URL("/api/polyfill?features=systemjs|variant=system", "https://polyfill.app"), + chrome(70) + ); + t.true([...polyfillRequest.features].some(({meta, name}) => name === "systemjs" && meta != null && meta.variant === "system")); }); \ No newline at end of file