Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Import third party js files to angular typescript project

During my experience in angular I was forced to use four different ways of include 3-rd party library poliglot.js (for multilang).

So to be able use new Polyglot(...) in my Lang class:

export class Lang
{
    ...
    constructor() {

        this.polyglot = new Polyglot({ locale: 'en' });
        ...        
    }
    ...
}

I use this four approach

A. In my quite old (2016) angular2 (based on framerwork angular2-webpack-starter) project (currently this solution doesn't work due to lack of require instruction in new angular projects):

var Polyglot = require('../../../node_modules/node-polyglot/build/polyglot.min.js');

B. In my next project angular4 (based on angular2-webpack-starter):

import Polyglot from '../../../node_modules/node-polyglot/build/polyglot.min.js'; 

C. In my recent angular5 project embeded in Laravel project (based on angular-cli)

import * as Polyglot from '../../../node_modules/node-polyglot/build/polyglot.min.js';

D. I also found 4-th solution which work on my some old angular project for jQuery (based on angular2-webpack-starter) (and people in internet mention this solution a lot) but I write it down using Polyglot example:

import '../../../node_modules/node-polyglot/build/polyglot.min.js';
declare var Polyglot: any;

// declare var $:any   // this is for jquery (as example)

The questions are: What is the difference between this four solutions and how they works? What cause that in some project one solution works but others does't work?

like image 527
Kamil Kiełczewski Avatar asked May 24 '18 18:05

Kamil Kiełczewski


People also ask

Can I use JS in TS project?

You can use thousands of existing JavaScript libraries in your TypeScript project. Type definition files allow you to enjoy the type-checking and autocomplete features in libraries that were written in JavaScript. These files make you more productive in writing code.


1 Answers

So lets break it down:

A: Would still work in any angular version you just have to declare require before using it.

declare const require: any;
const Polyglot = require('../../../node_modules/node-polyglot/build/polyglot.min.js');

B: Point A uses the CommonJS module system to load the dependency, the other points are using the ES6 dynamic import system (which can be used like the commonjs module system with webpack by default). You can import Polyglot directly if the library exposes the module e.g.

export class Polyglot {}

C: If Polyglot has multiple members which you all wan't to use you can import all members of Polyglot by writing

import * as Polyglot from '../../../node_modules/node-polyglot/build/polyglot.min.js';

D: Polyglot gets imported but not bind to any variable. But Polyglot exposes a global object which you don't have any access to until you declare the variable it will be available under.

See the mdn reference for better explanation

Depending on what build system you use there is no answer which one of the should always work but my solution A should work in every webpack build aswell as B and C. Friendly reminder that A and D are no optimal solutions and should only be used if there is no other way to import/use the module.

Edit: The ES6 standard just describes what a modules is, what it contains, how a module should be exported and imported and more on.

So there is no way how ES6 would handle these "old" modules since it isn't a library or anything like that. CommonJS is also just a standard, which is implemented by Node.js which module imports you know with require('module').

So Webpack comes into your help which can handle both of these module systems, because they implemented both of these.

If you create an empty project and build with webpack via webpack --env development, you can see how webpack handles the different modules. Webpack compiles your code and ads it's own handling for ESModules or CommonJS Modules. Depending on what module they find they will call different Methods. I added an example with the compiled code.

/******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId]) {
/******/ 			return installedModules[moduleId].exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/
/******/
/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;
/******/
/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;
/******/
/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ 		}
/******/ 	};
/******/
/******/ 	// define __esModule on exports
/******/ 	__webpack_require__.r = function(exports) {
/******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ 		}
/******/ 		Object.defineProperty(exports, '__esModule', { value: true });
/******/ 	};
/******/
/******/ 	// create a fake namespace object
/******/ 	// mode & 1: value is a module id, require it
/******/ 	// mode & 2: merge all properties of value into the ns
/******/ 	// mode & 4: return value when already ns object
/******/ 	// mode & 8|1: behave like require
/******/ 	__webpack_require__.t = function(value, mode) {
/******/ 		if(mode & 1) value = __webpack_require__(value);
/******/ 		if(mode & 8) return value;
/******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ 		var ns = Object.create(null);
/******/ 		__webpack_require__.r(ns);
/******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ 		return ns;
/******/ 	};
/******/
/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};
/******/
/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";
/******/
/******/
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = "./main.js");
/******/ })
/************************************************************************/
/******/ ({

/***/ "./esmodule.js":
/*!*********************!*\
  !*** ./esmodule.js ***!
  \*********************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n  value: true\n});\nexports.default = void 0;\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nvar MyClass = function MyClass() {\n  _classCallCheck(this, MyClass);\n\n  console.log('test');\n};\n\nexports.default = MyClass;\n\n//# sourceURL=webpack:///./esmodule.js?");

/***/ }),

/***/ "./main.js":
/*!*****************!*\
  !*** ./main.js ***!
  \*****************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
eval("\n\nvar test = _interopRequireWildcard(__webpack_require__(/*! ./esmodule.js */ \"./esmodule.js\"));\n\nfunction _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }\n\n__webpack_require__(/*! ./module */ \"./module.js\");\n\n//# sourceURL=webpack:///./main.js?");

/***/ }),

/***/ "./module.js":
/*!*******************!*\
  !*** ./module.js ***!
  \*******************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
eval("\n\nmodule.exports = {\n  myFunction: function myFunction() {\n    console.log('Test');\n  }\n};\n\n//# sourceURL=webpack:///./module.js?");

/***/ })

/******/ });

//// main.js
require('./module')
import * as test from './esmodule.js';
//// esmodule.js
export default class MyClass{
    constructor(){
        console.log('test')
    }
}
//// module.js
module.exports = {
    myFunction: function () {
        console.log('Test')
    }
}

You can see that Webpack creates a self executing function which gets all the created modules with their { id(pathToFile) : function(module, exports, __webpack_require__). In the 2 different module types (ESModule, Module --> CommonJS) you can see that Webpack handles the types differently. If you want a more in depth look i can edit my post again.

like image 54
Sven Avatar answered Sep 29 '22 13:09

Sven