Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't use with Angular #18

Closed
daverickdunn opened this issue Nov 21, 2022 · 5 comments
Closed

Can't use with Angular #18

daverickdunn opened this issue Nov 21, 2022 · 5 comments

Comments

@daverickdunn
Copy link

I'm trying to load this with an Angular app. TS is happy and the app compiles fine, but at runtime I'm getting an error:

zone.js:1518 Not allowed to load local resource: file:///C:/**/**/node_modules/brotli-wasm/pkg.web/brotli_wasm_bg.wasm

Importing as:

import brotliPromise from 'brotli-wasm';

Angular 13
Chrome 107

@pimterry
Copy link
Member

No idea I'm afraid, it sounds like this is an issue with either your deployment setup or your bundler configuration. Your bundler appears to be keeping the reference to the wasm file to load it at runtime (as it should) but if that error is appearing in the browser then it's preserving it with a file:// URL (which is very unusual) and either your browser or server configuration is refusing to allow the request to load this file.

For this to work in browsers, you need to:

  • Ensure the bundled output includes a usable URL reference to the WASM, which depends on how your server is set up (you can search the bundle for brotli_wasm_bg.wasm to find this)
  • Ensure the server serves the WASM correctly (you can check the files that your server is serving, and try manually making the request to the server URL with curl to check this)
  • Ensure your browser allows that request (you can try to fetch() the WASM in your browser to do this - it could be blocked by CSP, or CORS, or server configuration issues)

It's hard to know every possible configuration I'm afraid! I suspect this isn't really an issue related to this project though - you'll have the same issue with any wasm-based library. If it helps, you can see the Webpack config (for Webpack v5) that this project uses during webpack browser testing here:

webpack: {
mode: 'development',
devtool: 'source-map',
module: {
rules: [
{
test: /\.ts$/,
loader: 'ts-loader',
options: {
configFile: 'test/tsconfig.json',
compilerOptions: {
outDir: tmp.dirSync({ unsafeCleanup: true }).name
}
},
exclude: /node_modules/
}
]
},
resolve: {
extensions: ['.ts', '.js'],
fallback: {
crypto: false
}
},
experiments: {
asyncWebAssembly: true
},
output: {
path: outputDir
}
},

@daverickdunn
Copy link
Author

Hi, thanks for taking a look, that's understandable.

I tried a bunch of stuff to get it to bundle with my app but I couldn't figure out what was wrong. I don't really want to bloat with extra bundling config as I'd have to add extra packages etc. so I've switched to brotli-dec-wasm as that worked without any issues.

Thanks again.

@rr923
Copy link

rr923 commented Nov 23, 2023

brotli-dec-wasm

@daverickdunn , hi, does brotli-dec-wasm work for you with angular? I tried and it shows the same error. Could you please share how you did that?

@myl7
Copy link
Contributor

myl7 commented Nov 23, 2023

it shows the same error

As the error comes from the web variant (pkg.web), it is because the code generated by wasm-pack uses new URL('index_bg.wasm', import.meta.url) to determine to the URL to the WASM binary file so that in the browser it can fetch and load it.
The reason why it breaks in Angular may be that import.meta.url is not an expected value.
I am not familiar with Angular so I am not so sure though.

If you are looking for a quick and easy solution, you can just serve the WASM file on your own (by making the bundler copy it to the output dir, or even manually) and pass the URL string to the init function (__wbg_init in the generated code, pkg.web/brotli_wasm.js).

In brotli-wasm it only exports init().then(() => brotliWasm) so it can be a little hard to figure out how.
In brotli-dec-wasm I will soon release a new version so that you can do this:

import { init } from 'brotli-dec-wasm'

const wasmUrl = '...'
const brotli = await init(wasmUrl)

Or refer to the asset.md document.

PS: I am the author of brotli-dec-wasm and also put effort into this package so that Brotli can be easier in JS.

And @pimterry , I are recently working on another kind of entry for the web environment of these packages with less "side-effects".
It is in asset.js with another export in package.json, the document is at asset.md, and an example is available at example/webpack-asset.
Do you think it is fine and can I open a PR for the new entry?

@daverickdunn
Copy link
Author

daverickdunn commented Nov 24, 2023

@rr923

Note that I'm encoding the brotli buffer as base64, you may have it encoded as something else.

import { Injectable } from '@angular/core';
import { catchError, map, ReplaySubject, throwError } from 'rxjs';

function Base64ToArrayBuffer(base64: string) {
    const binary_string = atob(base64);
    const len = binary_string.length;
    const bytes = new Uint8Array(len);
    for (let i = 0; i < len; i++) {
        bytes[i] = binary_string.charCodeAt(i);
    }
    return bytes;
}

@Injectable({
    providedIn: 'root'
})
export class BrotliService {

    public brotli = new ReplaySubject<any>();

    private decoder = new TextDecoder();

    constructor() {
        this.init();
    }

    private async init() {
        const brotli = await import('brotli-dec-wasm');
        this.brotli.next(brotli)
    }

    public decompress<T = any>(data: string) {
        return this.brotli.pipe(
            map(brotli => {

                const buff_array = Base64ToArrayBuffer(data); // base64 string to buffer (compressed)

                const decompressed = brotli.brotliDec(buff_array); // compressed buffer to uncompressed buffer

                const decoded = this.decoder.decode(decompressed); // uncompressed buffer to utf-8 string

                return JSON.parse(decoded) as T;

            }),
            catchError(error => {
                console.error(error)
                return throwError(() => new Error(error))
            })
        )
    }

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants