-
-
Notifications
You must be signed in to change notification settings - Fork 735
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor RTL plugin loading code (#3418)
* Initial commit to split rtl to worker and main thread implementations. * Finish all fixes for rtl plugin split * Fix the tests that fail, add proper idle event handling * Changelog, lint, build and render * Improve render test * Fix changelog, add idle console logging * Return a promise from the public API * Add more logs to tests * More logs, more timeout * Fix lint * Clean error for failed tests * Fix typo
- Loading branch information
Showing
33 changed files
with
333 additions
and
334 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import {FakeServer, fakeServer} from 'nise'; | ||
import {rtlMainThreadPluginFactory} from './rtl_text_plugin_main_thread'; | ||
import {sleep} from '../util/test/util'; | ||
import {browser} from '../util/browser'; | ||
|
||
const rtlMainThreadPlugin = rtlMainThreadPluginFactory(); | ||
|
||
describe('RTLMainThreadPlugin', () => { | ||
let server: FakeServer; | ||
let broadcastSpy: jest.SpyInstance; | ||
beforeEach(() => { | ||
server = fakeServer.create(); | ||
global.fetch = null; | ||
// Reset the singleton instance before each test | ||
rtlMainThreadPlugin.clearRTLTextPlugin(); | ||
broadcastSpy = jest.spyOn(rtlMainThreadPlugin.dispatcher, 'broadcast').mockImplementation(() => { return Promise.resolve({} as any); }); | ||
}); | ||
|
||
afterEach(() => { | ||
server.restore(); | ||
broadcastSpy.mockRestore(); | ||
}); | ||
|
||
it('should get the RTL text plugin status', () => { | ||
const status = rtlMainThreadPlugin.getRTLTextPluginStatus(); | ||
expect(status).toBe('unavailable'); | ||
}); | ||
|
||
it('should set the RTL text plugin and download it', async () => { | ||
const url = 'http://example.com/plugin'; | ||
server.respondWith(new ArrayBuffer(0)); | ||
|
||
const promise = rtlMainThreadPlugin.setRTLTextPlugin(url); | ||
await sleep(0); | ||
server.respond(); | ||
await promise; | ||
expect(rtlMainThreadPlugin.pluginURL).toEqual(url); | ||
}); | ||
|
||
it('should set the RTL text plugin but deffer downloading', async () => { | ||
const url = 'http://example.com/plugin'; | ||
await rtlMainThreadPlugin.setRTLTextPlugin(url, true); | ||
expect(server.requests).toHaveLength(0); | ||
expect(rtlMainThreadPlugin.pluginStatus).toBe('deferred'); | ||
}); | ||
|
||
it('should throw if the plugin is already set', async () => { | ||
const url = 'http://example.com/plugin'; | ||
await rtlMainThreadPlugin.setRTLTextPlugin(url, true); | ||
await expect(rtlMainThreadPlugin.setRTLTextPlugin(url)).rejects.toThrow('setRTLTextPlugin cannot be called multiple times.'); | ||
}); | ||
|
||
it('should throw if the plugin url is not set', async () => { | ||
const spy = jest.spyOn(browser, 'resolveURL').mockImplementation(() => { return ''; }); | ||
await expect(rtlMainThreadPlugin.setRTLTextPlugin(null)).rejects.toThrow('rtl-text-plugin cannot be downloaded unless a pluginURL is specified'); | ||
spy.mockRestore(); | ||
}); | ||
|
||
it('should be in error state if download fails', async () => { | ||
const url = 'http://example.com/plugin'; | ||
server.respondWith(request => request.respond(404)); | ||
const promise = rtlMainThreadPlugin.setRTLTextPlugin(url); | ||
await sleep(0); | ||
server.respond(); | ||
await promise; | ||
expect(rtlMainThreadPlugin.pluginURL).toEqual(url); | ||
expect(rtlMainThreadPlugin.pluginStatus).toBe('error'); | ||
}); | ||
|
||
it('should lazy load the plugin if deffered', async () => { | ||
const url = 'http://example.com/plugin'; | ||
server.respondWith(new ArrayBuffer(0)); | ||
await rtlMainThreadPlugin.setRTLTextPlugin(url, true); | ||
expect(server.requests).toHaveLength(0); | ||
expect(rtlMainThreadPlugin.pluginStatus).toBe('deferred'); | ||
const promise = rtlMainThreadPlugin.lazyLoadRTLTextPlugin(); | ||
await sleep(0); | ||
server.respond(); | ||
await promise; | ||
expect(rtlMainThreadPlugin.pluginStatus).toBe('loaded'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import {getArrayBuffer} from '../util/ajax'; | ||
import {browser} from '../util/browser'; | ||
import {Event, Evented} from '../util/evented'; | ||
import {RTLPluginStatus, PluginState} from './rtl_text_plugin_status'; | ||
import {Dispatcher} from '../util/dispatcher'; | ||
import {getGlobalWorkerPool} from '../util/global_worker_pool'; | ||
|
||
class RTLMainThreadPlugin extends Evented { | ||
pluginStatus: RTLPluginStatus = 'unavailable'; | ||
pluginURL: string = null; | ||
dispatcher: Dispatcher = new Dispatcher(getGlobalWorkerPool(), 'rtl-text-plugin-dispacher'); | ||
queue: PluginState[] = []; | ||
|
||
async _sendPluginStateToWorker() { | ||
await this.dispatcher.broadcast('syncRTLPluginState', {pluginStatus: this.pluginStatus, pluginURL: this.pluginURL}); | ||
this.fire(new Event('pluginStateChange', {pluginStatus: this.pluginStatus, pluginURL: this.pluginURL})); | ||
} | ||
|
||
getRTLTextPluginStatus() { | ||
return this.pluginStatus; | ||
} | ||
|
||
clearRTLTextPlugin() { | ||
this.pluginStatus = 'unavailable'; | ||
this.pluginURL = null; | ||
} | ||
|
||
async setRTLTextPlugin(url: string, deferred: boolean = false): Promise<void> { | ||
if (this.pluginStatus === 'deferred' || this.pluginStatus === 'loading' || this.pluginStatus === 'loaded') { | ||
throw new Error('setRTLTextPlugin cannot be called multiple times.'); | ||
} | ||
this.pluginURL = browser.resolveURL(url); | ||
this.pluginStatus = 'deferred'; | ||
await this._sendPluginStateToWorker(); | ||
if (!deferred) { | ||
//Start downloading the plugin immediately if not intending to lazy-load | ||
await this._downloadRTLTextPlugin(); | ||
} | ||
} | ||
|
||
async _downloadRTLTextPlugin() { | ||
if (this.pluginStatus !== 'deferred' || !this.pluginURL) { | ||
throw new Error('rtl-text-plugin cannot be downloaded unless a pluginURL is specified'); | ||
} | ||
try { | ||
this.pluginStatus = 'loading'; | ||
await this._sendPluginStateToWorker(); | ||
await getArrayBuffer({url: this.pluginURL}, new AbortController()); | ||
this.pluginStatus = 'loaded'; | ||
} catch { | ||
this.pluginStatus = 'error'; | ||
} | ||
await this._sendPluginStateToWorker(); | ||
} | ||
|
||
async lazyLoadRTLTextPlugin() { | ||
if (this.pluginStatus === 'deferred') { | ||
await this._downloadRTLTextPlugin(); | ||
} | ||
} | ||
} | ||
|
||
let rtlMainThreadPlugin: RTLMainThreadPlugin = null; | ||
|
||
export function rtlMainThreadPluginFactory(): RTLMainThreadPlugin { | ||
if (!rtlMainThreadPlugin) { | ||
rtlMainThreadPlugin = new RTLMainThreadPlugin(); | ||
} | ||
return rtlMainThreadPlugin; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
/** | ||
* The possible option of the plugin's status | ||
* | ||
* `unavailable`: Not loaded. | ||
* | ||
* `deferred`: The plugin URL has been specified, but loading has been deferred. | ||
* | ||
* `loading`: request in-flight. | ||
* | ||
* `loaded`: The plugin is now loaded | ||
* | ||
* `error`: The plugin failed to load | ||
*/ | ||
export type RTLPluginStatus = 'unavailable' | 'deferred' | 'loading' | 'loaded' | 'error'; | ||
|
||
/** | ||
* The RTL plugin state | ||
*/ | ||
export type PluginState = { | ||
pluginStatus: RTLPluginStatus; | ||
pluginURL: string; | ||
}; |
Oops, something went wrong.