forked from external-repos/squoosh
Bundle URL assets as dependencies
I've added support for `new URL(..., import.meta.url)` pattern accepted by many bundlers to wasm-bindgen and Emscripten, both for Wasm files as well as for side Workers autogenerated to support multithreading. On the apps side like Squoosh this means we no longer have to manually specify URLs to be passed to wasm-bindgen or Emscripten init functions. In this PR I'm primarily doing just that - removing all the manual Wasm URL locators, as well as the associated logic. One notable change on the build system side is that, in order for Wasm and multithreading-related Workers to be detected as dependencies, I'm now walking over `referencedFiles` in addition to `imports` when collecting list of dependencies in `getDependencies` function (client-bundle-plugin.js). As a side effect, it also included other linked assets - images and CSS - which simplified quite a few caching lists in to-cache.ts as well. Instead of having to manually specify each asset that needs to be included, the logic is inverted and only few extra assets had to be excluded to keep the list of in items cached on the first load as low as it was before the change. All in all, I think this simplification is worth it and even helped to accidentally uncover & fix one caching bug where WP2 regular JS was cached in addition to WP2 multithreaded JS simultaneously.
This commit is contained in:
committed by
Ingvar Stepanyan
parent
d63823d196
commit
687cf5aae2
@@ -20,6 +20,7 @@ const allSrcPlaceholder = 'CLIENT_BUNDLE_PLUGIN_ALL_SRC';
|
||||
|
||||
export function getDependencies(clientOutput, item) {
|
||||
const crawlDependencies = new Set([item.fileName]);
|
||||
const referencedFiles = new Set();
|
||||
|
||||
for (const fileName of crawlDependencies) {
|
||||
const chunk = clientOutput.find((v) => v.fileName === fileName);
|
||||
@@ -27,11 +28,23 @@ export function getDependencies(clientOutput, item) {
|
||||
for (const dep of chunk.imports) {
|
||||
crawlDependencies.add(dep);
|
||||
}
|
||||
|
||||
for (const dep of chunk.referencedFiles) {
|
||||
referencedFiles.add(dep);
|
||||
}
|
||||
}
|
||||
|
||||
// Don't add self as dependency
|
||||
crawlDependencies.delete(item.fileName);
|
||||
|
||||
// Merge referencedFiles as regular deps.
|
||||
//
|
||||
// Didn't do this as part of the main loop since their `chunk` can't have
|
||||
// nested deps and sometimes might be missing altogether, depending on type.
|
||||
for (const dep of referencedFiles) {
|
||||
crawlDependencies.add(dep);
|
||||
}
|
||||
|
||||
return [...crawlDependencies];
|
||||
}
|
||||
|
||||
@@ -139,9 +152,9 @@ export default function (inputOptions, outputOptions, resolveFileUrl) {
|
||||
if (property.startsWith(allSrcPlaceholder)) {
|
||||
const allModules = [
|
||||
clientEntry,
|
||||
...dependencies.map((name) =>
|
||||
clientOutput.find((item) => item.fileName === name),
|
||||
),
|
||||
...dependencies
|
||||
.map((name) => clientOutput.find((item) => item.fileName === name))
|
||||
.filter((item) => item.code),
|
||||
];
|
||||
|
||||
const inlineDefines = [
|
||||
|
||||
@@ -17,10 +17,14 @@ const prefix = 'entry-data:';
|
||||
const mainNamePlaceholder = 'ENTRY_DATA_PLUGIN_MAIN_NAME';
|
||||
const dependenciesPlaceholder = 'ENTRY_DATA_PLUGIN_DEPS';
|
||||
const placeholderRe = /(ENTRY_DATA_PLUGIN_(?:MAIN_NAME|DEPS))(\d+)/g;
|
||||
const filenamePrefix = 'static/';
|
||||
|
||||
/** @param {string} fileName */
|
||||
export function fileNameToURL(fileName) {
|
||||
return fileName.replace(/^static\//, '/');
|
||||
}
|
||||
|
||||
export default function entryDataPlugin() {
|
||||
/** @type {string} */
|
||||
/** @type {number} */
|
||||
let exportCounter;
|
||||
/** @type {Map<number, string>} */
|
||||
let counterToIdMap;
|
||||
@@ -69,15 +73,11 @@ export default function entryDataPlugin() {
|
||||
if (!chunk) throw Error(`Cannot find ${id}`);
|
||||
|
||||
if (placeholder === mainNamePlaceholder) {
|
||||
return JSON.stringify(
|
||||
chunk.fileName.slice(filenamePrefix.length),
|
||||
);
|
||||
return JSON.stringify(fileNameToURL(chunk.fileName));
|
||||
}
|
||||
|
||||
return JSON.stringify(
|
||||
getDependencies(chunks, chunk).map((item) =>
|
||||
item.slice(filenamePrefix.length),
|
||||
),
|
||||
getDependencies(chunks, chunk).map(fileNameToURL),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
5
missing-types.d.ts
vendored
5
missing-types.d.ts
vendored
@@ -44,6 +44,11 @@ declare module 'data-url:*' {
|
||||
export default url;
|
||||
}
|
||||
|
||||
declare module 'service-worker:*' {
|
||||
const url: string;
|
||||
export default url;
|
||||
}
|
||||
|
||||
declare var ga: {
|
||||
(...args: any[]): void;
|
||||
q: any[];
|
||||
|
||||
12
package-lock.json
generated
12
package-lock.json
generated
@@ -179,9 +179,9 @@
|
||||
}
|
||||
},
|
||||
"@surma/rollup-plugin-off-main-thread": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.1.tgz",
|
||||
"integrity": "sha512-7OU8wfyv18YPWVmecg2/0Jh+pm3lQbvPhIWHd1YQpoxPKPW/vsDNGBaCnMKsZbz29RjgCoXKugAjyagPncgdEw==",
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.2.tgz",
|
||||
"integrity": "sha512-dOD6nGZ79RmWKDRQuC7SOGXMvDkkLwBogu+epfVFMKiy2kOUtLZkb8wV/ettuMt37YJAJKYCKUmxSbZL2LkUQg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ejs": "^3.1.6",
|
||||
@@ -7183,9 +7183,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"wasm-feature-detect": {
|
||||
"version": "1.2.9",
|
||||
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.2.9.tgz",
|
||||
"integrity": "sha512-2E9/gtLVLpv2wnZDyYv8WY2dR9gHbmyv5uhZsnOcMSzqc78aGZpKQORPNcnrPwAU23nFUo7GAwKuoTAWRgsJ7Q=="
|
||||
"version": "1.2.11",
|
||||
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.2.11.tgz",
|
||||
"integrity": "sha512-HUqwaodrQGaZgz1lZaNioIkog9tkeEJjrM3eq4aUL04whXOVDRc/o2EGb/8kV0QX411iAYWEqq7fMBmJ6dKS6w=="
|
||||
},
|
||||
"which": {
|
||||
"version": "2.0.2",
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"@rollup/plugin-commonjs": "^17.0.0",
|
||||
"@rollup/plugin-node-resolve": "^11.1.0",
|
||||
"@rollup/plugin-replace": "^2.3.4",
|
||||
"@surma/rollup-plugin-off-main-thread": "^2.2.1",
|
||||
"@surma/rollup-plugin-off-main-thread": "^2.2.2",
|
||||
"@types/dedent": "^0.7.0",
|
||||
"@types/mime-types": "^2.1.0",
|
||||
"@types/node": "^14.14.7",
|
||||
@@ -58,6 +58,6 @@
|
||||
"*.rs": "rustfmt"
|
||||
},
|
||||
"dependencies": {
|
||||
"wasm-feature-detect": "^1.2.9"
|
||||
"wasm-feature-detect": "^1.2.11"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import commonjs from '@rollup/plugin-commonjs';
|
||||
import { terser } from 'rollup-plugin-terser';
|
||||
import OMT from '@surma/rollup-plugin-off-main-thread';
|
||||
import replace from '@rollup/plugin-replace';
|
||||
import { importMetaAssets } from '@web/rollup-plugin-import-meta-assets';
|
||||
|
||||
import simpleTS from './lib/simple-ts';
|
||||
import clientBundlePlugin from './lib/client-bundle-plugin';
|
||||
@@ -31,10 +32,10 @@ import featurePlugin from './lib/feature-plugin';
|
||||
import initialCssPlugin from './lib/initial-css-plugin';
|
||||
import serviceWorkerPlugin from './lib/sw-plugin';
|
||||
import dataURLPlugin from './lib/data-url-plugin';
|
||||
import entryDataPlugin from './lib/entry-data-plugin';
|
||||
import entryDataPlugin, { fileNameToURL } from './lib/entry-data-plugin';
|
||||
|
||||
function resolveFileUrl({ fileName }) {
|
||||
return JSON.stringify(fileName.replace(/^static\//, '/'));
|
||||
return JSON.stringify(fileNameToURL(fileName));
|
||||
}
|
||||
|
||||
const dir = '.tmp/build';
|
||||
@@ -106,6 +107,7 @@ export default async function ({ watch }) {
|
||||
plugins: [
|
||||
{ resolveFileUrl },
|
||||
OMT({ loader: await omtLoaderPromise }),
|
||||
importMetaAssets(),
|
||||
serviceWorkerPlugin({
|
||||
output: 'static/serviceworker.js',
|
||||
}),
|
||||
|
||||
5
src/client/missing-types.d.ts
vendored
5
src/client/missing-types.d.ts
vendored
@@ -19,9 +19,4 @@ interface Navigator {
|
||||
|
||||
declare module 'add-css:*' {}
|
||||
|
||||
declare module 'service-worker:*' {
|
||||
const url: string;
|
||||
export default url;
|
||||
}
|
||||
|
||||
declare module 'preact/debug' {}
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import type { AVIFModule } from 'codecs/avif/dec/avif_dec';
|
||||
import wasmUrl from 'url:codecs/avif/dec/avif_dec.wasm';
|
||||
import { initEmscriptenModule, blobToArrayBuffer } from 'features/worker-utils';
|
||||
|
||||
let emscriptenModule: Promise<AVIFModule>;
|
||||
@@ -19,7 +18,7 @@ let emscriptenModule: Promise<AVIFModule>;
|
||||
export default async function decode(blob: Blob): Promise<ImageData> {
|
||||
if (!emscriptenModule) {
|
||||
const decoder = await import('codecs/avif/dec/avif_dec');
|
||||
emscriptenModule = initEmscriptenModule(decoder.default, wasmUrl);
|
||||
emscriptenModule = initEmscriptenModule(decoder.default);
|
||||
}
|
||||
|
||||
const [module, data] = await Promise.all([
|
||||
|
||||
@@ -11,14 +11,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import jxlDecoder, { JXLModule } from 'codecs/jxl/dec/jxl_dec';
|
||||
import wasmUrl from 'url:codecs/jxl/dec/jxl_dec.wasm';
|
||||
import { initEmscriptenModule, blobToArrayBuffer } from 'features/worker-utils';
|
||||
|
||||
let emscriptenModule: Promise<JXLModule>;
|
||||
|
||||
export default async function decode(blob: Blob): Promise<ImageData> {
|
||||
if (!emscriptenModule) {
|
||||
emscriptenModule = initEmscriptenModule(jxlDecoder, wasmUrl);
|
||||
emscriptenModule = initEmscriptenModule(jxlDecoder);
|
||||
}
|
||||
|
||||
const [module, data] = await Promise.all([
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import type { WebPModule } from 'codecs/webp/dec/webp_dec';
|
||||
import wasmUrl from 'url:codecs/webp/dec/webp_dec.wasm';
|
||||
import { initEmscriptenModule, blobToArrayBuffer } from 'features/worker-utils';
|
||||
|
||||
let emscriptenModule: Promise<WebPModule>;
|
||||
@@ -19,7 +18,7 @@ let emscriptenModule: Promise<WebPModule>;
|
||||
export default async function decode(blob: Blob): Promise<ImageData> {
|
||||
if (!emscriptenModule) {
|
||||
const decoder = await import('codecs/webp/dec/webp_dec');
|
||||
emscriptenModule = initEmscriptenModule(decoder.default, wasmUrl);
|
||||
emscriptenModule = initEmscriptenModule(decoder.default);
|
||||
}
|
||||
|
||||
const [module, data] = await Promise.all([
|
||||
|
||||
@@ -11,14 +11,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import wp2Decoder, { WP2Module } from 'codecs/wp2/dec/wp2_dec';
|
||||
import wasmUrl from 'url:codecs/wp2/dec/wp2_dec.wasm';
|
||||
import { initEmscriptenModule, blobToArrayBuffer } from 'features/worker-utils';
|
||||
|
||||
let emscriptenModule: Promise<WP2Module>;
|
||||
|
||||
export default async function decode(blob: Blob): Promise<ImageData> {
|
||||
if (!emscriptenModule) {
|
||||
emscriptenModule = initEmscriptenModule(wp2Decoder, wasmUrl);
|
||||
emscriptenModule = initEmscriptenModule(wp2Decoder);
|
||||
}
|
||||
|
||||
const [module, data] = await Promise.all([
|
||||
|
||||
@@ -12,9 +12,6 @@
|
||||
*/
|
||||
import type { AVIFModule } from 'codecs/avif/enc/avif_enc';
|
||||
import type { EncodeOptions } from '../shared/meta';
|
||||
import wasmUrlWithoutMT from 'url:codecs/avif/enc/avif_enc.wasm';
|
||||
import wasmUrlWithMT from 'url:codecs/avif/enc/avif_enc_mt.wasm';
|
||||
import workerUrl from 'omt:codecs/avif/enc/avif_enc_mt.worker.js';
|
||||
import { initEmscriptenModule } from 'features/worker-utils';
|
||||
import { threads } from 'wasm-feature-detect';
|
||||
|
||||
@@ -23,14 +20,10 @@ let emscriptenModule: Promise<AVIFModule>;
|
||||
async function init() {
|
||||
if (await threads()) {
|
||||
const avifEncoder = await import('codecs/avif/enc/avif_enc_mt');
|
||||
return initEmscriptenModule<AVIFModule>(
|
||||
avifEncoder.default,
|
||||
wasmUrlWithMT,
|
||||
workerUrl,
|
||||
);
|
||||
return initEmscriptenModule<AVIFModule>(avifEncoder.default);
|
||||
}
|
||||
const avifEncoder = await import('codecs/avif/enc/avif_enc.js');
|
||||
return initEmscriptenModule(avifEncoder.default, wasmUrlWithoutMT);
|
||||
return initEmscriptenModule(avifEncoder.default);
|
||||
}
|
||||
|
||||
export default async function encode(
|
||||
|
||||
@@ -16,31 +16,19 @@ import type { EncodeOptions } from '../shared/meta';
|
||||
import { initEmscriptenModule } from 'features/worker-utils';
|
||||
import { threads, simd } from 'wasm-feature-detect';
|
||||
|
||||
import wasmUrl from 'url:codecs/jxl/enc/jxl_enc.wasm';
|
||||
|
||||
import wasmUrlWithMT from 'url:codecs/jxl/enc/jxl_enc_mt.wasm';
|
||||
import workerUrl from 'omt:codecs/jxl/enc/jxl_enc_mt.worker.js';
|
||||
|
||||
import wasmUrlWithMTAndSIMD from 'url:codecs/jxl/enc/jxl_enc_mt_simd.wasm';
|
||||
import workerUrlWithSIMD from 'omt:codecs/jxl/enc/jxl_enc_mt_simd.worker.js';
|
||||
|
||||
let emscriptenModule: Promise<JXLModule>;
|
||||
|
||||
async function init() {
|
||||
if (await threads()) {
|
||||
if (await simd()) {
|
||||
const jxlEncoder = await import('codecs/jxl/enc/jxl_enc_mt_simd');
|
||||
return initEmscriptenModule(
|
||||
jxlEncoder.default,
|
||||
wasmUrlWithMTAndSIMD,
|
||||
workerUrlWithSIMD,
|
||||
);
|
||||
return initEmscriptenModule(jxlEncoder.default);
|
||||
}
|
||||
const jxlEncoder = await import('codecs/jxl/enc/jxl_enc_mt');
|
||||
return initEmscriptenModule(jxlEncoder.default, wasmUrlWithMT, workerUrl);
|
||||
return initEmscriptenModule(jxlEncoder.default);
|
||||
}
|
||||
const jxlEncoder = await import('codecs/jxl/enc/jxl_enc');
|
||||
return initEmscriptenModule(jxlEncoder.default, wasmUrl);
|
||||
return initEmscriptenModule(jxlEncoder.default);
|
||||
}
|
||||
|
||||
export default async function encode(
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
*/
|
||||
import mozjpeg_enc, { MozJPEGModule } from 'codecs/mozjpeg/enc/mozjpeg_enc';
|
||||
import { EncodeOptions } from '../shared/meta';
|
||||
import wasmUrl from 'url:codecs/mozjpeg/enc/mozjpeg_enc.wasm';
|
||||
import { initEmscriptenModule } from 'features/worker-utils';
|
||||
|
||||
let emscriptenModule: Promise<MozJPEGModule>;
|
||||
@@ -22,7 +21,7 @@ export default async function encode(
|
||||
options: EncodeOptions,
|
||||
): Promise<ArrayBuffer> {
|
||||
if (!emscriptenModule) {
|
||||
emscriptenModule = initEmscriptenModule(mozjpeg_enc, wasmUrl);
|
||||
emscriptenModule = initEmscriptenModule(mozjpeg_enc);
|
||||
}
|
||||
|
||||
const module = await emscriptenModule;
|
||||
|
||||
@@ -10,30 +10,27 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import initOxiWasmST, {
|
||||
optimise as optimiseST,
|
||||
} from 'codecs/oxipng/pkg/squoosh_oxipng';
|
||||
import initOxiWasmMT, {
|
||||
initThreadPool,
|
||||
optimise as optimiseMT,
|
||||
} from 'codecs/oxipng/pkg-parallel/squoosh_oxipng';
|
||||
import oxiWasmUrlST from 'url:codecs/oxipng/pkg/squoosh_oxipng_bg.wasm';
|
||||
import oxiWasmUrlMT from 'url:codecs/oxipng/pkg-parallel/squoosh_oxipng_bg.wasm';
|
||||
import { EncodeOptions } from '../shared/meta';
|
||||
import { threads } from 'wasm-feature-detect';
|
||||
|
||||
async function initMT() {
|
||||
await initOxiWasmMT(oxiWasmUrlMT);
|
||||
const { default: init, initThreadPool, optimise } = await import(
|
||||
'codecs/oxipng/pkg-parallel/squoosh_oxipng'
|
||||
);
|
||||
await init();
|
||||
await initThreadPool(navigator.hardwareConcurrency);
|
||||
return optimiseMT;
|
||||
return optimise;
|
||||
}
|
||||
|
||||
async function initST() {
|
||||
await initOxiWasmST(oxiWasmUrlST);
|
||||
return optimiseST;
|
||||
const { default: init, optimise } = await import(
|
||||
'codecs/oxipng/pkg/squoosh_oxipng'
|
||||
);
|
||||
await init();
|
||||
return optimise;
|
||||
}
|
||||
|
||||
let wasmReady: Promise<typeof optimiseMT | typeof optimiseST>;
|
||||
let wasmReady: ReturnType<typeof initMT | typeof initST>;
|
||||
|
||||
export default async function encode(
|
||||
data: ArrayBuffer,
|
||||
|
||||
@@ -16,18 +16,15 @@ import type { EncodeOptions } from '../shared/meta';
|
||||
import { initEmscriptenModule } from 'features/worker-utils';
|
||||
import { simd } from 'wasm-feature-detect';
|
||||
|
||||
import wasmUrl from 'url:codecs/webp/enc/webp_enc.wasm';
|
||||
import wasmUrlWithSIMD from 'url:codecs/webp/enc/webp_enc_simd.wasm';
|
||||
|
||||
let emscriptenModule: Promise<WebPModule>;
|
||||
|
||||
async function init() {
|
||||
if (await simd()) {
|
||||
const webpEncoder = await import('codecs/webp/enc/webp_enc_simd');
|
||||
return initEmscriptenModule(webpEncoder.default, wasmUrlWithSIMD);
|
||||
return initEmscriptenModule(webpEncoder.default);
|
||||
}
|
||||
const webpEncoder = await import('codecs/webp/enc/webp_enc');
|
||||
return initEmscriptenModule(webpEncoder.default, wasmUrl);
|
||||
return initEmscriptenModule(webpEncoder.default);
|
||||
}
|
||||
|
||||
export default async function encode(
|
||||
|
||||
@@ -16,31 +16,19 @@ import type { EncodeOptions } from '../shared/meta';
|
||||
import { initEmscriptenModule } from 'features/worker-utils';
|
||||
import { threads, simd } from 'wasm-feature-detect';
|
||||
|
||||
import wasmUrl from 'url:codecs/wp2/enc/wp2_enc.wasm';
|
||||
|
||||
import wasmUrlWithMT from 'url:codecs/wp2/enc/wp2_enc_mt.wasm';
|
||||
import workerUrl from 'omt:codecs/wp2/enc/wp2_enc_mt.worker.js';
|
||||
|
||||
import wasmUrlWithMTAndSIMD from 'url:codecs/wp2/enc/wp2_enc_mt_simd.wasm';
|
||||
import workerUrlWithSIMD from 'omt:codecs/wp2/enc/wp2_enc_mt_simd.worker.js';
|
||||
|
||||
let emscriptenModule: Promise<WP2Module>;
|
||||
|
||||
async function init() {
|
||||
if (await threads()) {
|
||||
if (await simd()) {
|
||||
const wp2Encoder = await import('codecs/wp2/enc/wp2_enc_mt_simd');
|
||||
return initEmscriptenModule(
|
||||
wp2Encoder.default,
|
||||
wasmUrlWithMTAndSIMD,
|
||||
workerUrlWithSIMD,
|
||||
);
|
||||
return initEmscriptenModule(wp2Encoder.default);
|
||||
}
|
||||
const wp2Encoder = await import('codecs/wp2/enc/wp2_enc_mt');
|
||||
return initEmscriptenModule(wp2Encoder.default, wasmUrlWithMT, workerUrl);
|
||||
return initEmscriptenModule(wp2Encoder.default);
|
||||
}
|
||||
const wp2Encoder = await import('codecs/wp2/enc/wp2_enc');
|
||||
return initEmscriptenModule(wp2Encoder.default, wasmUrl);
|
||||
return initEmscriptenModule(wp2Encoder.default);
|
||||
}
|
||||
|
||||
export default async function encode(
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import imagequant, { QuantizerModule } from 'codecs/imagequant/imagequant';
|
||||
import wasmUrl from 'url:codecs/imagequant/imagequant.wasm';
|
||||
import { initEmscriptenModule } from 'features/worker-utils';
|
||||
import { Options } from '../shared/meta';
|
||||
|
||||
@@ -22,7 +21,7 @@ export default async function process(
|
||||
opts: Options,
|
||||
): Promise<ImageData> {
|
||||
if (!emscriptenModule) {
|
||||
emscriptenModule = initEmscriptenModule(imagequant, wasmUrl);
|
||||
emscriptenModule = initEmscriptenModule(imagequant);
|
||||
}
|
||||
|
||||
const module = await emscriptenModule;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import type { WorkerResizeOptions } from '../shared/meta';
|
||||
import { getContainOffsets } from '../shared/util';
|
||||
import initResizeWasm, { resize as wasmResize } from 'codecs/resize/pkg';
|
||||
import resizeWasmUrl from 'url:codecs/resize/pkg/squoosh_resize_bg.wasm';
|
||||
import hqxWasmUrl from 'url:codecs/hqx/pkg/squooshhqx_bg.wasm';
|
||||
import initHqxWasm, { resize as wasmHqx } from 'codecs/hqx/pkg';
|
||||
|
||||
interface HqxResizeOptions extends WorkerResizeOptions {
|
||||
@@ -63,7 +61,7 @@ async function hqx(
|
||||
opts: HqxResizeOptions,
|
||||
): Promise<ImageData> {
|
||||
if (!hqxWasmReady) {
|
||||
hqxWasmReady = initHqxWasm(hqxWasmUrl);
|
||||
hqxWasmReady = initHqxWasm();
|
||||
}
|
||||
|
||||
await hqxWasmReady;
|
||||
@@ -96,7 +94,7 @@ export default async function resize(
|
||||
let input = data;
|
||||
|
||||
if (!resizeWasmReady) {
|
||||
resizeWasmReady = initResizeWasm(resizeWasmUrl);
|
||||
resizeWasmReady = initResizeWasm();
|
||||
}
|
||||
|
||||
if (optsIsHqxOpts(opts)) {
|
||||
|
||||
@@ -12,17 +12,10 @@
|
||||
*/
|
||||
export function initEmscriptenModule<T extends EmscriptenWasm.Module>(
|
||||
moduleFactory: EmscriptenWasm.ModuleFactory<T>,
|
||||
wasmUrl: string,
|
||||
workerUrl?: string,
|
||||
): Promise<T> {
|
||||
return moduleFactory({
|
||||
// Just to be safe, don't automatically invoke any wasm functions
|
||||
noInitialRun: true,
|
||||
locateFile: (url: string) => {
|
||||
if (url.endsWith('.wasm')) return wasmUrl;
|
||||
if (url.endsWith('.worker.js')) return workerUrl!;
|
||||
throw Error('Unknown url in locateFile ' + url);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
serveShareTarget,
|
||||
} from './util';
|
||||
import { get } from 'idb-keyval';
|
||||
import { shouldCacheDynamically } from './to-cache';
|
||||
|
||||
// Give TypeScript the correct global.
|
||||
declare var self: ServiceWorkerGlobalScope;
|
||||
@@ -70,7 +71,7 @@ self.addEventListener('fetch', (event) => {
|
||||
// We only care about GET from here on in.
|
||||
if (event.request.method !== 'GET') return;
|
||||
|
||||
if (url.pathname.startsWith('/c/demo-')) {
|
||||
if (shouldCacheDynamically(url.pathname)) {
|
||||
cacheOrNetworkAndCache(event, dynamicCache);
|
||||
cleanupCache(event, dynamicCache, ASSETS);
|
||||
return;
|
||||
|
||||
@@ -13,18 +13,46 @@ function subtractSets<T extends any>(set1: Set<T>, set2: Set<T>): Set<T> {
|
||||
|
||||
// Initial app stuff
|
||||
import * as initialApp from 'entry-data:client/initial-app';
|
||||
import swUrl from 'service-worker:sw';
|
||||
import * as compress from 'entry-data:client/lazy-app/Compress';
|
||||
import * as swBridge from 'entry-data:client/lazy-app/sw-bridge';
|
||||
import * as blobAnim from 'entry-data:shared/prerendered-app/Intro/blob-anim';
|
||||
import logo from 'url:shared/prerendered-app/Intro/imgs/logo.svg';
|
||||
import githubLogo from 'url:shared/prerendered-app/Intro/imgs/github-logo.svg';
|
||||
import largePhotoIcon from 'url:shared/prerendered-app/Intro/imgs/demos/icon-demo-large-photo.jpg';
|
||||
import artworkIcon from 'url:shared/prerendered-app/Intro/imgs/demos/icon-demo-artwork.jpg';
|
||||
import deviceScreenIcon from 'url:shared/prerendered-app/Intro/imgs/demos/icon-demo-device-screen.jpg';
|
||||
import logoIcon from 'url:shared/prerendered-app/Intro/imgs/demos/icon-demo-logo.png';
|
||||
import logoWithText from 'url:shared/prerendered-app/Intro/imgs/logo-with-text.svg';
|
||||
|
||||
let initalJs = new Set([
|
||||
// The processors and codecs
|
||||
// Simple stuff everyone gets:
|
||||
import * as featuresWorker from 'entry-data:../features-worker';
|
||||
|
||||
// Decoders (some are feature detected)
|
||||
import * as avifDec from 'entry-data:codecs/avif/dec/avif_dec';
|
||||
import * as webpDec from 'entry-data:codecs/webp/dec/webp_dec';
|
||||
|
||||
// AVIF
|
||||
import * as avifEncMt from 'entry-data:codecs/avif/enc/avif_enc_mt';
|
||||
import * as avifEnc from 'entry-data:codecs/avif/enc/avif_enc';
|
||||
|
||||
// JXL
|
||||
import * as jxlEncMtSimd from 'entry-data:codecs/jxl/enc/jxl_enc_mt_simd';
|
||||
import * as jxlEncMt from 'entry-data:codecs/jxl/enc/jxl_enc_mt';
|
||||
import * as jxlEnc from 'entry-data:codecs/jxl/enc/jxl_enc';
|
||||
|
||||
// OXI
|
||||
import * as oxiMt from 'entry-data:codecs/oxipng/pkg-parallel/squoosh_oxipng';
|
||||
import * as oxi from 'entry-data:codecs/oxipng/pkg/squoosh_oxipng';
|
||||
|
||||
// WebP
|
||||
import * as webpEncSimd from 'entry-data:codecs/webp/enc/webp_enc_simd';
|
||||
import * as webpEnc from 'entry-data:codecs/webp/enc/webp_enc';
|
||||
|
||||
// WP2
|
||||
import * as wp2EncMtSimd from 'entry-data:codecs/wp2/enc/wp2_enc_mt_simd';
|
||||
import * as wp2EncMt from 'entry-data:codecs/wp2/enc/wp2_enc_mt';
|
||||
import * as wp2Enc from 'entry-data:codecs/wp2/enc/wp2_enc';
|
||||
|
||||
export function shouldCacheDynamically(url: string) {
|
||||
return url.startsWith('/c/demo-');
|
||||
}
|
||||
|
||||
let initialJs = new Set([
|
||||
compress.main,
|
||||
...compress.deps,
|
||||
swBridge.main,
|
||||
@@ -32,77 +60,26 @@ let initalJs = new Set([
|
||||
blobAnim.main,
|
||||
...blobAnim.deps,
|
||||
]);
|
||||
// But initial app and any deps have already been inlined, so we don't need them:
|
||||
initalJs = subtractSets(
|
||||
initalJs,
|
||||
new Set([initialApp.main, ...initialApp.deps]),
|
||||
initialJs = subtractSets(
|
||||
initialJs,
|
||||
new Set([
|
||||
initialApp.main,
|
||||
...initialApp.deps.filter(
|
||||
(item) =>
|
||||
// Exclude JS deps that have been inlined:
|
||||
item.endsWith('.js') ||
|
||||
// As well as large image deps we want to keep dynamic:
|
||||
shouldCacheDynamically(item),
|
||||
),
|
||||
// Exclude features Worker itself - it's referenced from the main app,
|
||||
// but is meant to be cached lazily.
|
||||
featuresWorker.main,
|
||||
// Also exclude Service Worker itself (we're inside right now).
|
||||
swUrl,
|
||||
]),
|
||||
);
|
||||
|
||||
export const initial = [
|
||||
'/',
|
||||
...initalJs,
|
||||
logo,
|
||||
githubLogo,
|
||||
largePhotoIcon,
|
||||
artworkIcon,
|
||||
deviceScreenIcon,
|
||||
logoIcon,
|
||||
logoWithText,
|
||||
];
|
||||
|
||||
// The processors and codecs
|
||||
// Simple stuff everyone gets:
|
||||
import * as featuresWorker from 'entry-data:../features-worker';
|
||||
import rotateWasm from 'url:codecs/rotate/rotate.wasm';
|
||||
import quantWasm from 'url:codecs/imagequant/imagequant.wasm';
|
||||
import resizeWasm from 'url:codecs/resize/pkg/squoosh_resize_bg.wasm';
|
||||
import hqxWasm from 'url:codecs/hqx/pkg/squooshhqx_bg.wasm';
|
||||
import mozjpegWasm from 'url:codecs/mozjpeg/enc/mozjpeg_enc.wasm';
|
||||
|
||||
// Decoders (some are feature detected)
|
||||
import * as avifDec from 'entry-data:codecs/avif/dec/avif_dec';
|
||||
import avifDecWasm from 'url:codecs/avif/dec/avif_dec.wasm';
|
||||
import jxlDecWasm from 'url:codecs/jxl/dec/jxl_dec.wasm';
|
||||
import * as webpDec from 'entry-data:codecs/webp/dec/webp_dec';
|
||||
import webpDecWasm from 'url:codecs/webp/dec/webp_dec.wasm';
|
||||
import wp2DecWasm from 'url:codecs/wp2/dec/wp2_dec.wasm';
|
||||
|
||||
// AVIF
|
||||
import * as avifEncMtWorker from 'entry-data:codecs/avif/enc/avif_enc_mt.worker.js';
|
||||
import * as avifEncMt from 'entry-data:codecs/avif/enc/avif_enc_mt';
|
||||
import avifEncMtWasm from 'url:codecs/avif/enc/avif_enc_mt.wasm';
|
||||
import avifEncWasm from 'url:codecs/avif/enc/avif_enc.wasm';
|
||||
import * as avifEnc from 'entry-data:codecs/avif/enc/avif_enc.js';
|
||||
|
||||
// JXL
|
||||
import * as jxlEncMtSimdWorker from 'entry-data:codecs/jxl/enc/jxl_enc_mt_simd.worker.js';
|
||||
import * as jxlEncMtSimd from 'entry-data:codecs/jxl/enc/jxl_enc_mt_simd';
|
||||
import jxlEncMtSimdWasm from 'url:codecs/jxl/enc/jxl_enc_mt_simd.wasm';
|
||||
import * as jxlEncMtWorker from 'entry-data:codecs/jxl/enc/jxl_enc_mt.worker.js';
|
||||
import * as jxlEncMt from 'entry-data:codecs/jxl/enc/jxl_enc_mt';
|
||||
import jxlEncMtWasm from 'url:codecs/jxl/enc/jxl_enc_mt.wasm';
|
||||
import jxlEncWasm from 'url:codecs/jxl/enc/jxl_enc.wasm';
|
||||
import * as jxlEnc from 'entry-data:codecs/jxl/enc/jxl_enc';
|
||||
|
||||
// OXI
|
||||
import oxiMtWasm from 'url:codecs/oxipng/pkg-parallel/squoosh_oxipng_bg.wasm';
|
||||
import oxiWasm from 'url:codecs/oxipng/pkg/squoosh_oxipng_bg.wasm';
|
||||
|
||||
// WebP
|
||||
import * as webpEncSimd from 'entry-data:codecs/webp/enc/webp_enc_simd';
|
||||
import webpEncSimdWasm from 'url:codecs/webp/enc/webp_enc_simd.wasm';
|
||||
import * as webpEnc from 'entry-data:codecs/webp/enc/webp_enc';
|
||||
import webpEncWasm from 'url:codecs/webp/enc/webp_enc.wasm';
|
||||
|
||||
// WP2
|
||||
import * as wp2EncMtSimdWorker from 'entry-data:codecs/wp2/enc/wp2_enc_mt_simd.worker.js';
|
||||
import * as wp2EncMtSimd from 'entry-data:codecs/wp2/enc/wp2_enc_mt_simd';
|
||||
import wp2EncMtSimdWasm from 'url:codecs/wp2/enc/wp2_enc_mt_simd.wasm';
|
||||
import * as wp2EncMtWorker from 'entry-data:codecs/wp2/enc/wp2_enc_mt.worker.js';
|
||||
import * as wp2EncMt from 'entry-data:codecs/wp2/enc/wp2_enc_mt';
|
||||
import wp2EncMtWasm from 'url:codecs/wp2/enc/wp2_enc_mt.wasm';
|
||||
import * as wp2Enc from 'entry-data:codecs/wp2/enc/wp2_enc';
|
||||
import wp2EncWasm from 'url:codecs/wp2/enc/wp2_enc.wasm';
|
||||
export const initial = ['/', ...initialJs];
|
||||
|
||||
export const theRest = (async () => {
|
||||
const [
|
||||
@@ -124,88 +101,54 @@ export const theRest = (async () => {
|
||||
}),
|
||||
]);
|
||||
|
||||
const items = [
|
||||
featuresWorker.main,
|
||||
...featuresWorker.deps,
|
||||
rotateWasm,
|
||||
quantWasm,
|
||||
resizeWasm,
|
||||
hqxWasm,
|
||||
mozjpegWasm,
|
||||
jxlDecWasm,
|
||||
wp2DecWasm,
|
||||
];
|
||||
const items: string[] = [];
|
||||
|
||||
if (!supportsAvif) items.push(avifDec.main, ...avifDec.deps, avifDecWasm);
|
||||
if (!supportsWebP) items.push(webpDec.main, ...webpDec.deps, webpDecWasm);
|
||||
function addWithDeps(entry: typeof import('entry-data:*')) {
|
||||
items.push(entry.main, ...entry.deps);
|
||||
}
|
||||
|
||||
addWithDeps(featuresWorker);
|
||||
|
||||
if (!supportsAvif) addWithDeps(avifDec);
|
||||
if (!supportsWebP) addWithDeps(webpDec);
|
||||
|
||||
// AVIF
|
||||
if (supportsThreads) {
|
||||
items.push(
|
||||
avifEncMtWorker.main,
|
||||
...avifEncMtWorker.deps,
|
||||
avifEncMt.main,
|
||||
...avifEncMt.deps,
|
||||
avifEncMtWasm,
|
||||
);
|
||||
addWithDeps(avifEncMt);
|
||||
} else {
|
||||
items.push(avifEnc.main, ...avifEnc.deps, avifEncWasm);
|
||||
addWithDeps(avifEnc);
|
||||
}
|
||||
|
||||
// JXL
|
||||
if (supportsThreads && supportsSimd) {
|
||||
items.push(
|
||||
jxlEncMtSimdWorker.main,
|
||||
...jxlEncMtSimdWorker.deps,
|
||||
jxlEncMtSimd.main,
|
||||
...jxlEncMtSimd.deps,
|
||||
jxlEncMtSimdWasm,
|
||||
);
|
||||
addWithDeps(jxlEncMtSimd);
|
||||
} else if (supportsThreads) {
|
||||
items.push(
|
||||
jxlEncMtWorker.main,
|
||||
...jxlEncMtWorker.deps,
|
||||
jxlEncMt.main,
|
||||
...jxlEncMt.deps,
|
||||
jxlEncMtWasm,
|
||||
);
|
||||
addWithDeps(jxlEncMt);
|
||||
} else {
|
||||
items.push(jxlEnc.main, ...jxlEnc.deps, jxlEncWasm);
|
||||
addWithDeps(jxlEnc);
|
||||
}
|
||||
|
||||
// OXI
|
||||
if (supportsThreads) {
|
||||
items.push(oxiMtWasm);
|
||||
addWithDeps(oxiMt);
|
||||
} else {
|
||||
items.push(oxiWasm);
|
||||
addWithDeps(oxi);
|
||||
}
|
||||
|
||||
// WebP
|
||||
if (supportsSimd) {
|
||||
items.push(webpEncSimd.main, ...webpEncSimd.deps, webpEncSimdWasm);
|
||||
addWithDeps(webpEncSimd);
|
||||
} else {
|
||||
items.push(webpEnc.main, ...webpEnc.deps, webpEncWasm);
|
||||
addWithDeps(webpEnc);
|
||||
}
|
||||
|
||||
// WP2
|
||||
if (supportsThreads && supportsSimd) {
|
||||
items.push(
|
||||
wp2EncMtSimdWorker.main,
|
||||
...wp2EncMtSimdWorker.deps,
|
||||
wp2EncMtSimd.main,
|
||||
...wp2EncMtSimd.deps,
|
||||
wp2EncMtSimdWasm,
|
||||
);
|
||||
addWithDeps(wp2EncMtSimd);
|
||||
} else if (supportsThreads) {
|
||||
items.push(
|
||||
wp2EncMtWorker.main,
|
||||
...wp2EncMtWorker.deps,
|
||||
wp2EncMt.main,
|
||||
...wp2EncMt.deps,
|
||||
wp2EncMtWasm,
|
||||
);
|
||||
addWithDeps(wp2EncMt);
|
||||
} else {
|
||||
items.push(wp2Enc.main, ...wp2Enc.deps, wp2EncWasm);
|
||||
addWithDeps(wp2Enc);
|
||||
}
|
||||
|
||||
return [...new Set(items)];
|
||||
|
||||
Reference in New Issue
Block a user