GithubHelp home page GithubHelp logo

microsoft / dynamicproto-js Goto Github PK

View Code? Open in Web Editor NEW
22.0 11.0 10.0 1.23 MB

Generates dynamic prototype methods for JavaScript objects (classes) by supporting method definition within their "class" constructor (like an instance version), this removes the need to expose internal properties on the instance (this) which results in better code minfication and therefore improved load times for your users.

License: MIT License

TypeScript 100.00%
javascript typescript prototype inheritence microsoft minification

dynamicproto-js's Introduction

Dynamic Proto JavaScript

Generates dynamic prototype methods for JavaScript objects (classes) by supporting method definition within their "class" constructor (like an instance version), this removes the need to expose internal properties on the instance (this) and the usage of ClassName.prototype.funcName() both of which result in better code minfication (smaller output) and therefore improved load times for your users.

The dynamically generated prototype methods support class inheritance of any type, which means you can extend from base classes that use instance or prototype defined methods, you also don't need to add the normal boiler plate code to handle detecting, saving and calling any previous instance methods that you are overriding as support for this is provided automatically.

So whether creating a new class or extending some other class/code, your resulting code, can be successfully extended via TypeScript or JavaScript.

ES3 / IE8 support has been removed from Version 2.x.

if you need to retain ES3 / IE8 support then you will need to use one of the 1.x versions which is now maintained on the old master branch

The version 2.x is maintained on the default main branch

Documentation

Github Documentation includes typedoc API references.

Removing / Hiding internal properties from instance

By defining the properties / methods within the constructors closure, each instance can contain or define internal state in the form of properties which it does not have to expose publically as each defined "public" instance method has direct access to this define state within the context/scope of the closure method.

While this does require some additional CPU and memory at the point of creating each instance object this is designed to be as minimal as possible and should be outwayed by the following advantages :-

  • Avoids polluting the instance (this) namespace with internal values that can cause issues with inheritence for base/super classes or even derived classes that extend your class.
  • Smaller code as the internal properties and methods when defined within the instance can be minified.
  • As the resulting generated code can be better minified this should result in a smaller minified result and therefore better load times for your users.

Basic Usage

import dynamicProto from "@microsoft/dynamicproto-js";
class ExampleClass extends BaseClass {
    constructor() {
        dynamicProto(ExampleClass, this, (_self, base) => {
            // This will define a function that will be converted to a prototype function
            _self.newFunc = () => {
                // Access any "this" instance property  
                if (_self.someProperty) {
                    ...
                }
            }
            // This will define a function that will be converted to a prototype function
            _self.myFunction = () => {
                // Access any "this" instance property
                if (_self.someProperty) {
                    // Call the base version of the function that we are overriding
                    base.myFunction();
                }
                ...
            }
            _self.initialize = () => {
                ...
            }
            // Warnings: While the following will work as _self is simply a reference to
            // this, if anyone overrides myFunction() the overridden will be called first
            // as the normal JavaScript method resolution will occur and the defined
            // _self.initialize() function is actually gets removed from the instance and
            // a proxy prototype version is created to reference the created method.
            _self.initialize();
        });
    }
}

Build & Test this repo

  1. Install all dependencies

    npm install
    npm install -g @microsoft/rush
  2. Navigate to the root folder and update rush dependencies

    rush update
  3. Build, lint, create docs and run tests

    rush build
    npm run test

If you are changing package versions or adding/removing any package dependencies, run
rush update --purge --recheck --full
before building. Please check-in any files that change under common\ folder.

Performance

The minified version of this adds a negligible amount of code and loadtime to your source code and by using this library, your generated code can be better minified as it removes most references of Classname.prototype.XXX methods from the generated code.

Summary:

  • ~2 KB minified (uncompressed)

Example usage and resulting minified code

In this first example of code that is typically emitted by TypeScript it contains several references to the Classname.prototype and "this" references, both of which cannot be minfied.

var NormalClass = /** @class */ (function () {
    function NormalClass() {
        this.property1 = [];
        this.property1.push("Hello");
    }
    NormalClass.prototype.function1 = function () {
        //...
        doSomething();
    };
    NormalClass.prototype.function2 = function () {
        //...
        doSomething();
    };
    NormalClass.prototype.function3 = function () {
        //...
        doSomething();
    };
    return NormalClass;
}());

