Added polyfill
This commit is contained in:
808
package-lock.json
generated
808
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -16,6 +16,7 @@
|
|||||||
"install-prod-win": "npm install --only=dev && npm install --only=prod && npm run build && rmdir /Q/S node_modules && npm install --only=prod"
|
"install-prod-win": "npm install --only=dev && npm install --only=prod && npm run build && rmdir /Q/S node_modules && npm install --only=prod"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@10xjs/polyfill-analyzer": "^0.1.0",
|
||||||
"connect-redis": "^5.0.0",
|
"connect-redis": "^5.0.0",
|
||||||
"cookie-parser": "~1.4.4",
|
"cookie-parser": "~1.4.4",
|
||||||
"env-var": "^6.3.0",
|
"env-var": "^6.3.0",
|
||||||
@@ -25,9 +26,12 @@
|
|||||||
"json-prune": "^1.1.0",
|
"json-prune": "^1.1.0",
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.1",
|
||||||
"node-sass-middleware": "0.11.0",
|
"node-sass-middleware": "0.11.0",
|
||||||
|
"polyfill-library": "^3.97.0",
|
||||||
"proper-url-join": "^2.1.1",
|
"proper-url-join": "^2.1.1",
|
||||||
"pug": "^3.0.0",
|
"pug": "^3.0.0",
|
||||||
"redis": "^3.0.2",
|
"redis": "^3.0.2",
|
||||||
|
"threads": "^1.6.3",
|
||||||
|
"tiny-worker": "^2.3.0",
|
||||||
"uuid": "^8.3.1",
|
"uuid": "^8.3.1",
|
||||||
"winston": "^3.3.3"
|
"winston": "^3.3.3"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"noImplicitReturns": true,
|
"noImplicitReturns": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"sourceRoot": "./src",
|
"sourceRoot": "../js-source",
|
||||||
"rootDir": ".",
|
"rootDir": ".",
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"baseUrl": "."
|
"baseUrl": "."
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import * as redisStore from 'connect-redis';
|
|||||||
import * as session from 'express-session';
|
import * as session from 'express-session';
|
||||||
import * as sassMiddleware from 'node-sass-middleware';
|
import * as sassMiddleware from 'node-sass-middleware';
|
||||||
import indexRouter from './routes';
|
import indexRouter from './routes';
|
||||||
import {HttpLogger, Redis, Config, setupAuthProxy, getReloadRouter} from './utils';
|
import {HttpLogger, Redis, Config, setupAuthProxy, getReloadRouter, polyfillRoute} from './utils';
|
||||||
import {Store} from 'express-session';
|
import {Store} from 'express-session';
|
||||||
|
|
||||||
export const app = express();
|
export const app = express();
|
||||||
@@ -46,6 +46,7 @@ router.use(session({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
// static config
|
// static config
|
||||||
|
router.use("/js/polyfill.js", polyfillRoute);
|
||||||
router.use(sassMiddleware({
|
router.use(sassMiddleware({
|
||||||
src: path.join(__dirname, '../public'),
|
src: path.join(__dirname, '../public'),
|
||||||
dest: path.join(__dirname, '../public'),
|
dest: path.join(__dirname, '../public'),
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export class Resolvable<T, U extends Array<unknown>> extends FetchOnce<T, U> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WaitForSync<T, U extends Array<unknown>> extends FetchOnce<T, U> {
|
export class WaitForSync<T> extends FetchOnce<T, never> {
|
||||||
protected state: ResolvableState = ResolvableState.PENDING;
|
protected state: ResolvableState = ResolvableState.PENDING;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ export {Logger, HttpLogger} from './logging';
|
|||||||
export {setupAuthProxy} from './auth-proxy';
|
export {setupAuthProxy} from './auth-proxy';
|
||||||
export {Resolvable, WaitForSync} from './helpers/resolvable';
|
export {Resolvable, WaitForSync} from './helpers/resolvable';
|
||||||
export {getReloadRouter} from './auto-reload';
|
export {getReloadRouter} from './auto-reload';
|
||||||
|
export {polyfillRoute} from './polyfill';
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const logger = winston.createLogger({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const levels = ["error", "warn", "info", "http", "verbose", "debug", "silly"] as const;
|
const levels = ["error", "warn", "info", "http", "verbose", "debug", "silly"] as const;
|
||||||
type LogLevels = typeof levels[number];
|
type LogLevels = typeof levels[number]|"log";
|
||||||
const wrapper = (original: LeveledLogMethod) => {
|
const wrapper = (original: LeveledLogMethod) => {
|
||||||
return (...args: unknown[]) => {
|
return (...args: unknown[]) => {
|
||||||
return original(args.map((obj) => typeof obj === "string" ? obj : prune(obj)).join(" "));
|
return original(args.map((obj) => typeof obj === "string" ? obj : prune(obj)).join(" "));
|
||||||
@@ -30,6 +30,7 @@ export const Logger = {
|
|||||||
for (const level of levels) {
|
for (const level of levels) {
|
||||||
Logger[level] = wrapper(logger[level]);
|
Logger[level] = wrapper(logger[level]);
|
||||||
}
|
}
|
||||||
|
Logger.log = wrapper(logger["silly"]);
|
||||||
|
|
||||||
export const HttpLogger: RequestHandler = (req, res, next) => {
|
export const HttpLogger: RequestHandler = (req, res, next) => {
|
||||||
const start = Date.now();
|
const start = Date.now();
|
||||||
|
|||||||
25
src/utils/polyfill-worker.ts
Normal file
25
src/utils/polyfill-worker.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// workers/add.js
|
||||||
|
import {expose} from "threads/worker";
|
||||||
|
import * as fs from "fs";
|
||||||
|
import {analyze} from '@10xjs/polyfill-analyzer';
|
||||||
|
import allPolyfills from '@10xjs/polyfill-analyzer/dist/polyfills';
|
||||||
|
import {PolyfillFeatureList} from "polyfill-library";
|
||||||
|
|
||||||
|
expose(() => {
|
||||||
|
const exclude = [
|
||||||
|
"console.markTimeline",
|
||||||
|
"console.timeline",
|
||||||
|
"console.timelineEnd",
|
||||||
|
];
|
||||||
|
const featureList = analyze({
|
||||||
|
source: fs.readFileSync('./public/js/bundle.js', 'utf-8'),
|
||||||
|
include: allPolyfills.filter(x => !exclude.includes(x)),
|
||||||
|
// Not all features listed by polyfillLibrary.listAllPolyfills()` can be detected.
|
||||||
|
unsupportedPolyfill: 'ignore',
|
||||||
|
});
|
||||||
|
const feats: PolyfillFeatureList = {};
|
||||||
|
for (const feature of featureList) {
|
||||||
|
feats[feature] = {};
|
||||||
|
}
|
||||||
|
return feats;
|
||||||
|
});
|
||||||
35
src/utils/polyfill.ts
Normal file
35
src/utils/polyfill.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import {RequestHandler} from 'express';
|
||||||
|
import * as polyfillLibrary from 'polyfill-library';
|
||||||
|
import {Config} from './config';
|
||||||
|
import {PolyfillFeatureList} from 'polyfill-library';
|
||||||
|
import {Logger} from './logging';
|
||||||
|
import {WaitForSync} from './helpers/resolvable';
|
||||||
|
import {spawn, Thread, Worker} from 'threads';
|
||||||
|
import {WorkerFunction} from 'threads/dist/types/worker';
|
||||||
|
|
||||||
|
const features = new WaitForSync<PolyfillFeatureList>();
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const worker = await spawn<WorkerFunction>(new Worker("./polyfill-worker"));
|
||||||
|
const feats = await worker() as PolyfillFeatureList;
|
||||||
|
await Thread.terminate(worker);
|
||||||
|
return feats;
|
||||||
|
})()
|
||||||
|
.then(feats => {
|
||||||
|
Logger.debug("Polyfill analysed:", feats);
|
||||||
|
features.setData(feats);
|
||||||
|
})
|
||||||
|
.catch(err => features.setError(err));
|
||||||
|
|
||||||
|
|
||||||
|
export const polyfillRoute: RequestHandler = async (req, res) => {
|
||||||
|
const polyfillBundle = await polyfillLibrary.getPolyfillString({
|
||||||
|
uaString: req.header("user-agent"),
|
||||||
|
features: await features.resolve(),
|
||||||
|
minify: Config.isProduction,
|
||||||
|
unknown: "polyfill",
|
||||||
|
stream: false,
|
||||||
|
});
|
||||||
|
res.setHeader('Content-Type', 'text/javascript');
|
||||||
|
res.send(polyfillBundle);
|
||||||
|
};
|
||||||
37
src/utils/types/polyfill.d.ts
vendored
Normal file
37
src/utils/types/polyfill.d.ts
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
declare module "polyfill-library" {
|
||||||
|
import {Readable} from 'stream';
|
||||||
|
|
||||||
|
function listAllPolyfills(): string[];
|
||||||
|
function describePolyfill(featureName: string): Promise<PolyfillMetadata|undefined>;
|
||||||
|
function getOptions(opts: Partial<PolyfillOptions>): PolyfillOptions;
|
||||||
|
function getPolyfills(opts: Partial<PolyfillOptions>): Promise<PolyfillFeatures>;
|
||||||
|
function getPolyfillString(opts: Partial<PolyfillOptions>&{stream?: true}): Readable;
|
||||||
|
function getPolyfillString(opts: Partial<PolyfillOptions>&{stream: false}): Promise<string>;
|
||||||
|
|
||||||
|
type PolyfillMetadata = {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
type PolyfillFeatureList = {
|
||||||
|
[featureName: string]: {
|
||||||
|
flags?: string[]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
type PolyfillOptions = {
|
||||||
|
minify: boolean,
|
||||||
|
unknown: 'polyfill'|'ignore',
|
||||||
|
features: PolyfillFeatureList,
|
||||||
|
excludes: string[],
|
||||||
|
uaString: string,
|
||||||
|
rum: boolean,
|
||||||
|
};
|
||||||
|
|
||||||
|
type PolyfillFeature = {
|
||||||
|
flags: string[],
|
||||||
|
dependencyOf: string[],
|
||||||
|
aliasOf: string[],
|
||||||
|
}
|
||||||
|
|
||||||
|
type PolyfillFeatures = { [featureName: string]: PolyfillFeature };
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ html
|
|||||||
script(type='text/javascript', async, src=baseUrl+'/auto-reload/client.js')
|
script(type='text/javascript', async, src=baseUrl+'/auto-reload/client.js')
|
||||||
body
|
body
|
||||||
block content
|
block content
|
||||||
|
script(type='text/javascript', src=baseUrl+'/js/polyfill.js')
|
||||||
script(type='text/javascript', src=baseUrl+'/js/require-2.3.6.min.js')
|
script(type='text/javascript', src=baseUrl+'/js/require-2.3.6.min.js')
|
||||||
script(type='text/javascript', src=baseUrl+'/js/bundle.js')
|
script(type='text/javascript', src=baseUrl+'/js/bundle.js')
|
||||||
script.
|
script.
|
||||||
|
|||||||
Reference in New Issue
Block a user