How do I import an IIFE-based JavaScript module into an Angular TypeScript app?

牧云@^-^@ 提交于 2019-12-21 04:57:04

问题


So I have a third-party SDK written as an oldschool IIFE based module. In other words it looks something like this:

var ThirdPartySDK = (function() {
  var export = {};

  // Add some methods to export

  return export;
})();

You would then be expected to use it by referencing it on the global scope like this:

<html>
  <body>
    <script src="lib/ThirdPartySDK.js">
    <script>
      ThirdPartySDK.foo();
    <\script>
  <\body>
<\html>

I could still use it this way of course, but is that really the best practice with Angular and TypeScript? Is there some way to set things up with angular/TypeScript/webpack so that I can use a proper import statement? Something like this:

import { ThirdPartySDK } from '../lib/ThirdPartySDK.js';
ThirdPartySDK.foo();

回答1:


The best way to have a proper import statement for the actual value of ThirdPartySDK is to refactor the script to a module that exports this value. The following snippet allows you to use the import statement as showed:

export const ThirdPartySDK = {
    foo() { console.log('Doing foo'); }
};

For big libraries refactoring is not always that easy, so I see 2 approaches that do not involve too much refactoring:


1. Export the ThirdPartySDK variable

You could simply make a module out of the IIFE file by exporting the current IThirdPartySDK variable (returned by the IIFE), and then import it as you showed:

export const ThirdPartySDK = (function() {
    var _export = {};

    // Add some methods to export

    return _export;
})();

Note that if you want to have some useful information about the shape of ThirdPartySDK you would have to add a type annotation to the const declaration, and if SomeType (see below) does not yet exist you'll have to write it yourself:

export const ThirdPartySDK: SomeType = (function() {
// ...

At this point Typescript will start to complain about the IIFE expression not being assignable to SomeType; the quick 'solution' to tell typescript to pretend the expression evaluates to a value of type SomeType using the as keyword:

export const ThirdPartySDK: SomeType = (function() {
    // ...
})() as SomeType;

2. Keep the <script> tag and declare the variable

Another option it to keep the script tag, import nothing, and declare the variable and its expected type in typescript:

(But also in this case you might have to provide type definitions yourself)

interface SomeType {
    // SDK type shape goes here...
}

declare const ThirdPartySDK: SomeType;



回答2:


You can wrap the third-party SDK in a TypeScript module using a hack with eval.

Let's say that ThirdPartySDK.js looks like this:

var ThirdPartySDK = (function () {
    var exports = {
        foo: function () { console.log("Hello, world!"); }
    };
    return exports;
})();

You would then create a ThirdPartySDK-wrapper.ts module that looks something like this:

import * as fs from 'fs';
const script = fs.readFileSync('../lib/ThirdPartySDK.js').toString();

global.eval(script);

//@ts-ignore
export default ThirdPartySDK;

The @ts-ignore directive is required to keep the TypeScript compiler from complaining about not finding a declaration for the ThirdPartySDK variable (it is declared in the script executed through eval).

You can then import ThirdPartySDK through the wrapper module:

import ThirdPartySDK from './wrapper';
ThirdPartySDK.foo();  // Console output: "Hello, world!" 

Note that this wrapper only works for applications running in Node.js, since it uses fs.fileReadSync to get the contents of the script.

If you're going to use it in a browser, you will need some other way to retrieve the script. You could probably use frameworks such as WebPack to bundle the ThirdPartySDK script as a string value that you can require in the wrapper module.



来源:https://stackoverflow.com/questions/54225603/how-do-i-import-an-iife-based-javascript-module-into-an-angular-typescript-app

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!