mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-07-05 10:38:30 +00:00
More webpack 4 code. Make sure to asynchronously await the availability of our webpack hook everywhere that we use it that it's reasonable to wait.
This adds a new module called switchboard that abuses the root React Router instance to forcibly load a chunk, letting us grab `require()` quickly rather than waiting potentially forever for another chunk to be loaded due to user action, etc.
This commit is contained in:
parent
194f93414d
commit
86c5fee033
13 changed files with 128 additions and 24 deletions
|
@ -1,3 +1,8 @@
|
||||||
|
<div class="list-header">4.0.0-rc1.8<span>@498c1b079484a762958a</span> <time datetime="2018-05-18">(2018-05-18)</time></div>
|
||||||
|
<ul class="chat-menu-content menu-side-padding">
|
||||||
|
<li>Changed: Finish writing support for webpack 4 support.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<div class="list-header">4.0.0-rc1.7<span>@498c1b079484a762958a</span> <time datetime="2018-05-18">(2018-05-18)</time></div>
|
<div class="list-header">4.0.0-rc1.7<span>@498c1b079484a762958a</span> <time datetime="2018-05-18">(2018-05-18)</time></div>
|
||||||
<ul class="chat-menu-content menu-side-padding">
|
<ul class="chat-menu-content menu-side-padding">
|
||||||
<li>Changed: Rewrite the webpack hooking code to add support for webpack 4.</li>
|
<li>Changed: Rewrite the webpack hooking code to add support for webpack 4.</li>
|
||||||
|
|
|
@ -100,7 +100,7 @@ class FrankerFaceZ extends Module {
|
||||||
FrankerFaceZ.Logger = Logger;
|
FrankerFaceZ.Logger = Logger;
|
||||||
|
|
||||||
const VER = FrankerFaceZ.version_info = {
|
const VER = FrankerFaceZ.version_info = {
|
||||||
major: 4, minor: 0, revision: 0, extra: '-rc1.7',
|
major: 4, minor: 0, revision: 0, extra: '-rc1.8',
|
||||||
build: __webpack_hash__,
|
build: __webpack_hash__,
|
||||||
toString: () =>
|
toString: () =>
|
||||||
`${VER.major}.${VER.minor}.${VER.revision}${VER.extra || ''}${DEBUG ? '-dev' : ''}`
|
`${VER.major}.${VER.minor}.${VER.revision}${VER.extra || ''}${DEBUG ? '-dev' : ''}`
|
||||||
|
|
|
@ -11,6 +11,8 @@ import Fine from 'utilities/compat/fine';
|
||||||
import FineRouter from 'utilities/compat/fine-router';
|
import FineRouter from 'utilities/compat/fine-router';
|
||||||
import Apollo from 'utilities/compat/apollo';
|
import Apollo from 'utilities/compat/apollo';
|
||||||
|
|
||||||
|
import Switchboard from './switchboard';
|
||||||
|
|
||||||
import {createElement} from 'utilities/dom';
|
import {createElement} from 'utilities/dom';
|
||||||
import {has} from 'utilities/object';
|
import {has} from 'utilities/object';
|
||||||
|
|
||||||
|
@ -28,7 +30,8 @@ export default class Twilight extends BaseSite {
|
||||||
this.inject(WebMunch);
|
this.inject(WebMunch);
|
||||||
this.inject(Fine);
|
this.inject(Fine);
|
||||||
this.inject('router', FineRouter);
|
this.inject('router', FineRouter);
|
||||||
this.inject(Apollo);
|
this.inject(Apollo, false);
|
||||||
|
this.inject(Switchboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoad() {
|
onLoad() {
|
||||||
|
|
|
@ -197,7 +197,7 @@ export default class EmoteMenu extends Module {
|
||||||
//this.MenuEmote = this.fine.wrap('ffz-menu-emote');
|
//this.MenuEmote = this.fine.wrap('ffz-menu-emote');
|
||||||
}
|
}
|
||||||
|
|
||||||
onEnable() {
|
async onEnable() {
|
||||||
this.on('i18n:update', () => this.EmoteMenu.forceUpdate());
|
this.on('i18n:update', () => this.EmoteMenu.forceUpdate());
|
||||||
this.on('chat.emotes:update-default-sets', this.maybeUpdate, this);
|
this.on('chat.emotes:update-default-sets', this.maybeUpdate, this);
|
||||||
this.on('chat.emotes:update-user-sets', this.maybeUpdate, this);
|
this.on('chat.emotes:update-user-sets', this.maybeUpdate, this);
|
||||||
|
@ -228,7 +228,7 @@ export default class EmoteMenu extends Module {
|
||||||
this.css_tweaks.toggle('emote-menu', this.chat.context.get('chat.emote-menu.icon'));
|
this.css_tweaks.toggle('emote-menu', this.chat.context.get('chat.emote-menu.icon'));
|
||||||
|
|
||||||
const t = this,
|
const t = this,
|
||||||
React = this.web_munch.getModule('react'),
|
React = await this.web_munch.findModule('react'),
|
||||||
createElement = React && React.createElement;
|
createElement = React && React.createElement;
|
||||||
|
|
||||||
if ( ! createElement )
|
if ( ! createElement )
|
||||||
|
|
|
@ -329,8 +329,8 @@ export default class ChatHook extends Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
grabTypes() {
|
async grabTypes() {
|
||||||
const ct = this.web_munch.getModule('chat-types');
|
const ct = await this.web_munch.findModule('chat-types');
|
||||||
|
|
||||||
this.automod_types = ct && ct.a || AUTOMOD_TYPES;
|
this.automod_types = ct && ct.a || AUTOMOD_TYPES;
|
||||||
this.chat_types = ct && ct.b || CHAT_TYPES;
|
this.chat_types = ct && ct.b || CHAT_TYPES;
|
||||||
|
|
|
@ -25,7 +25,6 @@ export default class ChatLine extends Module {
|
||||||
this.inject('site');
|
this.inject('site');
|
||||||
this.inject('site.fine');
|
this.inject('site.fine');
|
||||||
this.inject('site.web_munch');
|
this.inject('site.web_munch');
|
||||||
this.inject('site.apollo');
|
|
||||||
this.inject(RichContent);
|
this.inject(RichContent);
|
||||||
|
|
||||||
this.inject('viewer_cards');
|
this.inject('viewer_cards');
|
||||||
|
@ -45,7 +44,7 @@ export default class ChatLine extends Module {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
onEnable() {
|
async onEnable() {
|
||||||
this.chat.context.on('changed:chat.emoji.style', this.updateLines, this);
|
this.chat.context.on('changed:chat.emoji.style', this.updateLines, this);
|
||||||
this.chat.context.on('changed:chat.bits.stack', this.updateLines, this);
|
this.chat.context.on('changed:chat.bits.stack', this.updateLines, this);
|
||||||
this.chat.context.on('changed:chat.badges.style', this.updateLines, this);
|
this.chat.context.on('changed:chat.badges.style', this.updateLines, this);
|
||||||
|
@ -57,7 +56,7 @@ export default class ChatLine extends Module {
|
||||||
this.chat.context.on('changed:chat.actions.inline', this.updateLines, this);
|
this.chat.context.on('changed:chat.actions.inline', this.updateLines, this);
|
||||||
|
|
||||||
const t = this,
|
const t = this,
|
||||||
React = this.web_munch.getModule('react');
|
React = await this.web_munch.findModule('react');
|
||||||
if ( ! React )
|
if ( ! React )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,9 @@ export default class RichContent extends Module {
|
||||||
this.RichContent = null;
|
this.RichContent = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
onEnable() {
|
async onEnable() {
|
||||||
const t = this,
|
const t = this,
|
||||||
React = this.web_munch.getModule('react');
|
React = await this.web_munch.findModule('react');
|
||||||
if ( ! React )
|
if ( ! React )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -24,11 +24,11 @@ export default class SettingsMenu extends Module {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
onEnable() {
|
async onEnable() {
|
||||||
this.on('i18n:update', () => this.SettingsMenu.forceUpdate());
|
this.on('i18n:update', () => this.SettingsMenu.forceUpdate());
|
||||||
|
|
||||||
const t = this,
|
const t = this,
|
||||||
React = this.web_munch.getModule('react');
|
React = await this.web_munch.findModule('react');
|
||||||
if ( ! React )
|
if ( ! React )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -58,8 +58,8 @@ export default class TabCompletion extends Module {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
onEnable() {
|
async onEnable() {
|
||||||
const React = this.web_munch.getModule('react'),
|
const React = await this.web_munch.findModule('react'),
|
||||||
createElement = React && React.createElement;
|
createElement = React && React.createElement;
|
||||||
|
|
||||||
if ( ! createElement )
|
if ( ! createElement )
|
||||||
|
|
93
src/sites/twitch-twilight/switchboard.js
Normal file
93
src/sites/twitch-twilight/switchboard.js
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Switchboard
|
||||||
|
// A hack for React Router to make it load a module.
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
import Module from 'utilities/module';
|
||||||
|
|
||||||
|
|
||||||
|
export default class Switchboard extends Module {
|
||||||
|
constructor(...args) {
|
||||||
|
super(...args);
|
||||||
|
|
||||||
|
this.inject('site.web_munch');
|
||||||
|
this.inject('site.fine');
|
||||||
|
|
||||||
|
this.RootRouter = this.fine.define(
|
||||||
|
'root-router',
|
||||||
|
n => n && n.logger && n.logger.category === 'default-root-router'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
awaitRouter() {
|
||||||
|
const router = this.RootRouter.first;
|
||||||
|
if ( router )
|
||||||
|
return Promise.resolve(router);
|
||||||
|
|
||||||
|
return new Promise(resolve => {
|
||||||
|
this.RootRouter.ready(() => resolve(this.RootRouter.first))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async onEnable() {
|
||||||
|
const router = await this.awaitRouter(),
|
||||||
|
child = router && this.fine.getFirstChild(router),
|
||||||
|
da_switch = child && child.stateNode;
|
||||||
|
|
||||||
|
if ( this.web_munch.v4 === false )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( ! da_switch )
|
||||||
|
return new Promise(r => setTimeout(r, 50)).then(() => this.onEnable());
|
||||||
|
|
||||||
|
const real_context = da_switch.context,
|
||||||
|
on_settings = real_context.router.route.location.pathname.includes('settings');
|
||||||
|
|
||||||
|
let output;
|
||||||
|
|
||||||
|
try {
|
||||||
|
da_switch.context = {
|
||||||
|
router: {
|
||||||
|
route: {
|
||||||
|
location: {
|
||||||
|
pathname: on_settings ? '/inventory' : '/settings'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
output = da_switch.render();
|
||||||
|
|
||||||
|
} catch(err) {
|
||||||
|
this.log.error('Error forcing router to render another page.', err);
|
||||||
|
da_switch.context = real_context;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
da_switch.context = real_context;
|
||||||
|
|
||||||
|
if ( ! output || ! output.props || ! output.props.component )
|
||||||
|
return this.log.warn('Unexpected output from router render.');
|
||||||
|
|
||||||
|
let component;
|
||||||
|
|
||||||
|
try {
|
||||||
|
component = new output.props.component;
|
||||||
|
} catch(err) {
|
||||||
|
this.log.error('Error instantiating component for forced loading of another chunk.', err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
component.props.children.props.loader().then(() => {
|
||||||
|
this.log.info('Successfully forced a chunk to load.');
|
||||||
|
});
|
||||||
|
} catch(err) {
|
||||||
|
this.log.warn('Unexpected result trying to use component loader to force loading of another chunk.', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -52,7 +52,7 @@ export default class Apollo extends Module {
|
||||||
this.inject('..fine');
|
this.inject('..fine');
|
||||||
}
|
}
|
||||||
|
|
||||||
onEnable() {
|
async onEnable() {
|
||||||
// TODO: Come up with a better way to await something existing.
|
// TODO: Come up with a better way to await something existing.
|
||||||
let client = this.client;
|
let client = this.client;
|
||||||
|
|
||||||
|
@ -63,11 +63,11 @@ export default class Apollo extends Module {
|
||||||
client = this.client = inst && inst.props && inst.props.client;
|
client = this.client = inst && inst.props && inst.props.client;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.printer = this.web_munch.getModule('gql-printer');
|
|
||||||
this.gql_print = this.printer && this.printer.print;
|
|
||||||
|
|
||||||
if ( ! client )
|
if ( ! client )
|
||||||
return new Promise(s => setTimeout(s,50)).then(() => this.onEnable());
|
return new Promise(() => this.onEnable(), 50);
|
||||||
|
|
||||||
|
this.printer = await this.web_munch.findModule('gql-printer');
|
||||||
|
this.gql_print = this.printer && this.printer.print;
|
||||||
|
|
||||||
// Register middleware so that we can intercept requests.
|
// Register middleware so that we can intercept requests.
|
||||||
if ( ! this.client.link || ! this.client.queryManager || ! this.client.queryManager.link ) {
|
if ( ! this.client.link || ! this.client.queryManager || ! this.client.queryManager.link ) {
|
||||||
|
|
|
@ -23,7 +23,7 @@ export default class WebMunch extends Module {
|
||||||
this._module_names = {};
|
this._module_names = {};
|
||||||
this._mod_cache = {};
|
this._mod_cache = {};
|
||||||
|
|
||||||
this.v4 = false;
|
this.v4 = null;
|
||||||
|
|
||||||
this.hookLoader();
|
this.hookLoader();
|
||||||
this.hookRequire();
|
this.hookRequire();
|
||||||
|
@ -47,7 +47,9 @@ export default class WebMunch extends Module {
|
||||||
|
|
||||||
if ( typeof window.webpackJsonp === 'function' ) {
|
if ( typeof window.webpackJsonp === 'function' ) {
|
||||||
// v3
|
// v3
|
||||||
|
this.v4 = false;
|
||||||
this._original_loader = window.webpackJsonp;
|
this._original_loader = window.webpackJsonp;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
window.webpackJsonp = this.webpackJsonpv3.bind(this);
|
window.webpackJsonp = this.webpackJsonpv3.bind(this);
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
|
@ -249,7 +251,7 @@ export default class WebMunch extends Module {
|
||||||
const loader = require.e && require.e.toString();
|
const loader = require.e && require.e.toString();
|
||||||
let modules;
|
let modules;
|
||||||
if ( loader && loader.indexOf('Loading chunk') !== -1 ) {
|
if ( loader && loader.indexOf('Loading chunk') !== -1 ) {
|
||||||
const data = /({0:.*?})/.exec(loader);
|
const data = this.v4 ? /assets\/"\+\(({1:.*?})/.exec(loader) : /({0:.*?})/.exec(loader);
|
||||||
if ( data )
|
if ( data )
|
||||||
try {
|
try {
|
||||||
modules = JSON.parse(data[1].replace(/(\d+):/g, '"$1":'))
|
modules = JSON.parse(data[1].replace(/(\d+):/g, '"$1":'))
|
||||||
|
|
|
@ -402,8 +402,9 @@ export class Module extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inject(name, module) {
|
inject(name, module, require = true) {
|
||||||
if ( name instanceof Module || name.prototype instanceof Module ) {
|
if ( name instanceof Module || name.prototype instanceof Module ) {
|
||||||
|
require = module != null ? module : true;
|
||||||
module = name;
|
module = name;
|
||||||
name = null;
|
name = null;
|
||||||
}
|
}
|
||||||
|
@ -447,7 +448,8 @@ export class Module extends EventEmitter {
|
||||||
if ( ! module )
|
if ( ! module )
|
||||||
throw new Error(`cannot find module ${name} or no module provided`);
|
throw new Error(`cannot find module ${name} or no module provided`);
|
||||||
|
|
||||||
requires.push(module.abs_path('.'));
|
if ( require )
|
||||||
|
requires.push(module.abs_path('.'));
|
||||||
|
|
||||||
if ( this.enabled && ! module.enabled )
|
if ( this.enabled && ! module.enabled )
|
||||||
module.enable();
|
module.enable();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue