Skip to content

Commit

Permalink
Try to, completely, avoid loading the ReadableStream polyfill in MO…
Browse files Browse the repository at this point in the history
…ZCENTRAL builds

With https://bugzilla.mozilla.org/show_bug.cgi?id=1505122 landing in Firefox 65, the native `ReadableStream` implementation is now enabled by default in Firefox.

Obviously it would be nice to simply stop bundling the polyfill in MOZCENTRAL builds altogether, however given that it's still possible to disable[1] `ReadableStream` this is probably not a good idea just yet.
Nonetheless, now that native support is available, it seems unnecessary (and wasteful) to keep bundling the polyfill twice[2] in MOZCENTRAL builds. Hence this patch, which contains a suggest approach for packing the polyfill in a *separate* file which is then *only* loaded if/when needed.

With this patch, the size of the `gulp mozcentral` build target is thus reduced accordingly:

|       | `build/mozcentral`
|-------|-------------------
|master |   3 461 089
|patch  |   3 340 268

Besides the PDF.js files taking up less space in Firefox this way, the additional benefit is that there's (by default) less code that needs to be loaded and parsed when the PDF Viewer is used which also cannot hurt.

---
[1] In `about:config`, by toggling the `javascript.options.streams` preference.

[2] Once in the `build/pdf.js` file, and once in the `build/pdf.worker.js` file.
  • Loading branch information
Snuffleupagus committed Jan 19, 2019
1 parent 1bb5ca0 commit 4801106
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 45 deletions.
19 changes: 19 additions & 0 deletions extensions/firefox/content/streams_polyfill.js
@@ -0,0 +1,19 @@
/* Copyright 2018 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

if (typeof ReadableStream === "undefined") {
require("../../../src/shared/global_scope").ReadableStream =
require("../../../external/streams/streams-lib").ReadableStream;
}
12 changes: 12 additions & 0 deletions gulpfile.js
Expand Up @@ -766,6 +766,16 @@ function preprocessDefaultPreferences(content) {
content + '\n');
}

function createMozcentralStreamsPolyfillBundle(defines) {
var streamsPolyfillOutputName = 'streams_polyfill.js';

var streamsPolyfillFileConfig = createWebpackConfig(defines, {
filename: streamsPolyfillOutputName,
});
return gulp.src('./extensions/firefox/content/streams_polyfill.js')
.pipe(webpack2Stream(streamsPolyfillFileConfig));
}

gulp.task('mozcentral-pre', gulp.series('buildnumber', 'locale', function () {
console.log();
console.log('### Building mozilla-central extension');
Expand All @@ -787,6 +797,8 @@ gulp.task('mozcentral-pre', gulp.series('buildnumber', 'locale', function () {
return merge([
createBundle(defines).pipe(gulp.dest(MOZCENTRAL_CONTENT_DIR + 'build')),
createWebBundle(defines).pipe(gulp.dest(MOZCENTRAL_CONTENT_DIR + 'web')),
createMozcentralStreamsPolyfillBundle(defines)
.pipe(gulp.dest(MOZCENTRAL_CONTENT_DIR + 'build')),
gulp.src(COMMON_WEB_FILES, { base: 'web/', })
.pipe(gulp.dest(MOZCENTRAL_CONTENT_DIR + 'web')),
gulp.src(['external/bcmaps/*.bcmap', 'external/bcmaps/LICENSE'],
Expand Down
12 changes: 8 additions & 4 deletions src/pdf.worker.js
Expand Up @@ -12,13 +12,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* eslint-disable no-unused-vars */
/* eslint-disable no-restricted-globals, no-unused-vars */

'use strict';

var pdfjsVersion = PDFJSDev.eval('BUNDLE_VERSION');
var pdfjsBuild = PDFJSDev.eval('BUNDLE_BUILD');
if (PDFJSDev.test('MOZCENTRAL') && typeof ReadableStream === 'undefined') {
importScripts('./streams_polyfill.js');
}

var pdfjsCoreWorker = require('./core/worker.js');
const pdfjsVersion = PDFJSDev.eval('BUNDLE_VERSION');
const pdfjsBuild = PDFJSDev.eval('BUNDLE_BUILD');

const pdfjsCoreWorker = require('./core/worker.js');

exports.WorkerMessageHandler = pdfjsCoreWorker.WorkerMessageHandler;
41 changes: 24 additions & 17 deletions src/shared/streams_polyfill.js
Expand Up @@ -14,25 +14,32 @@
*/
/* eslint-disable no-restricted-globals */

let isReadableStreamSupported = false;
if (typeof ReadableStream !== 'undefined') {
// MS Edge may say it has ReadableStream but they are not up to spec yet.
try {
// eslint-disable-next-line no-new
new ReadableStream({
start(controller) {
controller.close();
},
});
isReadableStreamSupported = true;
} catch (e) {
// The ReadableStream constructor cannot be used.
}
}
if (isReadableStreamSupported) {
if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('MOZCENTRAL')) {
// On the main-thread the `streams_polyfill.js` file is loaded using a
// <script> tag; see `web/viewer-snippet-firefox-extension.html`.
// On the worker-thread the `streams_polyfill.js` file is (conditionally)
// loaded using `importScripts`; see `src/pdf.worker.js`.
exports.ReadableStream = ReadableStream;
} else {
if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('IMAGE_DECODERS')) {
let isReadableStreamSupported = false;
if (typeof ReadableStream !== 'undefined') {
// MS Edge may say it has ReadableStream but they are not up to spec yet.
try {
// eslint-disable-next-line no-new
new ReadableStream({
start(controller) {
controller.close();
},
});
isReadableStreamSupported = true;
} catch (e) {
// The ReadableStream constructor cannot be used.
}
}
if (isReadableStreamSupported) {
exports.ReadableStream = ReadableStream;
} else if (typeof PDFJSDev !== 'undefined' &&
PDFJSDev.test('IMAGE_DECODERS')) {
class DummyReadableStream {
constructor() {
throw new Error('The current image decoders are synchronous, ' +
Expand Down
47 changes: 23 additions & 24 deletions src/shared/url_polyfill.js
Expand Up @@ -32,32 +32,31 @@ if (typeof PDFJSDev !== 'undefined' && !PDFJSDev.test('GENERIC')) {

if (isURLSupported) {
exports.URL = URL;
} else {
if (typeof PDFJSDev !== 'undefined' && PDFJSDev.test('IMAGE_DECODERS')) {
class DummyURL {
constructor() {
throw new Error('The current image decoders doesn\'t utilize the ' +
'`URL` constructor, hence it shouldn\'t need to be ' +
'polyfilled for the IMAGE_DECODERS build target.');
}
} else if (typeof PDFJSDev !== 'undefined' &&
PDFJSDev.test('IMAGE_DECODERS')) {
class DummyURL {
constructor() {
throw new Error('The current image decoders doesn\'t utilize the ' +
'`URL` constructor, hence it shouldn\'t need to be ' +
'polyfilled for the IMAGE_DECODERS build target.');
}
exports.URL = DummyURL;
} else {
const PolyfillURL = require('../../external/url/url-lib').URL;
}
exports.URL = DummyURL;
} else {
const PolyfillURL = require('../../external/url/url-lib').URL;

// Attempt to copy over the static methods.
const OriginalURL = require('./global_scope').URL;
if (OriginalURL) {
PolyfillURL.createObjectURL = function(blob) {
// IE extension allows a second optional options argument, see
// http://msdn.microsoft.com/en-us/library/ie/hh772302(v=vs.85).aspx
return OriginalURL.createObjectURL.apply(OriginalURL, arguments);
};
PolyfillURL.revokeObjectURL = function(url) {
OriginalURL.revokeObjectURL(url);
};
}
exports.URL = PolyfillURL;
// Attempt to copy over the static methods.
const OriginalURL = require('./global_scope').URL;
if (OriginalURL) {
PolyfillURL.createObjectURL = function(blob) {
// IE extension allows a second optional options argument, see
// http://msdn.microsoft.com/en-us/library/ie/hh772302(v=vs.85).aspx
return OriginalURL.createObjectURL.apply(OriginalURL, arguments);
};
PolyfillURL.revokeObjectURL = function(url) {
OriginalURL.revokeObjectURL(url);
};
}
exports.URL = PolyfillURL;
}
}
7 changes: 7 additions & 0 deletions web/viewer-snippet-firefox-extension.html
@@ -1,3 +1,10 @@
<!-- This snippet is used in the Firefox extension (included from viewer.html) -->
<base href="resource://pdf.js/web/">
<script>
(function() {
if (typeof ReadableStream === "undefined") {
document.write("<script src=\"../build/streams_polyfill.js\"><\/script>");
}
})();
</script>
<script src="../build/pdf.js"></script>

0 comments on commit 4801106

Please sign in to comment.