So the result would look something like this which represents a ~45% compression, note that the Classname.prototype appears several times.

var NormalClass=(NormalClass.prototype.function1=function(){doSomething()},NormalClass.prototype.function2=function(){doSomething()},NormalClass.prototype.function3=function(){doSomething()},function(){this.property1=[],this.property1.push("Hello")});

While in this example when using the dynamicProto helper to create the same resulting class and objects there are no references to Classname.prototype and only 1 reference to this.

var DynamicClass = /** @class */ (function () {
    function DynamicClass() {
        dynamicProto(DynamicClass, this, function (_self, base) {
            _self.property1 = [];
            _self.property1.push("Hello()");
            _self.function1 = function () {
                //...
                doSomething();
            };
            _self.function2 = function () {
                //...
                doSomething();
            };
            _self.function3 = function () {
                //...
                doSomething();
            };
        });
    }
    return DynamicClass;
}());

Which results in the following minified code which is much smaller and represents ~63% compression.

var DynamicClass=function n(){dynamicProto(n,this,function(n,o){n.property1=[],n.property1.push("Hello()"),n.function1=function(){doSomething()},n.function2=function(){doSomething()},n.function3=function(){doSomething()}})};

So when looking at the code for NormalClass and DynamicClass, both end up with 1 instance property called property1 and the 3 functions function1, function2 and function3, in both cases the functions are defined ONLY on the "class" prototype and property1 is defined on the instance. So anyone, whether using JavaScript or TypeScript will be able to "extend" either of class without any concerns about overloading instance functions and needing to save any previous method. And you are extending a 3rd party library you no longer have to worry about them changing the implementation as dynamicProto() handles converting overriden instance functions into prototype level ones. Yes, this means that if you don't override instance function it will continue to be an instance function.

When to use

While this helper was created to support better minification for generated code via TypeScript code, it is not limited to only being used from within TypeScript, you can use the helper function directly in the same way as the examples above.

As with including any additional code into your project there are trade offs that you need to make, including if you are looking at this helper, one of the primary items is the overall size of the additional code that you will be including vs the minification gains that you may obtained. This project endeavours to keep it's impact (bytes) as small as possible while supporting you to create readable and maintainable code that will create a smaller minified output.

In most cases when creating JavaScript to support better minfication, when your code doesn't expose or provide a lot of public methods or only uses un-minifiable "names" less than 2 times, then you may not see enough potential gains to counteract the additional bytes required from the helper code. However, for any significant project you should.

So at the end of the day, if you are creating JS classes directly you should be able to create a simplier one-off solution that would result in smaller output (total bytes). This is how this project started, but, once we had several of these one-off solutions it made more sense to build it once.

Performance optimizations (from v1.1)

To aid with execution performance from v1.1.0 (by default) the dynamically generated prototype functions will attempt to directly assign a top-level instance function (on first execution) of each function. This means that subsequent calls to that function will directly call the target instance function and avoid the dynamic function lookup process, this provides a minor performance improvement assists with identifying the called functions during profiling.

To ensure that this does not break inheritance there are 3 prerequisites that must be true before this happens

  • This check is only performed once per instance, per dynamic function
  • The instance cannot already have an existing instance level function (duh!)
  • The dynamic proto function MUST be the FIRST prototype level function in the inherited class hierarchy.
    • This simply means if a new class extends a class which is using dynamicProto() and it provides it's own prototype (class level in TypeScript terms) function, then we can't set an instance level as this would cause the class level function to never get called.

You can disable this default behavior by passing a new (optional) 4th argument to the dynamicProto(), the new 'options' argument is defined as an interface IDynamicProtoOpts to aid with any future options that may get exposed and has the following values

Name Type Description
setInstFuncs Boolean Should the dynamic prototype attempt to set an instance function for instances that do not already have an function of the same name or have been extended by a class with a (non-dynamic proto) prototype function.

Note:

If ANY class in the hierarchy explicitly disables this behavior (passes options object with a value of setInstFuncs: false) to it's dynamicProto() calls, then that will block ALL functions for all classes, even if a base class explicitly passes an options with it set to true. This enables any class to explicitly disable this behavior should some unknown and unexpected issue occur, if you encounter something that requires this usage then please raised an issue (or provide a PR) so we can resolve for everyone.

Included NPM distribution formats

As part of the build / publish formats via NPM we include the following module formats:

  • dist/esm – Used as the "module" definition for npm, which keeps the bundle as an ES module file, suitable for other bundlers and inclusion as a < amd – Asynchronous Module Definition, used with module loaders like RequireJS
  • dist/node - Used as the "main" npm entry point for the utility, using the umd format with any third party modules located and included using the Node resolution algorithm

Other included formats

  • dist/cjs – CommonJS, suitable for Node and other bundlers script type=module> tag in modern browsers
  • dist/iife – A self-executing function, suitable for inclusion as a <script> tag. (If you want to create a bundle for your application, you probably want to use this.)
  • dist/umd – Universal Module Definition, works as amd, cjs and iife all in one
  • dist/system – Native format of the SystemJS loader

TypeScript Declaration Helper

When using TypeScript to create classes and automatically generate the declaration (*.d.ts) files for your classes you will run into one or more of the following issues :-

  1. When you attempt to extend a base class which defines an abstract member (class) function you will get error TS2424: Class 'ABC' defines instance member function 'myFunction', but extended class 'XYZ' defines it as instance member property.
    • The only solution for this is to define an empty 'Stub' method which stops the error, but also generates an unused prototype method in your final code that just takes up space.
export abstract class ABC {
    public myFunction(someArg:string): void {
    }

    public abstract myFunction2(theArg:string, ...): void;
}

export class XYZ extends ABC {
    public myFunction2(theArg:string, ...): void {
        // This stub is required otherwise it won't compile
        // It's also extra unnecessary code in the final code
    }

    constructor() {
        dynamicProto(XYZ, this, (self, base) => {
            self.myFunction = (someArg) => {
                // This implements a member function (on the prototype)
            };

            self.myFunction2 = (theArg:string, ...) => {
            };
        });
    }
}

The above results in the following javascript output for XYZ class where the XYZ.prototype.myFunction2 is obsolete (as it gets replace), unnecessary (for the class to function) and uncompressable bloat for the code

var XYZ = /** @class */ (function () {
    function XYZ() {
        dynamicProto(XYZ, this, (self, base) => {
            // ... Removed for brevity ...
            self.myFunction2 = (theArg:string, ...) => {
            };
        });
    }
    XYZ.prototype.myFunction2 = function () {
        // This stub is required otherwise it won't compile
        // It's also extra unnecessary code in the final code
    };
    return XYZ;
}());
  1. When you are creating a class that you want users to be able to extend (using TypeScript), and you want all of the functions to be declared (in the *.d.ts) as member functions (not properties), so that the extendsion classes (using typescript) can just use the normal super keyword without forcing them to either use dynamicProto() or save / call the instance properties.
    • As with above the only solution (for dynamically generated declaration files) would be to defined Stub methods as above.
export class BaseClass {
    // A Member function
    public myFunction(someArg:string):void { 
        // Stub function
    }

    // A instance member property (which happens to be a function)
    public propFunction: (theArgs:string) => void;

    constructor() {
        dynamicProto(BaseClass, this) (self) => {
            // This will create (at runtime) a member functions
            self.myFunction = (someArg:string) => {
            };
            self.propFunction = (theArgs:string) => {
            };
        });
    }
}

export class NewClass extends BaseClass {
    // This works as TS see's that the base class has a prototype
    // function (not a property one)
    public myFunction(someArg:string:void) {
        super.myFunction(someArg);
    }

    public propFunction(theArgs:string): void {
        // This doesn't work as you can't call super on properties
        // Even though, when the base class is using dynamicProto()
        // this WILL work!
        super.propFunction(theArgs);
    }
}

So in both of these cases the only workable solutions are either :-

  • Define Stub member functions and live with the code bloat
  • Just don't use dynamicProto() and again live with the larger file size.

So assuming that you do want to continue using dynamicProto() and don't want to deal with the additional code bloat, this project includes a simple rollup plugin included in the tools/rollup folder that can be used to remove "tagged" stub code from the resulting output during packaging.

This is a Post processor that removes any code/comments (not just function) that are "tagged" from the resulting output, thus removing the Stub methods and the resulting code bloat from your final packaged code, but still leaving typescript declaration with the final (runtime) member function definition.

