Search code examples
javascriptgoogle-closure-compiler

How to get Closure Compiler to find window.crypto?


I am new to javascript and working on this existing package that uses closure compiler v20120917 to compile a vanilla javascript package into a single minified js file.

I am trying to use crypto:

function computeChallenge(buffer) {
    return window.crypto.subtle.digest('SHA-256', buffer); 
}

but Closure compiler is throwing an error: ERROR - Property subtle never defined on Window.prototype.crypto

I can run this on my browser console, and it works fine. Why can't closure compiler find the method? Do I need to import some file, how would I do so?


Solution

  • Tool that generates externs automatically by executing the JS and scanning the objects:
    JavaScript externs generator
    GitHub Repo
    Runnable Demo
    Save the extern.js file and then add it to your externs:

    java -jar compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS \
      --js myjs.js --externs extern.js
    

    Another way is to just make all calls using string keys when accessing properties
    eg: window["sjcl"]["cipher"]["aes"]()

    Closure Compiler 2012 version will be too old and missing externs for a lot of globals, which Closure Compiler advanced will need or it will treat them as mangleable properties (and subsequently as no-ops).
    Upgrading is recommended, because there have been a lot of improvements in the last 8 years, but this may not be practical due to large changes in how the code must be written (as your comment implies). Below are some options for backporting externs and declaring your own. If you have experience with TypeScript, the process of creating externs should feel familiar.

    Here are some pre-built externs from Google that you should be able to use directly so you can use the crypto API (and other new APIs):

    For any library that you want to use (without bundling it and compiling it with your program) you will have to declare externs to prevent mangling:
    Declaring Externs Docs
    This is so that Closure Compiler knows that they are names of functions and objects that already exist and should not be mangled
    eg:

    // myexterns.js
    function MyExternFunction(){};
    window["MyGlobalVariable"];
    
    java -jar compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS \
      --js myjs.js --externs myexterns.js
    

    Note: Trying to bundle libraries using Closure Compiler Advanced, especially the 2012 version, is most likely not going to be realistically possible unless they already target CC. Just declare the externs and call it a day.

    This doc explains the why you need externs and how the mangling effects your code:
    Restrictions for Advanced Optimizations Docs