Switch things to typescript, use @types/modernizr, fix global.d.ts. Move mobile_guide redirect to index.ts

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski 2020-04-05 00:55:36 +01:00
parent 093b7bbf72
commit b1575524aa
8 changed files with 92 additions and 72 deletions

View file

@ -96,6 +96,7 @@
"@babel/preset-typescript": "^7.7.4",
"@babel/register": "^7.7.4",
"@babel/runtime": "^7.7.6",
"@types/modernizr": "^3.5.3",
"@types/react": "16.9",
"@types/react-dom": "^16.9.4",
"autoprefixer": "^9.7.3",

View file

@ -14,12 +14,22 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
type ReactNode = import("react").ReactNode;
import {ReactNode} from "react";
import "modernizr";
interface Window {
Olm: {
init: () => Promise<void>;
};
mxSendRageshake: (text: string, withLogs?: boolean) => void;
matrixChat: ReactNode;
declare global {
interface Window {
Modernizr: ModernizrAPI & FeatureDetects;
Olm: {
init: () => Promise<void>;
};
mxSendRageshake: (text: string, withLogs?: boolean) => void;
matrixChat: ReactNode;
}
// workaround for https://github.com/microsoft/TypeScript/issues/30933
interface ObjectConstructor {
fromEntries?(xs: [string|number|symbol, any][]): object
}
}

View file

@ -44,41 +44,6 @@ import {loadConfig, preparePlatform, loadLanguage, loadOlm} from "./init";
let lastLocationHashSet = null;
function checkBrowserFeatures() {
if (!window.Modernizr) {
console.error("Cannot check features - Modernizr global is missing.");
return false;
}
// custom checks atop Modernizr because it doesn't have ES2018/ES2019 checks in it for some features we depend on,
// Modernizr requires rules to be lowercase with no punctuation:
// ES2018: http://www.ecma-international.org/ecma-262/9.0/#sec-promise.prototype.finally
window.Modernizr.addTest("promiseprototypefinally", () =>
window.Promise && window.Promise.prototype && typeof window.Promise.prototype.finally === "function");
// ES2019: http://www.ecma-international.org/ecma-262/10.0/#sec-object.fromentries
window.Modernizr.addTest("objectfromentries", () =>
window.Object && typeof window.Object.fromEntries === "function");
const featureList = Object.keys(window.Modernizr);
let featureComplete = true;
for (let i = 0; i < featureList.length; i++) {
if (window.Modernizr[featureList[i]] === undefined) {
console.error(
"Looked for feature '%s' but Modernizr has no results for this. " +
"Has it been configured correctly?", featureList[i],
);
return false;
}
if (window.Modernizr[featureList[i]] === false) {
console.error("Browser missing feature: '%s'", featureList[i]);
// toggle flag rather than return early so we log all missing features rather than just the first.
featureComplete = false;
}
}
return featureComplete;
}
// Parse the given window.location and return parameters that can be used when calling
// MatrixChat.showScreen(screen, params)
function getScreenFromLocation(location) {
@ -163,7 +128,7 @@ function onTokenLoginCompleted() {
window.location.href = formatted;
}
export async function loadApp() {
export async function loadApp(fragParams: {}, acceptBrowser: boolean) {
// XXX: the way we pass the path to the worker script from webpack via html in body's dataset is a hack
// but alternatives seem to require changing the interface to passing Workers to js-sdk
const vectorIndexeddbWorkerScript = document.body.dataset.vectorIndexeddbWorkerScript;
@ -191,26 +156,8 @@ export async function loadApp() {
// Load language after loading config.json so that settingsDefaults.language can be applied
await loadLanguage();
const fragparts = parseQsFromFragment(window.location);
const params = parseQs(window.location);
// don't try to redirect to the native apps if we're
// verifying a 3pid (but after we've loaded the config)
// or if the user is following a deep link
// (https://github.com/vector-im/riot-web/issues/7378)
const preventRedirect = fragparts.params.client_secret || fragparts.location.length > 0;
if (!preventRedirect) {
const isIos = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
const isAndroid = /Android/.test(navigator.userAgent);
if (isIos || isAndroid) {
if (document.cookie.indexOf("riot_mobile_redirect_to_guide=false") === -1) {
window.location = "mobile_guide/";
return;
}
}
}
// as quickly as we possibly can, set a default theme...
await setTheme();
@ -237,17 +184,13 @@ export async function loadApp() {
return <GenericErrorPage message={errorMessage} title={_t("Your Riot is misconfigured")} />;
}
const validBrowser = checkBrowserFeatures();
const acceptInvalidBrowser = window.localStorage && window.localStorage.getItem('mx_accepts_unsupported_browser');
const urlWithoutQuery = window.location.protocol + '//' + window.location.host + window.location.pathname;
console.log("Vector starting at " + urlWithoutQuery);
if (configError) {
return <div className="error">
Unable to load config file: please refresh the page to try again.
</div>;
} else if (validBrowser || acceptInvalidBrowser) {
} else if (acceptBrowser) {
platform.startUpdater();
try {
@ -260,7 +203,7 @@ export async function loadApp() {
ConferenceHandler={VectorConferenceHandler}
config={config}
realQueryParams={params}
startingFragmentQueryParams={fragparts.params}
startingFragmentQueryParams={fragParams}
enableGuest={!config.disable_guests}
onTokenLoginCompleted={onTokenLoginCompleted}
initialScreenAfterLogin={getScreenFromLocation(window.location)}

View file

@ -25,6 +25,7 @@ require('gfm.css/gfm.css');
require('highlight.js/styles/github.css');
// These are things that can run before the skin loads - be careful not to reference the react-sdk though.
import {parseQsFromFragment} from "./url_utils";
import './modernizr';
// load service worker if available on this platform
@ -40,6 +41,41 @@ async function settled(prom: Promise<any>) {
}
}
function checkBrowserFeatures() {
if (!window.Modernizr) {
console.error("Cannot check features - Modernizr global is missing.");
return false;
}
// custom checks atop Modernizr because it doesn't have ES2018/ES2019 checks in it for some features we depend on,
// Modernizr requires rules to be lowercase with no punctuation:
// ES2018: http://www.ecma-international.org/ecma-262/9.0/#sec-promise.prototype.finally
window.Modernizr.addTest("promiseprototypefinally", () =>
window.Promise && window.Promise.prototype && typeof window.Promise.prototype.finally === "function");
// ES2019: http://www.ecma-international.org/ecma-262/10.0/#sec-object.fromentries
window.Modernizr.addTest("objectfromentries", () =>
window.Object && typeof window.Object.fromEntries === "function");
const featureList = Object.keys(window.Modernizr);
let featureComplete = true;
for (let i = 0; i < featureList.length; i++) {
if (window.Modernizr[featureList[i]] === undefined) {
console.error(
"Looked for feature '%s' but Modernizr has no results for this. " +
"Has it been configured correctly?", featureList[i],
);
return false;
}
if (window.Modernizr[featureList[i]] === false) {
console.error("Browser missing feature: '%s'", featureList[i]);
// toggle flag rather than return early so we log all missing features rather than just the first.
featureComplete = false;
}
}
return featureComplete;
}
// React depends on Map & Set which we check for using modernizr's es6collections
// if modernizr fails we may not have a functional react to show the error message.
// try in react but fallback to an `alert`
@ -52,11 +88,35 @@ async function start() {
await settled(rageshakePromise); // give rageshake a chance to load/fail
const fragparts = parseQsFromFragment(window.location);
// don't try to redirect to the native apps if we're
// verifying a 3pid (but after we've loaded the config)
// or if the user is following a deep link
// (https://github.com/vector-im/riot-web/issues/7378)
const preventRedirect = fragparts.params.client_secret || fragparts.location.length > 0;
if (!preventRedirect) {
const isIos = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
const isAndroid = /Android/.test(navigator.userAgent);
if (isIos || isAndroid) {
if (document.cookie.indexOf("riot_mobile_redirect_to_guide=false") === -1) {
window.location.href = "mobile_guide/";
return;
}
}
}
await loadSkin();
let acceptBrowser = checkBrowserFeatures();
if (!acceptBrowser && window.localStorage) {
acceptBrowser = Boolean(window.localStorage.getItem("mx_accepts_unsupported_browser"));
}
// Finally, load the app. All of the other react-sdk imports are in this file which causes the skinner to
// run on the components. We use `require` here to make sure webpack doesn't optimize this into an async
// import and thus running before the skin can load.
await loadApp();
await loadApp(fragparts.params, acceptBrowser);
}
start();

View file

@ -138,11 +138,12 @@ export async function loadSkin() {
console.log("Skin loaded!");
}
export async function loadApp() {
export async function loadApp(fragParams: {}, acceptBrowser: boolean) {
// load app.js async so that its code is not executed immediately and we can catch any exceptions
const module = await import(
/* webpackChunkName: "riot-web-app" */
/* webpackPreload: true */
"./app");
window.matrixChat = ReactDOM.render(await module.loadApp(), document.getElementById('matrixchat'));
window.matrixChat = ReactDOM.render(await module.loadApp(fragParams, acceptBrowser),
document.getElementById('matrixchat'));
}

View file

@ -32,7 +32,7 @@ export function parseQsFromFragment(location: Location) {
const result = {
location: decodeURIComponent(hashparts[0]),
params: {},
params: <qs.ParsedUrlQuery>{},
};
if (hashparts.length > 1) {

View file

@ -31,7 +31,7 @@ module.exports = (env, argv) => {
...development,
entry: {
"bundle": "./src/vector/index.js",
"bundle": "./src/vector/index.ts",
"indexeddb-worker": "./src/vector/indexeddb-worker.js",
"mobileguide": "./src/vector/mobile_guide/index.js",
"jitsi": "./src/vector/jitsi/index.ts",

View file

@ -1245,6 +1245,11 @@
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
"@types/modernizr@^3.5.3":
version "3.5.3"
resolved "https://registry.yarnpkg.com/@types/modernizr/-/modernizr-3.5.3.tgz#8ef99e6252191c1d88647809109dc29884ba6d7a"
integrity sha512-jhMOZSS0UGYTS9pqvt6q3wtT3uvOSve5piTEmTMx3zzTuBLvSIMxSIBIc3d5lajVD5h4xc41AMZD2M5orN3PxA==
"@types/node@*":
version "13.9.0"
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.9.0.tgz#5b6ee7a77faacddd7de719017d0bc12f52f81589"