The plugin uses the following rules to identify and remove tagged code :-

  • The function must be a instance member function (a prototype level function) where the generated JS looks like "MyClass.prototype.methodName = function () { };"
  • The tagname must appear either on the line before the function name (pre); on the closing line of the function (post) (NOTE: Not after as TypeScript can drop this from the final output) or within the stub function (enclosed).
    // @DynamicProtoStub
    MyClass.prototype.methodName = function () {
    };
    
    MyClass.prototype.methodName = function () {
    }; // @DymanicProtoStub
    
    MyClass.prototype.methodName = function () {
        // @DynamicProtoStub
    };
    
    MyClass.prototype.methodName = function () {
        /* @DynamicProtoStub 
        * Some other comments
        */
    };
    
  • The pre and post tagging comments must be defined using a single line comment "// @DynamicProtoStub" only.
  • Enclosed tagging comments (within the function definition) may be defined using either single or multi-line comments. But the tagging comment MUST be the first comment within the function.
  • The function may be prefixed by a typedoc comment of "/** Description @param arg - arg details */" etc, which will be removed if the function is removed. However, it will not remove other prefixed single or multi-line comments.
  • The tagname must be the first "element"/"word" of any comment with optional leading spaces or tabs only.
    • e.g. These would not match "// - @DynamicProtoStub", "// This is the @DynamicProtoStub"
  • Tagging comments may contains additional trailing content (after the tagName) and will also be removed
    • "// @DynamicProtoStub - Will be removed!"
  • If the stub function appears to contain any logic, specifically a closing bracket } (including with a comment) will cause the function to not be matched and removed.
  • A final check is performed after removing all tagged functions for any remaining tags within the result and if any tags are detected it will cause the removal process to throw and fail the conversion. This ensures that if you expected a function to be removed that it has been removed.
    • If your build is failing please check that the tagging comments conform to the above rules, failures normally occur because of unexpected formatting changes.

Some possible examples

/**
 * The typedoc comments
 */
// @DynamicProtoStub
public toBeRemoved():void {
}
 
// @DynamicProtoStub
public toBeRemoved():void {
}

/**
 * This function does stuff
 * @param args - used in the function
 */
public myFunction(args:string): void {
    ...
} // @DynamicProtoStub - Function will be removed

public myFunction2(): void {
...
}  // @DynamicProtoStub - Function will be removed

/**
 * This function does stuff
 * @param args - used in the function
 */
public myFunction(args:string): void {
    // @DynamicProtoStub - Function will be removed
}

public myFunction2(): void {
    /* @DynamicProtoStub 
     * Function will be removed
     */
}  

For clarification the following will NOT match or get removed

public myFunction3(): void {
}
// @DynamicProtoStub - This method will not be removed


// @DynamicProtoStub - This method will not be removed

public myFunction4(): void {
}

public myFunction4(): void {
    /* 
     * @DynamicProtoStub 
     * This will fail because the tag is not the first 
     * "element"/"word" of any comment with optional 
     * leading spaces or tabs only. 
     */
}

public myFunction4(): void {
    // This is a stub
    /* @DynamicProtoStub 
     * This will fail because the tagging comment is not
     * the first comment within the function. 
     */
}

Adding to you own rollup.config.js

import dynamicRemove from "@microsoft/dynamicproto-js/tools/rollup/node/removedynamic";

  const moduleRollupConfig = {
    input: `${inputName}.js`,
    output: {
      file: `./dist/${format}/${outputName}.js`,
      banner: banner,
      format: format,
        name: "OutputName-JS",
      extend: true,
      sourcemap: true
    },
    plugins: [
      dynamicRemove(),
      dynamicRemove({ tagname: "@MyTagName" }),
      nodeResolve(),
      uglify({
        ie8: true,
        toplevel: true,
        compress: {
          passes:3,
          unsafe: true
        },
        output: {
          preamble: banner,
          webkit:true
        }
      })
    ]
  };

Not using Rollup?

Then let us know or simply take the embedded RegEx, and wrap it into your favorite tool and submit a PR.

It should be as simple as :-

  • Load the TypeScript generated JS output source file
  • Apply the regex using replace to "remove" the tagged code, if the named group tags where detected.
  • Write the new resulting file to the output path (or stream)
  • Do the final check for any "remaining" tags, which represents a failed matching

Version 2.x

Version 2.x is maintained on the default main branch

Breaking Changes from Version 1.x

  • Removed ES3 / IE8 support

Browser Support

  • ES5 Compliant browsers
Chrome Firefox IE9 Edge Opera Safari
Latest ✔ Latest ✔ 9+ Full ✔ Latest ✔ Latest ✔ Latest ✔

Previous Versions

Version 1.x

Version 1.x is maintained on the master branch

Browser Support (1.x)

  • ES3 Compliant browsers
Chrome Firefox IE8 Edge Opera Safari
Latest ✔ Latest ✔ 8+ Full ✔ Latest ✔ Latest ✔ Latest ✔

ES3/IE8 Compatibility

Version 1.x ONLY, 2.x DOES NOT support ES3/IE8

As a library there are numerous users which cannot control the browsers that their customers use. As such we need to ensure that this library continues to "work" and does not break the JS execution when loaded by an older browser. While it would be ideal to just not support IE8 and older generation (ES3) browsers there are numerous large customers/users that continue to require pages to "work" and as noted they may or cannot control which browser that their end users choose to use.

As part of enabling ES3/IE8 support we have set the tsconfig.json to ES3 and uglify settings in rollup.config.js transformations to support ie8. This provides a first level of support which blocks anyone from adding unsupported ES3 features to the code and enables the generated javascript to be validily parsed in an ES3+ environment.

Ensuring that the generated code is compatible with ES3 is only the first step, JS parsers will still parse the code when an unsupport core function is used, it will just fail or throw an exception at runtime. Therefore, we also need to require/use polyfil implementations or helper functions to handle those scenarios.

ES3/IE8 Features, Solutions, Workarounds and Polyfill style helper functions

This table does not attempt to include ALL of the ES3 unsupported features, just the currently known functions that where being used at the time or writing. You are welcome to contribute to provide additional helpers, workarounds or documentation of values that should not be used.

Feature Description Usage
Object.keys() Not provided by ES3 and not used N/A
ES5+ getters/setters
Object.defineProperty(...)
Not provided by ES3 and not used N/A
Object.create(protoObj, [descriptorSet]?) Not provided by ES3 and not used N/A
Object.defineProperties() Not provided by ES3 and not used N/A
Object.getOwnPropertyNames(obj) Not provided by ES3 and not used _forEachProp(target:any, callback: (name: string) => void)
Object.getPrototypeOf(obj) Not provided by ES3 and not used _getObjProto(target:any)
Object.getOwnPropertyDescriptor(obj) Not provided by ES3 and not used N/A
Object.preventExtensions(obj) Not provided by ES3 and not used N/A
Object.isExtensible(obj) Not provided by ES3 and not used N/A
Object.seal(obj) Not provided by ES3 and not used N/A
Object.isSealed(obj) Not provided by ES3 and not used N/A
Object.freeze(obj) Not provided by ES3 and not used N/A
Object.isFrozen(obj) Not provided by ES3 and not used N/A

Contributing

Read our contributing guide to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes to Application Insights.

Trademarks

This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft’s Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party’s policies.

License

MIT

dynamicproto-js's People

Contributors

microsoft-github-operations[bot] avatar microsoftopensource avatar msnev avatar xiao-lix avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dynamicproto-js's Issues

Semmle warning help

We have bunch of Semmle warning being reported from nuget package that we're consuming. Wanted to check with them if they're being addressed already?

[Feature Request] Performance optimization - ability to keep/set instance level function to avoid dynamic proxy lookup

As part of some performance optimizations, it would be helpful if when as part of creating dynamic prototype method (to support class extension/inheritance) that the instance level methods are either

  • left in place (and not erased)
  • on first execution of a prototype proxy if no instance method is assign to assign the instance level function.

Both of these options will assist with declaring classes to use dyamicProto() that are called frequently (or in tight loops) so that once the instance level function is defined it avoids the dynamic proxy lookups added as the prototype functions.

[Enhancement] A Post Processor is required for WebPack to remove @DynamicProtoStub tagged methods

While a rollup plugin is available to remove the stub functions tagged with @DynamicProtoStub, we should really look at providing a version for WebPack.

As per the readme, tagged functions/methods should be removed from the resulting code as they are necessary to ensure that TypeScript provides the correct resulting definition (*.d.ts) where the functions are declared as "prototype" level functions.

/**
 * The typedoc comments
 */
// @DynamicProtoStub
public toBeRemoved():void {
}
 
// @DynamicProtoStub
public toBeRemoved():void {
}

/**
 * This function does stuff
 * @param args - used in the function
 */
public myFunction(args:string): void {
    ...
} // @DynamicProtoStub - Function will be removed

public myFunction2(): void {
...
}  // @DynamicProtoStub - Function will be removed

/**
 * This function does stuff
 * @param args - used in the function
 */
public myFunction(args:string): void {
    // @DynamicProtoStub - Function will be removed
}

public myFunction2(): void {
    /* @DynamicProtoStub 
     * Function will be removed
     */
}  

[BUG] _checkPrototype function loops indefinitely when calling Invoke-WebRequest cmdlet against a docs.microsoft.com webpage

Description/Screenshot

This is related with the issue described at https://docs.microsoft.com/en-us/answers/questions/329655/powershell-invoke-webrequest-to-httpsdocsmicrosoft.html. Upon debugging the issue, it seems we loop indefinitely in a javascript function from this SDK, hence this issue.

The goal here is to verify that changes have recently been done in this area and if any IE quirk may need to be accounted for.

Steps to Reproduce

  1. Open a PowerShell command line and type in the following command:

Invoke-WebRequest -Uri https://docs.microsoft.com/en-us/windows-server/remote/remote-desktop-services/clients/windowsdesktop-whatsnew

  1. The command may never return and you'll see powershell.exe going 100% CPU indefinitely

From the Invoke-WebRequest documentation:

The Invoke-WebRequest cmdlet sends HTTP and HTTPS requests to a web page or web service. It parses the response and returns collections of links, images, and other significant HTML elements.

This parsing is performed by using IE's mshtml.dll module, which may be part of the problem. Inspecting the CPU hogging PowerShell process, it seems we loop indefinitely in the following function:

	function _checkPrototype(classProto, thisTarget) {
        var thisProto = _getObjProto$1(thisTarget);
        while (thisProto && !_isObjectArrayOrFunctionPrototype(thisProto)) {
            if (thisProto === classProto) {
                return true;
            }
            thisProto = _getObjProto$1(thisProto);
        }
        return false;
    }
  • OS/Browser: Windows 10 20H2
  • SDK Version [e.g. 22]: latest stable
  • How you initialized the SDK:

Expected behavior

The command returns with the DOM elements parsed. This can be observed by targeting any other URL for the Invoke-WebRequest cmdlet, not matter how complex the page may be.

Additional context

This is affecting enterprise customers that rely on this method to parse docs.microsoft.com content for certain internal processes.

Originally raised by @apmpinho

Bump external library Sinon.JS to newer version which does not use eval

As described in ticket Azure/azure-sdk-for-js#24903 the current version of the external library Sinon.JS (1.17.2 from 2015) uses eval for some purpose and therefore all projects that use Microsoft Dynamic Proto Utility or libraries depending on it (like @azure/communication-calling) are required to allow script-src: unsafe-eval in the CSP policy.

Would it be possible to use at least version 2.0.0 (from 2017), which does not use eval anymore? (Ticket: sinonjs/sinon#710, Releasenotes: https://github.com/sinonjs/sinon/releases/tag/v2.0.0)

Add sideEffects field to package.json

To make this package optimizeable via webpack tree shaking, please add a correct sideEffects field to the package.json file for this lib.

I care about this b/c the dynamicproto-js lib is a transitive dependency of @microsoft/applicationinsights-web . All the other dependencies of @microsoft/applicationinsights-web have this field correctly set.

[Bug] Corner case issue when extending the same "Class" name from different components

There is a corner case issue that occurs when "extending" an existing class which has the same class name where

  • Both classes are using the same "Name"
  • Both classes are using dynamicProto
  • The base class has already been initialized from a is being from a different module
  • The base class doesn't extend any other class or only extends from classes that don't use dynamic proto
  • The runtime has enabled useBaseInst config options (Used for unit testing) <- The Issue does NOT occur with this setting

eg.
import { AppInsightsCore as InternalCore } from "..."
class AppInsightsCore extends InternalCore {}

This results in both the base class and the new extension class getting assigned the same "dynamic classname" which when the class calls the base class function with the same name results in it calling itself -- resulting in a stack overflow.

Version 1.1.2 has extraneous dependencies such as findup-sync

When installed via npm, I'm seeing 3 extraneous dependencies:

    "findup-sync": "^4.0.0",
    "nopt": "^5.0.0",
    "pify": "^2.3.0"

For context, here's the full resolved package.json I get in node_modules/@microsoft/dynamicproto-js:

{
  "_from": "@microsoft/dynamicproto-js",
  "_id": "@microsoft/[email protected]",
  "_inBundle": false,
  "_integrity": "sha512-lKhE+Jc8l4shvYF4C++WAMXpufxpQzBA/OoAAUq7kEPu5e+X+Cj2H8gGRobgz5eyrw3fGfpwUf2+4mfgmYMSLA==",
  "_location": "/@microsoft/dynamicproto-js",
  "_phantomChildren": {},
  "_requested": {
    "type": "tag",
    "registry": true,
    "raw": "@microsoft/dynamicproto-js",
    "name": "@microsoft/dynamicproto-js",
    "escapedName": "@microsoft%2fdynamicproto-js",
    "scope": "@microsoft",
    "rawSpec": "",
    "saveSpec": null,
    "fetchSpec": "latest"
  },
  "_requiredBy": [
    "#USER",
    "/"
  ],
  "_resolved": "https://registry.npmjs.org/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.2.tgz",
  "_shasum": "a6c8f27c01d53e613c6f02d0d20dacca7eb3a3b7",
  "_spec": "@microsoft/dynamicproto-js",
  "_where": "C:\\Code\\test-package",
  "author": {
    "name": "Microsoft Application Insights Team"
  },
  "bugs": {
    "url": "https://github.com/microsoft/DynamicProto-JS/issues"
  },
  "bundleDependencies": false,
  "dependencies": {
    "findup-sync": "^4.0.0",
    "nopt": "^5.0.0",
    "pify": "^2.3.0"
  },
  "deprecated": false,
  "description": "Microsoft Dynamic Proto Utility",
  "devDependencies": {
    "grunt": "~1.0.1",
    "grunt-cli": "^1.4.2",
    "grunt-contrib-qunit": "^3.1.0",
    "grunt-contrib-uglify": "^3.1.0",
    "grunt-run": "^0.8.1",
    "grunt-ts": "^6.0.0-beta.22",
    "grunt-tslint": "^5.0.2",
    "rollup": "^1.27.2",
    "tslint": "^5.19.0",
    "tslint-config-prettier": "^1.18.0",
    "tslint-microsoft-contrib": "^5.2.1",
    "typedoc": "^0.15.1",
    "typescript": "3.7.2"
  },
  "directories": {
    "doc": "lib/docs"
  },
  "homepage": "https://github.com/microsoft/DynamicProto-JS#readme",
  "keywords": [
    "javascript",
    "dynamic prototype",
    "microsoft",
    "typescript",
    "inheritence",
    "minification",
    "application insights"
  ],
  "license": "MIT",
  "main": "./lib/dist/node/dynamicproto-js.js",
  "module": "./lib/dist/esm/dynamicproto-js.js",
  "name": "@microsoft/dynamicproto-js",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/microsoft/DynamicProto-JS.git"
  },
  "scripts": {
    "build": "node common/scripts/install-run-rush.js rebuild",
    "docs": "typedoc --out docs lib/src --excludePrivate --excludeProtected --tsconfig lib/tsconfig.json --theme minimal",
    "rollup": "grunt rollup",
    "test": "grunt dynamicprototest",
    "travisinit": "node common/scripts/install-run-rush.js update --recheck --full"
  },
  "sideEffects": false,
  "types": "./lib/types/dynamicproto-js.d.ts",
  "version": "1.1.2"
}

I looked through this package's source briefly, and I wonder if it might be the rush build setup which is causing this? Normally I'd expect rush to be used in monorepos, but here it seems there isn't a distinction between the development root package.json and the single package being published. If that theory is correct then this would probably apply to previous versions as well.

Any help is appreciated, thanks!

Exclude files from published package

Hi, I noticed that npm package for this library includes files that seem like they should not be published:

  • microsoft-dynamicproto-js-1.1.7.tgz — a zip of the project itself?
  • lib/test — Tests?
  • list/docs — Documentation?
  • Top level documentation files such as CODE_OF_CONDUCT.md, SUPPORT.md

Removing these will cut the on-disk size of the install by more than 50%

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.