Showing posts with label ecmascript-6. Show all posts
Showing posts with label ecmascript-6. Show all posts

Monday, August 6, 2018

Using React within a dynamically loaded es module

Leave a Comment

I have been loading a native ES Module which can be simplified to src/test.tsx:

export default class Test {     constructor() {         console.log('loaded');     } } 

I can load this in my browser and initialize it great, a la:

import('http://127.0.0.1:8085/').then(m => {    const instance = new m.default(); }); 

However.. if I want to add any external dependency, in this case React, I can't seem to figure out how to target es6 and also bundle React, with tsc. So my dist file contains import React from 'react'; for which the browser has no idea how to resolve, and produces:

(index):1 Uncaught (in promise) TypeError: Failed to resolve module specifier "react". Relative references must start with either "/", "./", or "../".

My tsconfig looks like:

{     "compilerOptions": {         "baseUrl": ".",         "rootDir": "src",         "module": "es6",         "target": "es2015",         "lib": ["es6", "dom"],         "declaration": true,         "jsx": "react",         "outDir": "dist",         "strict": true,         "noImplicitAny": false,         "allowSyntheticDefaultImports": true,         "esModuleInterop": true,         "experimentalDecorators": true,         "moduleResolution": "node",         "skipLibCheck": true     },     "include": ["./src/**/*"] } 

Running node v9.5.0, typescript v2.9.2

I have also attempted to use webpack to bundle everything but cannot figure out how to produce a dynamically importable module that way

2 Answers

Answers 1

Please use tsconfig.json as below :-

   {   "compilerOptions": {     "baseUrl": ".",     "outDir": "build/dist",     "module": "esnext",     "target": "es5",     "lib": ["es6", "dom","esnext.asynciterable"],     "sourceMap": true,     "allowJs": true,     "jsx": "react",     "moduleResolution": "node",     "rootDir": "src",     "forceConsistentCasingInFileNames": true,     "noImplicitReturns": true,     "noImplicitThis": true,     "noImplicitAny": true,     "strictNullChecks": true,     "suppressImplicitAnyIndexErrors": true,     "noUnusedLocals": true,     "allowSyntheticDefaultImports": true,          //Important for your problem     "experimentalDecorators": true,   },   "exclude": [     "node_modules",     "build",     "scripts",     "acceptance-tests",     "webpack",     "jest",     "src/setupTests.ts"   ] } 

Answers 2

With tsc-bundler, you can use the importAs switch to make it correctly bundle external references. This switch is not yet available as a tsconfig option.

E.g.

tsc-bundle --project ./tsconfig.json --importAs react=React,react-dom=ReactDOM 
Read More

Thursday, January 25, 2018

Can (a ==1 && a== 2 && a==3) ever evaluate to true?

Leave a Comment

Is it ever possible that (a ==1 && a== 2 && a==3) could evaluate to true in JavaScript?

This is an interview question asked by a major tech company. It happened 2 weeks back, but I'm still trying to find the answer. I know we never write such code in our day to day job, but I'm curious.

30 Answers

Answers 1

If you take advantage of how == works, you could simply create an object with a custom toString (or valueOf) function that changes what it returns each time it is used such that it satisfies all three conditions.

const a = {    i: 1,    toString: function () {      return a.i++;    }  }    if(a == 1 && a == 2 && a == 3) {    console.log('Hello World!');  }


The reason this works is due to the use of the loose equality operator. When using loose equality, if one of the operands is of a different type than the other, the engine will attempt to convert one to the other. In the case of an object on the left and a number on the right, it will attempt to convert the object to a number by first calling valueOf if it is callable, and failing that, it will call toString. I used toString in this case simply because it's what came to mind, valueOf would make more sense. If I instead returned a string from toString, the engine would have then attempted to convert the string to a number giving us the same end result, though with a slightly longer path.

Answers 2

I couldn't resist - the other answers are undoubtedly true, but you really can't walk past the following code:

var aᅠ = 1;  var a = 2;  var ᅠa = 3;  if(aᅠ==1 && a== 2 &&ᅠa==3) {      console.log("Why hello there!")  }

Note the weird spacing in the if statement (that I copied from your question). It is the half-width Hangul (that's Korean for those not familiar) which is an Unicode space character that is not interpreted by ECMA script as a space character - this means that it is a valid character for an identifier. Therefore there are three completely different variables, one with the Hangul after the a, one with it before and the last one with just a. Replacing the space with _ for readability, the same code would look like this:

var a_ = 1;  var a = 2;  var _a = 3;  if(a_==1 && a== 2 &&_a==3) {      console.log("Why hello there!")  }

Check out the validation on Mathias' variable name validator. If that weird spacing was actually included in their question, I feel sure that it's a hint for this kind of answer.

Don't do this. Seriously.

Answers 3

IT IS POSSIBLE!

var i = 0;    with({    get a() {      return ++i;    }  }) {    if (a == 1 && a == 2 && a == 3)      console.log("wohoo");  }

This uses a getter inside of a with statement to let a evaluate to three different values.

... this still does not mean this should be used in real code...

Answers 4

Example without getters or valueOf:

a = [1,2,3];  a.join = a.shift;  console.log(a == 1 && a == 2 && a == 3);

This works because == invokes toString which calls .join for Arrays.

Another solution, using Symbol.toPrimitive which is an ES6 equivalent of toString/valueOf:

let a = {[Symbol.toPrimitive]: ((i) => () => ++i) (0)};    console.log(a == 1 && a == 2 && a == 3);

Answers 5

If it is asked if it is possible (not MUST), it can ask "a" to return a random number, it would be true if it generates 1,2 and 3 sequentially.

with({    get a() {      return Math.floor(Math.random()*4);    }  }){    for(var i=0;i<1000;i++){      if (a == 1 && a == 2 && a == 3){        console.log("after "+(i+1)+" trials, it becomes true finally!!!");        break;      }    }  }

Answers 6

When you can't do anything without regular expressions:

var a = {    r: /\d/g,     valueOf: function(){      return this.r.exec(123)[0]    }  }    if (a == 1 && a == 2 && a == 3) {      console.log("!")  }

It works because of custom valueOf method that is called when Object compared with primitive (such as Number). Main trick is that a.valueOf returns new value every time because it's calling exec on regular expression with g flag, which causing updating lastIndex of that regular expression every time match is found. So first time this.r.lastIndex == 0, it matches 1 and updates lastIndex: this.r.lastIndex == 1, so next time regex will match 2 and so on.

Answers 7

It can be accomplished using the following in the global scope. For nodejs use global instead of window in the code below.

var val = 0;  Object.defineProperty(window, 'a', {    get: function() {      return ++val;    }  });  if (a == 1 && a == 2 && a == 3) {    console.log('yay');  }

This answer abuses the implicit variables provided by the global scope in the execution context by defining a getter to retrieve the variable.

Answers 8

This is also possible using a series of self-overwriting getters:

(This is similar to jontro's solution, but doesn't require a counter variable.)

(() => {      "use strict";      Object.defineProperty(this, "a", {          "get": () => {              Object.defineProperty(this, "a", {                  "get": () => {                      Object.defineProperty(this, "a", {                          "get": () => {                              return 3;                          }                      });                      return 2;                  },                  configurable: true              });              return 1;          },          configurable: true      });      if (a == 1 && a == 2 && a == 3) {          document.body.append("Yes, it’s possible.");      }  })();

Answers 9

This is possible in case of variable a being accessed by, say 2 web workers through a SharedArrayBuffer as well as some main script. The possibility is low, but it is possible that when the code is compiled to machine code, the web workers update the variable a just in time so the conditions a==1, a==2 and a==3 are satisfied.

This can be an example of race condition in multi-threaded environment provided by web workers and SharedArrayBuffer in JavaScript.

Here is the basic implementation of above:

main.js

// Main Thread  const worker = new Worker('worker.js') const modifiers = [new Worker('modifier.js'), new Worker('modifier.js')] // Let's use 2 workers const sab = new SharedArrayBuffer(1)  modifiers.forEach(m => m.postMessage(sab)) worker.postMessage(sab) 

worker.js

let array  Object.defineProperty(self, 'a', {   get() {     return array[0]   } });  addEventListener('message', ({data}) => {     array = new Uint8Array(data)     let count = 0     do {         var res = a == 1 && a == 2 && a == 3         ++count     } while(res == false) // just for clarity. !res is fine     console.log(`It happened after ${count} iterations`)     console.log('You should\'ve never seen this') }) 

modifier.js

addEventListener('message' , ({data}) => {     setInterval( () => {         new Uint8Array(data)[0] = Math.floor(Math.random()*3) + 1     }) }) 

On my MacBook Air, it happens after around 10 billion iterations on the first attempt:

enter image description here

Second attempt:

enter image description here

As I said, the chances will be low, but given enough time, it'll hit the condition.

Tip: If it takes too long on your system. Try only a == 1 && a == 2 and change Math.random()*3 to Math.random()*2. Adding more and more to list drops the chance of hitting.

Answers 10

I don't see this answer already posted, so I'll throw this one into the mix too. This is similar to Jeff's answer with the half-width Hangul space.

var a = 1;  var a = 2;  var а = 3;  if(a == 1 && a == 2 && а == 3) {      console.log("Why hello there!")  }

You might notice a slight discrepancy with the second one, but the first and third are identical to the naked eye. All 3 are distinct characters:

a - Latin lower case A
a - Full Width Latin lower case A
а - Cyrillic lower case A

The generic term for this is "homoglyphs": different unicode characters that look the same. Typically hard to get three that are utterly indistinguishable, but in some cases you can get lucky. A, Α, А, and Ꭺ would work better (Latin-A, Greek Alpha, Cyrillic-A, and Cherokee-A respectively; unfortunately the Greek and Cherokee lower-case letters are too different from the Latin a: α,ꭺ, and so doesn't help with the above snippet).

There's an entire class of Homoglyph Attacks out there, most commonly in fake domain names (eg. wikipediа.org (Cyrillic) vs wikipedia.org (Latin)), but it can show up in code as well; typically referred to as being underhanded (as mentioned in a comment, [underhanded] questions are now off-topic on PPCG, but used to be a type of challenge where these sorts of things would show up). I used this website to find the homoglyphs used for this answer.

Answers 11

Alternatively, you could use a class for it and an instance for the check.

function A() {      var value = 0;      this.valueOf = function () { return ++value; };  }    var a = new A;    if (a == 1 && a == 2 && a == 3) {      console.log('bingo!');  }

Answers 12

Javascript

a == a +1

In Javascript, there are no integers but only Numbers, which are implemented as double precision floating point number.

It means that if a Number a is large enough, it can be considered equal to 3 consecutive integers:

a = 100000000000000000  if (a == a+1 && a == a+2 && a == a+3){    console.log("Precision loss!");  }

True, it's not exactly what the interviewer asked (it doesn't work with a=0), but it doesn't involve any trick with hidden functions or operator overloading.

Other languages

For reference, there are a==1 && a==2 && a==3 solutions in Ruby and Python. With a slight modification, it's also possible in Java.

Ruby

With a custom ==:

class A   def ==(o)     true   end end  a = A.new  if a == 1 && a == 2 && a == 3   puts "Don't do this!" end 

or an increasing a:

def a   @a ||= 0   @a += 1 end  if a == 1 && a == 2 && a == 3   puts "Don't do this!" end 

Python

class A:     def __eq__(self, who_cares):         return True a = A()  if a == 1 and a == 2 and a == 3:     print("Don't do that!") 

Java

It's possible to modify Java Integer cache:

package stackoverflow;  import java.lang.reflect.Field;  public class IntegerMess {     public static void main(String[] args) throws Exception {         Field valueField = Integer.class.getDeclaredField("value");         valueField.setAccessible(true);         valueField.setInt(1, valueField.getInt(42));         valueField.setInt(2, valueField.getInt(42));         valueField.setInt(3, valueField.getInt(42));         valueField.setAccessible(false);          Integer a = 42;          if (a.equals(1) && a.equals(2) && a.equals(3)) {             System.out.println("Bad idea.");         }     } } 

Answers 13

Rule number one of interviews; never say impossible.

No need for hidden character trickery.

window.__defineGetter__( 'a', function(){      if( typeof i !== 'number' ){          // define i in the global namespace so that it's not lost after this function runs          i = 0;      }      return ++i;  });    if( a == 1 && a == 2 && a == 3 ){      alert( 'Oh dear, what have we done?' );  }

Answers 14

This is an inverted version of @Jeff's answer* where a hidden character (U+115F, U+1160 or U+3164) is used to create variables that look like 1, 2 and 3.

var  a = 1;  var ᅠ1 = a;  var ᅠ2 = a;  var ᅠ3 = a;  console.log( a ==ᅠ1 && a ==ᅠ2 && a ==ᅠ3 );

* That answer can be simplified by using zero width non-joiner (U+200C) and zero width joiner (U+200D). Both of these characters are allowed inside identifiers but not at the beginning:

var a = 1;  var a‌ = 2;  var a‍ = 3;  console.log(a == 1 && a‌ == 2 && a‍ == 3);    /****  var a = 1;  var a\u200c = 2;  var a\u200d = 3;  console.log(a == 1 && a\u200c == 2 && a\u200d == 3);  ****/

Other tricks are possible using the same idea e.g. by using Unicode variation selectors to create variables that look exactly alike (a︀ = 1; a︁ = 2; a︀ == 1 && a︁ == 2; // true).

Answers 15

Honestly though, whether there is a way for it to evaluate to true or not (and as others have shown, there are multiple ways), the answer I'd be looking for, speaking as someone who has conducted hundreds of interviews, would be something along the lines of:

"Well, maybe yes under some weird set of circumstances that aren't immediately obvious to me... but if I encountered this in real code then I would use common debugging techniques to figure out how and why it was doing what it was doing and then immediately refactor the code to avoid that situation... but more importantly: I would absolutely NEVER write that code in the first place because that is the very definition of convoluted code, and I strive to never write convoluted code".

I guess some interviewers would take offense to having what is obviously meant to be a very tricky question called out, but I don't mind developers who have an opinion, especially when they can back it up with reasoned thought and can dovetail my question into a meaningful statement about themselves.

Answers 16

Javascript

Yes, it is possible! 😎

if‌=()=>!0;  var a = 9;    if‌(a==1 && a== 2 && a==3)  {      document.write("<h1>Yes, it is possible!😎</h1>")  }

The above code is a short version (thanks to @Forivin for its note in comments) and the following code is original:

var a = 9;    if‌(a==1 && a== 2 && a==3)  {      //console.log("Yes, it is possible!😎")      document.write("<h1>Yes, it is possible!😎</h1>")  }    //--------------------------------------------    function if‌(){return true;}

If you just see top side of my code and run it you say WOW, how?

So I think it is enough to say Yes, it is possible to someone that said to you: Nothing is impossible

Trick: I used a hidden character after if to make a function that its name is similar to if. In JavaScript we can not override keywords so I forced to use this way. It is a fake if but works for you in this case!


C#:

Also I wrote a C# version (with increase property value technic): Live Demo

static int _a; public static int a {get{ ++_a; return _a;}}  public static void Main() {     if(a==1 && a==2 && a==3)     {         Console.WriteLine("Yes, it is possible!😎");     } } 

Answers 17

Here's another variation, using an array to pop off whatever values you want.

const a = {    n: [3,2,1],    toString: function () {      return a.n.pop();    }  }    if(a == 1 && a == 2 && a == 3) {    console.log('Yes');  }

Answers 18

If you ever get such an interview question (or notice some equally unexpected behavior in your code) think about what kind of things could possibly cause a behavior that looks impossible at first glance:

  1. Encoding: In this case the variable you are looking at is not the one you think it is. This can happen if you intentionally mess around with Unicode using homoglyphs or space characters to make the name of a variable look like another one, but encoding issues can also be introduced accidentally, e.g. when copying & pasting code from the Web that contains unexpected Unicode code points (e.g. because a content management system did some "auto-formatting" such as replacing fl with Unicode 'LATIN SMALL LIGATURE FL' (U+FB02)).

  2. Race conditions: A race-condition might occur, i.e. a situation where code is not executing in the sequence expected by the developer. Race conditions often happen in multi-threaded code, but multiple threads are not a requirement for race conditions to be possible – Asynchronicity is sufficient. Note that therefore JavaScript is also not free from race conditions just because it is single-threaded (unless you are using web workers1). See here for a simple single-threaded – but async – example. In the context of an if-statement the race condition however would be rather hard to hit in JavaScript without web workers.

  3. Side-effects: A side-effect of the equality comparison operation (which doesn't have to be as obvious as in the examples here, often side-effects are very subtle).

These kind of issues can appear in many programming languages, not only JavaScript, so we aren't seeing one of the classical JavaScript WTFs here2.

Of course, the interview question and the samples here all look very contrived. But they are a good reminder that:

  • Side-effects can get really nasty and that a well-designed program should be free from unwanted side-effects.
  • Multi-threading and mutable state can be problematic.
  • Not doing character encoding and string processing right can lead to nasty bugs.

1 @mehulmpt has a great proof-of-concept using web workers.

2 For example, you can find an example in a totally different programming language (C#) exhibiting a side-effect (an obvious one) here.

Answers 19

Okay, another hack with generators:

const value = function* () {    let i = 0;    while(true) yield ++i;  }();    Object.defineProperty(this, 'a', {    get() {      return value.next().value;    }  });    if (a === 1 && a === 2 && a === 3) {    console.log('yo!');  }

Answers 20

Actually the answer to the first part of the question is "Yes" in every programming language. For example, this is in the case of C/C++:

#define a   (b++) int b = 1; if (a ==1 && a== 2 && a==3) {     std::cout << "Yes, it's possible!" << std::endl; } else {     std::cout << "it's impossible!" << std::endl; } 

Answers 21

Same, but different, but still same (can be "tested" multiple times):

const a = { valueOf: () => this.n = (this.n || 0) % 3 + 1}        if(a == 1 && a == 2 && a == 3) {    console.log('Hello World!');  }    if(a == 1 && a == 2 && a == 3) {    console.log('Hello World!');  }

My idea started from how Number object type equation works.

Answers 22

Since I haven't seen any answers using Proxies yet:

var a = new Proxy({ i: 0 }, {     get: (target, name) => name === Symbol.toPrimitive ? () => ++target.i : target[name], }); console.log(a == 1 && a == 2 && a == 3); 

Proxies basically pretend to be a target object (the first parameter) but intercept operations on the target object (in this case the "get property" operation) so that there is an opportunity to do something other than the default object behavior. In this case the "get property" action is called on a when == coerces its type in order to compare it to each number. So what's happening here is:

  1. We create a target object, { i: 0 }, where the i property is our counter
  2. We create a Proxy for the target object and assign it to a
  3. For each a == comparison, a's type is coerced to a primitive value
  4. This type coercion results in calling a[Symbol.toPrimitive]() internally
  5. The Proxy intercepts getting the a[Symbol.toPrimitive] function using the "get handler"
  6. The Proxy's "get handler" checks that the property being gotten is Symbol.toPrimitive, in which case it increments and then returns the counter from the target object: ++target.i. If a different property is being retrieved, we just fall back to returning the default property value, target[name]

So:

var a = ...; // a.valueOf == target.i == 0 a == 1 && // a == ++target.i == 1 a == 2 && // a == ++target.i == 2 a == 3    // a == ++target.i == 3 

As with most of the other answers, this only works with a loose equality check (==) because strict equality checks (===) do not do type coercion that the Proxy can intercept.

Answers 23

I think this is the minimal code to implement it:

i=0,a={valueOf:()=>++i}    if (a == 1 && a == 2 && a == 3) {    console.log('Mind === Blown');  }

Creating a dummy object with a custom valueOf that increments a global variable i on each call. 23 characters!

Answers 24

An ES6 answer that makes use of Symbols:

const a = {value: 1}; a[Symbol.toPrimitive] = function() { return this.value++ }; console.log((a == 1 && a == 2 && a == 3)); 

Due to == usage, Javascript is supposed to coerce a into something close to the second operand (1, 2, 3 in this case). But before Javascript tries to figure coercing on its own, it tries to call Symbol.toPrimitive. If you provide Symbol.toPrimitive JS would use the value your function returns. If not, JS would call valueOf.

Answers 25

This one uses the defineProperty with a nice side-effect causing global variable!

var _a = 1    Object.defineProperty(this, "a", {    "get": () => {      return _a++;    },    configurable: true  });    console.log(a)  console.log(a)  console.log(a)

Answers 26

Even without confusing naming, overloading, or random variables, a == 1 && a == 2 && a == 3 can return true in multi-threaded environments as the value of a may change between each comparison as long as it is not thread-safe.

Answers 27

The main reason why this could be equals is == operators, with === won't work.

const a = {     i: 0;     valueOf: function() {        return this.i++;     }  }  if(a == 1 && a == 2 && a == 3) // true 

Because the methods valueOf and toString will be called when the == operators are used.

if(a === 1 && a === 2 && a === 3) // false 

The valueOf and toString methods are not called.

Answers 28

Another solution is to override the prototype.toString function for a Set structure from Javascript.

Suppose we have a Set called a with three values.

var a = new Set([1,2,3]); 

When we compare one Set with a primitive type it's triggered toString function from Set class because we need to coerce the left member.

Set.prototype.toString=function(){    let first = [...a][0];    this.delete(first);    return first; } 

var a=new Set([1,2,3]);  Set.prototype.toString = function(){     let first = [...a][0];     this.delete(first);     return first;  }  console.log(a==1 && a==2 && a==3);

In fact, since we compare two different data types , we can do that with a lot of data structures from javascript and we have advantage that javascript is weakly-typed language.

We just need to override the toString property of given data type, because when we use == it invokes toString function.

Answers 29

If you use webpack, you can use a lovely config like that:

const { DefinePlugin } = require('webpack') const config = {     plugins: [         new DefinePlugin({ 'a': '(window.a = ++window.a || 1)' })     ] } 

Answers 30

While there are already a lot of good answers to the question, but my response to the interviewer will be:

Yes, there may special cases that will make this expression evaluated to true but I will try to avoid coding like this. As it is not good coding practice and will create confusions to the future maintainers of the code.

Read More

Tuesday, October 31, 2017

Lost context in object

Leave a Comment

I have this code:

/// global context function Outer(){     /// Outer context     this.print = function(){          console.log("1: "+this)          inside(); /// "this" is bound to the global object. Why not bound to the Outer object?         function inside(){              console.log("2: "+this)          }     };  }  function print(){     console.log("3: "+this); } var obj = new Outer;  obj.print(); /// "this" is bound to the Outer object. print(); /// "this" is bound to the global object. 

Why inside the method call, this has a global object? Can anyone explain this?

6 Answers

Answers 1

That's because, its obeying following 2 JS rules

  • Rule 1. In Javascript, new function = new scope - that’s the rule.
  • Rule 2. When a function is called as a method of an object, this is set to the object the method is called on.

Explanation of the code:

  • For rule 2, this.print() is a feature of Outer object. So this will refer to the Outer object.

So the console.log 1 will print 1: [object Object]

  • For rule 1, the function inside() in Outer is not a feature of Outer object. So new scope will created and this assigned to window. And that's also same for the last function 'print()'

So console.log 2 will print 2: [object Window]

And console.log 3 will print 3: [object Window] as well

Hope Helps,

Run the code: https://es6console.com/j9bxeati/

Reference: https://toddmotto.com/everything-you-wanted-to-know-about-javascript-scope/#function-scope

Answers 2

As the reference states,

In most cases, the value of this is determined by how a function is called. It can't be set by assignment during execution, and it may be different each time the function is called. ES5 introduced the bind method to set the value of a function's this regardless of how it's called, and ES2015 introduced arrow functions which do provide their own this binding (it remains the this value of the enclosing lexical context).

<...>

Inside a function, the value of this depends on how the function is called.

<...>

Since the following code is not in strict mode, and because the value of this is not set by the call, this will default to the global object

<...>

So, in strict mode, if this was not defined by the execution context, it remains undefined.

The posted code is not executed in strict mode, so this equals to global variable (window) inside the function when it's called like print().

If this is not the desirable behaviour, and print is expected to be called separately from the object it originally was defined on (e.g. when being passed as a callback), the function can be bound to its lexical this with arrow in ES6:

function Outer(){     this.print = () => { ... };  }  

In ES5 bind or self = this recipe can be used:

function Outer(){     this.print = (function(){ ... }).bind(this); }  function Outer(){     var self = this;     this.print = function(){       self;       ...     }; } 

If the function isn't expected to be called with another context, it can be called with another context in-place:

print.call(this); 

Or:

print.bind(this)(); 

Answers 3

If it is not obvious for you, that probably means you confuse scope and context of the function. Scope is what vars function has access to during invocation. Context (this) is determined by how function is invoked.

Now look on how you invoke your function 'inside' and answer the question. Does it vividly owned by any object? That is why you have global

Answers 4

The value of this is determined by how a function is called.

Your "inside" function was called inside "print" function, which has an object reference, but that object did not have "inside" function as a property or that object did not invoke "inside" function.

"this" refers to the object which called it, not the scope in which it is called. Hence, the global object

Answers 5

A function's this keyword behaves a little differently in JavaScript compared to other languages. It also has some differences between strict mode and non-strict mode.

In most cases, the value of this is determined by how a function is called. It can't be set by assignment during execution, and it may be different each time the function is called. ES5 introduced the bind method to set the value of a function's this regardless of how it's called, and ES2015 introduced arrow functions which do provide their own this binding (it remains the this value of the enclosing lexical context).

// An object can be passed as the first argument to call or apply and this will be bound to it.  var obj = {a: 'Custom'};    // This property is set on the global object  var a = 'Global';    function whatsThis(arg) {    return this.a;  // The value of this is dependent on how the function is called  }    whatsThis();          // 'Global'  whatsThis.call(obj);  // 'Custom'  whatsThis.apply(obj); // 'Custom'

Answers 6

the value of this is depends on how you are making a call to the intended function and generally leading parent object plays important role in it.

what does it mean by leading parent object?:

sampleObj.getDetails(); // here 'sampleObj' is the leading parent object for 'getDetails()' function 

lets try to clear the things using some examples of making call to the function using below sample code snippet.

function globalFunction(){     console.log('global this: ', this); } var simpleObj = {   name : 'john'  }; var complexObj = {   outer: function(){     console.log('outer this: ', this);   } } globalFunction(); // will log global object as no leading parent object is available  complexObj.outer(); // will log 'complexObj' object as leading parent object is 'complexObj'  complexObj.outer = complexObj.outer.bind(simpleObj); complexObj.outer(); // will log 'simpleObj' object as we have set preference as 'simpleObj' for this **  complexObj.outer.call(); // will log global object as we arent setting any preference for 'this' ***  complexObj.outer.call(simpleObj); // will log simpleObj object as we have set preference as simpleObj for 'this' ***  complexObj.outer.apply(); // will log global object as we arent setting any preference for 'this' ****  complexObj.outer.apply(simpleObj); // will log simpleObj object as we have set preference as simpleObj for 'this' **** 

hopefully it will help you!

** what is bind: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

*** what is call: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call

**** what is apply: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply

Read More

Thursday, October 19, 2017

Create ES6/ESNext prototype function with different scope (not an inline function)

Leave a Comment

Ok say we have this:

class Car {     constructor(name) {         this.kind = 'Car';         this.name = name;     }      printName() {         console.log('this.name');     } } 

what I want to do is define printName, something like this:

class Car {     constructor(name) {         this.kind = 'Car';         this.name = name;     }      // we want to define printName using a different scope     // this syntax is close, but is *not* quite correct     printName: makePrintName(foo, bar, baz)  } 

where makePrintName is a functor, something like this:

exports.makePrintName = function(foo, bar, baz){    return function(){ ... } }; 

is this possible with ES6? My editor and TypeScript is not liking this

NOTE: using ES5, this was easy to do, and looks like this:

var Car = function(){...};  Car.prototype.printName = makePrintName(foo, bar, baz); 

Using class syntax, currently the best thing that is working for me, is this:

const printName = makePrintName(foo,bar,baz);  class Car {   constructor(){...}   printName(){     return printName.apply(this,arguments);   } } 

but that is not ideal. You will see the problem if you try to use class syntax to do what ES5 syntax can do. The ES6 class wrapper, is therefore a leaky abstraction.

To see the real-life use case, see:

https://github.com/sumanjs/suman/blob/master/lib/test-suite-helpers/make-test-suite.ts#L171

the problem with using TestBlock.prototype.startSuite = ..., is that in that case, I cannot simply return the class on line:

https://github.com/sumanjs/suman/blob/master/lib/test-suite-helpers/make-test-suite.ts#L67

5 Answers

Answers 1

The preferable ways to do this in JavaScript and TypeScript may differ due to limitations in typing system, but if printName is supposed to be a prototype method and not instance method (the former is beneficial for several reasons), there are not so many options.

Prototype method can be retrieved via accessor. In this case it should be preferably memoized or cached to a variable.

const cachedPrintName = makePrintName(foo, bar, baz);  class Car {     ...     get printName(): () => void {         return cachedPrintName;     } } 

And it can be lazily evaluated:

let cachedPrintName;  class Car {     ...     get printName(): () => void {         return cachedPrintName || cachedPrintName = makePrintName(foo, bar, baz);     } } 

Or it can be assigned to class prototype directly. In this case it should be additionally typed as class property because TypeScript ignores prototype assignments:

class Car {     ...     printName(): () => void; }  Car.prototype.printName = makePrintName(foo, bar, baz); 

Where () => void is the type of a function that makePrintName returns.

A way that is natural to TypeScript is to not modify class prototypes but extend prototype chain and introduce new or modified methods via mixin classes. This introduces unnecessary complexity in JavaScript yet keeps TypeScript happy about types:

function makePrintNameMixin(foo, bar, baz){   return function (Class) {     return class extends Class {       printName() {...}     }   } }  const Car = makePrintNameMixin(foo, bar, baz)(   class Car {     constructor() {...}   } ); 

TypeScript decorator cannot be seamlessly used at this point because class mutation is not supported at this moment. The class should be additionally supplemented with interface to suppress type errors:

interface Car {   printName: () => void; }  @makePrintNameMixin(foo, bar, baz) class Car {     constructor() {...} } 

Answers 2

Just replace : with =

printName = makePrintName() 

: goes for type notation.

Edit
As noted in comments the above will not change the prototype. Instead, you can do this outside the class definition, using ES5 syntax:

// workaround: extracting function return type const dummyPrintName = !true && makePrintName(); type PrintNameType = typeof dummyPrintName;  class Car {     // ...     printName: PrintNameType; } Car.prototype.printName = makePrintName(); 

Playground

Answers 3

Another idea I haven't seen mentioned yet is to use a method decorator. The following decorator takes a method implementation and puts it on the prototype, as desired:

function setMethod<T extends Function>(value: T) {     return function (target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<T>): void {       descriptor.value = value;       delete descriptor.get;       delete descriptor.set;     }; } 

Put it in a library somewhere. Here's how you'd use it:

class Car {     constructor(name) {         this.kind = 'Car';         this.name = name;     }      @setMethod(makePrintName(foo, bar, baz))     printName() {} // dummy implementation } 

The only downside is that you have to put a dummy implementation of the method with the right signature in the class, since the decorator needs something to decorate. But it behaves exactly as you want at runtime (it isn't an instance method which costs a new function definition for each instance, or an accessor which costs an extra function call at each use).

Does that help?

Answers 4

Why don't you try something like this

class Car {     constructor(name) {         this.kind = 'Car';         this.name = name;         this.printName = makePrintName(foo, bar, baz);      } } 

Answers 5

am I dont getting it or ..??

class keyword normally is just a syntax sugar of the delegate prototype in ES5. I just tried it in typescript

class Car { private kind: string; private name : string; printName :Function;     constructor(name) {                 this.kind = 'Car';                 this.name = name;             }     } var makePrintName = function (foo, bar, baz) {     return function () { console.log(foo, bar, baz); }; }; Car.prototype.printName = makePrintName('hello', 'world', 'did you get me'); var bmw = new Car('bmw'); bmw.printName(); console.log(bmw.hasOwnProperty('printName')); 
Read More

Tuesday, September 5, 2017

ERROR in bundle.js from UglifyJs Name expected

Leave a Comment

I am trying to use UglifyJS to minimize/compress my bundle.js file. When I run webpack -p, I am getting the following:

ERROR in bundle.js from UglifyJs Name expected [bundle.js:105519,6]

Line 105519 is as follows:

const {M, l, pattern} = __webpack_require__(862).

I am using React w/ ES6. Any thoughts as to what is wrong?

3 Answers

Answers 1

Every version of Webpack has a built-in version of UglifyJS (0.4.6) which doesn't support ES6. This version supports ES5 syntax only.

There are two possible solutions:

  • Make transpiler target es5
  • Don't use the built-in version of uglifyjs-webpack-plugin and install the latest version using npm install -D uglifyjs-webpack-plugin. Add it to your plugins property in your configuration:

    const UglifyJSPlugin = require('uglifyjs-webpack-plugin')  module.exports = {   plugins: [     new UglifyJSPlugin()   ] } 

Answers 2

This error comes when uglifyjs-webpack-plugin is not able to Uglify particular dependency

So, How to find library that creates such error ?

I was using react , so i deleted all forms in my app and kept just 1 form and imported all dependencies in it, and remove/add those dependencies one by one and run command

webpack -p 

SO In My case it was browser-history creating such error .Now you can report this issue to that library's author with some replicating example

Answers 3

Definitely an issue with the version of uglifyjs and the javascript target you are trying to compile to. It could be 2 things, your webpack setup and your babel setup causing this.

If you are using the latest version of webpack v3.5.5 it comes with uglifyjs-webpack-plugin ^0.4.6 which doesn't support a target of es6 or above.

Referring to the current Webpack docs about UglifyjsWebpackPlugin options it covers how to use the latest beta version of uglify-js-webpack-plugin v1.0.0-beta.2. But isnt that clear on how to install that version.

To use it with the Webpack do

yarn add uglifyjs-webpack-plugin@beta --dev

As you don't mention what your Babel setup is. You might be or want to use babel-preset-env as your preset. There is an option for uglifyjs.

Be great to see a repo or a Gist.

Read More

Friday, September 1, 2017

ECMA-262 7.0 GetValue(V)

Leave a Comment

Can anyone explain to me with examples how this algorithm works?

GetValue (V)#  1. ReturnIfAbrupt(V). 2. If Type(V) is not Reference, return V.  3. Let base be GetBase(V).  4. If IsUnresolvableReference(V) is true, throw a ReferenceError exception.  5. If IsPropertyReference(V) is true, then       a. If HasPrimitiveBase(V) is true, then           i. Assert: In this case, base will never be null or undefined.           ii. Let base be ToObject(base).       b. Return ? base.[[Get]](GetReferencedName(V), GetThisValue(V)).  6. Else base must be an Environment Record,       a. Return ? base.GetBindingValue(GetReferencedName(V), IsStrictReference(V)) (see 8.1.1). 

http://www.ecma-international.org/ecma-262/7.0/#sec-getvalue

It would be nice if someone with examples explained how it works. I tried, but I did not understand much.

Examples for explanation:

let a = 10, b = {name: "Unknown"}; (null, a); (null, a.name); (null, b); (null, b.name); (null, b.surname); (null, 10); /// etc... 

1 Answers

Answers 1

This segment gives more context:

...The Reference Specification Type#

NOTE The Reference type is used to explain the behaviour of such operators as delete, typeof, the assignment operators, the super keyword and other language features. For example, the left-hand operand of an assignment is expected to produce a reference.

A Reference is a resolved name or property binding. A Reference consists of three components, the base value, the referenced name and the Boolean valued strict reference flag. The base value is either undefined, an Object, a Boolean, a String, a Symbol, a Number, or an Environment Record. A base value of undefined indicates that the Reference could not be resolved to a binding. The referenced name is a String or Symbol value.

A Super Reference is a Reference that is used to represents a name binding that was expressed using the super keyword. A Super Reference has an additional thisValue component and its base value will never be an Environment Record.

The following abstract operations are used in this specification to access the components of references:

  • GetBase(V). Returns the base value component of the reference V.
  • GetReferencedName(V). Returns the referenced name component of the reference V.
  • IsStrictReference(V). Returns the strict reference flag component of the reference V.
  • HasPrimitiveBase(V). Returns true if Type(base) is Boolean, String, Symbol, or Number.
  • IsPropertyReference(V). Returns true if either the base value is an object or HasPrimitiveBase(V) is true; otherwise returns false.
  • IsUnresolvableReference(V). Returns true if the base value is undefined and false otherwise.
  • IsSuperReference(V). Returns true if this reference has a thisValue component. The following abstract operations are used in this specification to operate on references...

This is language internals. From a quick glance it looks like it is related to type inference before additional actions are performed on the value. This kind of operations are performed on a lower level when you call things like

delete someObject.prop 

or

typeof someVarIdentifier 

Example:

("" + a); 

Parse expression -> getValue("") + getValue(a) -> string{""} + (number{10} -> cast to string) -> concat("","10") -> "10"

Read More

Wednesday, August 23, 2017

How to disable babel transform-regenerator completely

Leave a Comment

I'm looking for a way to completely disable generator functions transform with babel. With babel 5 there was a blacklist option, but it seems that with babel 6 there is no way to do that (at least I did not find any documentation on the official website).

My current configuration

{   "presets": [     "react",   ],   "plugins": [     "transform-object-rest-spread",      ] } 

Disabling it like described here https://babeljs.io/docs/plugins/transform-regenerator/ did not help.

Any ideas?

1 Answers

Answers 1

Have you tried "exclude"? Like:

{    "presets": [       ["env", {          "exclude": ["transform-regenerator"]       }]    ] } 

Please see https://babeljs.io/docs/plugins/preset-env/#optionsexclude for details.

Read More

Tuesday, August 22, 2017

istanbul-instrumenter-loader: coverage issues don't match source

Leave a Comment

I'm using istanbul-instrumenter-loader to try to generate code coverage reports for my untranspiled es6 code, and while everything runs fine, the issues reported in the generated HTML output doesn't seem to line up with the actual source.

For example:

Incorrect coverage output

(in case the image is removed) A const declaration has 3 "if statement not covered" after it, even though there is no such statement or any code at all after that line. Sometimes "statement not covered" is marked in the middle of a string, or in an object declaration, or across multiple statements, etc etc.

Here's my Karma config file:

module.exports = function(config) {     config.set({         basePath: '../../',         frameworks: [ 'qunit' ],          files: [             'test/index.js',              // Session tickets             { pattern: 'test/tickets/*.json', watched: true, included: false, served: true }          ],          preprocessors: {             'test/index.js': 'webpack'         },         webpack: {             module: {                 rules: [{                     test: /\.js$/,                     exclude: /node_modules/,                     loaders: ['istanbul-instrumenter-loader', 'babel-loader']                 },                 {                     test: /\.vue$/,                     loaders: ['vue-loader']                 },                 {                     test: /\.png$/,                     loaders: ['url-loader']                 }]             }         },         reporters: [ 'coverage-istanbul', 'progress' ],         coverageIstanbulReporter: {             type: 'html',             dir: './coverage'             fixWebpackSourcePaths: true         },         port: 9876,         colors: true,         logLevel: config.LOG_INFO,         autoWatch: true,         browsers: [ 'Chrome' ],         browserNoActivityTimeout: 30000,         singleRun: true,         concurrency: Infinity,         client: {             captureConsole: true         },         browserConsoleLogOptions: {             terminal: true,             level: ''         }     }) }; 

1 Answers

Answers 1

karma-coverage and karma-webpack seem to be working together

"karma": "^0.12.28", "karma-coverage": "^0.2.7", "karma-sourcemap-loader": "^0.3.2", "karma-webpack": "^1.3.1", "webpack": "^1.4.14" 

Have you configured correctly , you can get more here https://github.com/webpack-contrib/istanbul-instrumenter-loader

and can u provide a a sample for your js file/spec

Read More

Wednesday, July 5, 2017

.js file works in chrome and firefox but not IE

Leave a Comment

When testing my website out in IE11 certain parts of it don't work and I believe the issue lies with my 'custom.js' file as all the problems link to that js. However, the page works perfectly in Chrome and Firefox.

I load the .js file called 'custom.js' in the footer of my page along with other page specfic plugins (jquery and bootstrap are loaded in the head) like so:

<!-- JS Implementing Plugins --> <script type="text/javascript" src="/js/back-to-top.js"></script> <script type="text/javascript" src="/js/smoothScroll.js"></script> <script type="text/javascript" src="/js/jquery.parallax.js"></script> <script type="text/javascript" src="/js/masterslider.min.js"></script> <script type="text/javascript" src="/js/jquery.easing.min.js"></script> <script type="text/javascript" src="/js/owl.carousel.min.js"></script> <script type="text/javascript" src="/js/jquery.cubeportfolio.min.js"></script>  <!-- JS Customization --> <script type="text/javascript" src="/js/custom.js"></script>  <!-- JS Page Level --> <script type="text/javascript" src="/js/app.js"></script> <script type="text/javascript" src="/js/owl-carousel.js"></script> <script type="text/javascript" src="/js/master-slider-fw.js"></script> <script type="text/javascript" src="/js/jquery.owl-filter.js"></script> <script type="text/javascript" src="/js/material.min.js"></script>  <script type="text/javascript">     jQuery(document).ready(function() {         App.init();         App.initCounter();         App.initParallaxBg();         FancyBox.initFancybox();         MSfullWidth.initMSfullWidth();         OwlCarousel.initOwlEvent();         OwlCarousel.initOwlSingle();         OwlCarousel.initOwlTwo();         OwlCarousel.initOwlAbout();      });     $(document).ready(function(){         $('.owl-carousel').owlCarousel({             nav:true,             loop:true         });     });  </script>  <!--[if lt IE 9]> <script src="/plugins/respond.js"></script> <script src="/plugins/html5shiv.js"></script> <script src="/plugins/placeholder-IE-fixes.js"></script> 

The contents of the custom.js file is:

$(".helpform-container:not(.displayblock)").hide();     $(".helpform")         .on('mouseover focus', function(e) {             $(this).addClass("link-div-hover")         })         .on('mouseout blur', function(e) {             $(this).removeClass("link-div-hover")         })         .on('touchstart', function(e) {             $(this).addClass("link-div-hover")         })         .on('touchend', function(e) {             $(this).removeClass("link-div-hover")         })         .on('click', function(e) {             $(this).toggleClass("active");             e.preventDefault();              if ($(".helpform-container").is(":hidden")) {                 $(".helpform-container").slideDown(400).addClass("displayed");                 analyticsevent('How can we help form', 'open');             } else {                 $(".helpform-container").slideUp(400).removeClass("displayed");                 $("#sticky-wrapper").css("height","auto");                 analyticsevent('How can we help form', 'closed');             }              if (sitewidth < 1024) {                 $('html,body').animate({ scrollTop: $("#howcanwehelp").offset().top - 60 }, 250);             } else {                 $('html,body').delay(500).animate({                      scrollTop: $("#howcanwehelp").offset().top                  }, 400);             }         })      //FORM METRICS     if ($('.formsent').length){          analyticsevent('Contact form completed', 'consultation/quote/info/media');     }  //Homepage news articles  var divs = $(".owl-news > .news-v2"); let array = [   { length: 1, num: 4 },   { length: 2, num: 3 },   { length: 2, num: 3 },   { length: 3, num: 2 }   ];  let i = 0;   for (let item of array) {   divs.slice(i, i+item.length).wrapAll(`<div id='news-${item.num}' class='col-md-${item.num}'></div>`);   i += item.length; }  $("#news-4").before("<div class='col-md-4'><h3 id='title_featured'>Featured News</h3></div><div class='col-md-8'><h3 id='title_latest'>Latest News</h3></div>"); 

2 Answers

Answers 1

Problem: Internet Explorer 11, released in 2013, does not run ECMAScript 2015 (for obvious reason).

Dirty Way: Babel (Standalone)

The quickest but also the least efficient way. Don't use in production.

<!-- Load the in-browser babel compiler.  Make sure page encoding is UTF-8. --> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <!-- Set script type to text/babel for on-the-fly conversion and execution --> <script type="text/babel" src="custom.js"></script> <!-- Babel need to read the script through ajax, same origin policy applies. --> 

Painful Way: Rewrite in ES5

Simply rewrite the last few lines of custom.js in ES5, and be extra care not to use any ES6/7/8+ features in the future:

var divs = $(".owl-news > .news-v2"),    array = [       { length: 1, num: 4 },       { length: 2, num: 3 },       { length: 2, num: 3 },       { length: 3, num: 2 }      ],    i = 0;  array.forEach( function( item ) {   divs.slice(i, i+item.length).wrapAll( "<div id='news-"+item.num+"' class='col-md-"+item.num+"'></div>" );   i += item.length; } ); 

Systematic Way: Build Script

A proper build system can help you manage the project, such as automatic testing and deployment to test and production system. One of the things they can do is to convert your ES6 code to ES5 on deployment and maybe minify / obfuscate them, for example with Babel, Traceur, or Closure.

The "build system" can be as simple as a batch file. If you tell your boss it'll protect valuable company intellectual properties (s)he may give you the time you need to properly learn one.


Save the Web: Don't support IE 11

I know, I know. You won't be asking if it's an option.

But your boss may not be aware that IE support costs more development time, which means higher cost, slower delivery, and less profit.

Few people (3.2%) use IE 11 in the real world - less than "UC Browser" (8%), "Firefox" (6%), "Samsung Internet" (3.6%), or "Opera" (3.4%). (Statcounter May 2017 global stat.) If a user or client ask why don't you support the Samsung browser, saying no one use it is not a good excuse, as IE 11 has even less users.

Most IE users have learned that if it doesn't work in IE, try Chrome. Encourage them to use Chrome first and IE last will be good. They are safer, the web is brighter, everyone is happy.

Answers 2

You're using the javascript let keyword, which is only available on IE11. More information here...

If the problem persists and you are sure the code is compiling, then you should activate the browser's debugger to figure out what's going on... Just place the keyword debugger; somewhere in your code, and the browser will suspend execution at that stop allowing you to inspect the variables...

Something like this:

debugger; $(".helpform-container:not(.displayblock)").hide(); ... $("#news-4").before("<div class='col-md-4'><h3 id='title_featured'>Featured News</h3></div><div class='col-md-8'><h3 id='title_latest'>Latest News</h3></div>"); 
Read More

Thursday, February 23, 2017

Using React Router and Webpack 2 how to require external libraries only on certain routes?

Leave a Comment

Currently working

Using Webpack 2 and React Router v4 I have been able to set up working code splitting. There is an intermediate <AsyncComponent> that resolves the promise and returns the component (a pattern found on github issues).

An example set of routes below:

<Switch>     <Route          path="me"          render={(props) =>              <AsyncComponent promise={ require.ensure([], (require) => require('./modules/Profile'), 'profile') } props={props} />         }      />     <Route          path="credit-card"          render={(props) =>              <AsyncComponent promise={ require.ensure([], (require) => require('./modules/CreditCard'), 'credit-card') } props={props} />         }      /> </Switch> 

Objective

I would like to extend that further, and for certain routes only, load in additional libraries. In the example above, I would like to fetch the StripeJS (https://js.stripe.com/v2/) library only when on the credit card route.

I want to emphasise that I can load Stripe directly into the footer and all works normally. There are multiple libraries, I'm using Stripe as an easy to digest example.

Attempted

The following has been attempted to little success:

  • Marking the lib external within the webpack config. This (correctly) flags the library as being external and won't attempt to bundle it during the resolve sequence of a require. However the expectation is that the library is manually brought in.
  • I have played with the idea of using a pseudo script loader (when hitting that route, manually create a <script> with a src attribute, wait for it to load, then let the component do its thing. This works ok, but is really horrible from a maintainability (if two or more libraries are needed, I then need to replicate the clumsy manual script load) point of view and seems to work against the webpack "way".

Relevant parts of the config

const core = [     'lodash',     'react',     'react-dom',     'axios',     'react-router-dom', ];  const config = {     context: path.resolve(__dirname, './ts_build'),     node: {         fs: "empty"     },     entry: {         app: './app.js',         core: core,     },     output: {         filename: '[name].js',         chunkFilename: '[name].[id].chunk.js',         path: path.resolve(__dirname, './../../public'),         publicPath: 'http://example.org/',     },     resolve: {         modules: [             path.resolve('./src'),         ],     },     plugins: [         new webpack.optimize.CommonsChunkPlugin({             names: ['core'],              minChunks: Infinity,         }),         new webpack.NamedModulesPlugin(),     ], }; 

2 Answers

Answers 1

If you are using Webpack 2 you use import() in your React Router config file

export default {  component: App,  childRoutes: [    {      path: '/',      getComponent(location, cb) {        import('external-library-here')        .then(function(){          return System.import('pages/Home');        })       .then(loadRoute(cb)).catch(errorLoading);      }    },    {      path: 'blog',      getComponent(location, cb) {        import('pages/Blog').then(loadRoute(cb)).catch(errorLoading);      }    },    {      path: 'about',      getComponent(location, cb) {        import('pages/About').then(loadRoute(cb)).catch(errorLoading);      }    },  ] }; 

You can also use the getComponent or getComponents props in the Router component to pass in modules you want specifically for that route.

Answers 2

There are some cases in this question that should be taken in detail.

Let's start.

Observations

  • You should switch the use of react-router from components to PlainRoute object, this will give you more flexibility when it comes to doing the code splitting, and also skips the creation of <AsyncComponent> component
  • I'm pretty sure you are going to have more nested components within your route, so what if a nested component within credit-card route needs a library?

Suggestions

  • Use your route component as an entry point, so it doesn't become a huge implementation in a single component
  • Given the above suggestion, you can add there an index with your library dependencies and use them within that route (in you nested components)
  • You should not import these libraries in any part of the code otherwise this functionality breaks
  • Once you have loaded these libraries inject them in the window object. and your nested components will able to access globally to your libraries

This is a suggestion that has not been implemented, but I'm trying to take you in the right direction regarding your question

In the end, this is the approach that I have suggested:

import App from 'components/App';  function errorLoading(err) {   console.error('Dynamic page loading failed', err); }  function loadRoute(cb) {   return (module) => cb(null, module.default); }  function injectLibraries(libraries) {   Object.keys(libraries).forEach(key => {     window[key] = libraries[key];   }); }  export default {   component: App,   childRoutes: [     {       path: '/(index.html)',       name: 'home',       getComponent(location, cb) {         const importModules = Promise.all([           import('components/HomePage/'),           import('components/HomePage/libraries'),         ]);          const renderRoute = loadRoute(cb);          importModules.then(([component, libraries]) => {           injectLibraries(libraries);           renderRoute(component);         });          importModules.catch(errorLoading);       },     },     {       path: '/credit-card',       name: 'credit-card',       getComponent(nextState, cb) {         const importModules = Promise.all([           import('components/CreditCardPage/'),           import('components/CreditCardPage/libraries'),         ]);          const renderRoute = loadRoute(cb);          importModules.then(([component, libraries]) => {           injectLibraries(libraries);           renderRoute(component);         });          importModules.catch(errorLoading);       },     },   ], }; 

Your libraries file should look like this:

import stripe from 'stripe';  export default {   stripe  }; 
Read More

Friday, June 24, 2016

wallaby.js got error >> SyntaxError: Unexpected token u

Leave a Comment

i tried to set up wallaby.js on visual studio code.

my project use language: node.js (es6)

  1. test: mocha
  2. ide: visual studio code
  3. node version: v5.9.0

i always got this error when i run wallaby

SyntaxError: Unexpected token u 

====== my wallaby config file (wallaby.js) =======

module.exports = function (wallaby) {   return {     files: [       'server/**/*.js',       '!node_modules/**/*.js'     ],     tests: [       'test/**/*.js'     ],     compilers: {       '**/*.js': wallaby.compilers.babel()     },     env: {       type: 'node',       params: {         runner: '--harmony --harmony_arrow_functions'       }     },     testFramework: 'mocha'   }; }; 

====== error =======

​SyntaxError: Unexpected token u /PATH/config/index.js:3:0 

====== config.index.js ======

'use strict'  module.exports  = {   // do something } 

it looks like there is an error on line module.exports = { because of the es6 syntax.

but i used node 5.9 which support es6

how should i solved this issue?

2 Answers

Answers 1

i have tried to create a small project with simple test cases and wallaby.js work fine.

I am not sure what the cause is but it should be my big code not wallaby.js.

Answers 2

Seems like you need to add missing semicolon at the end of first config line:

'use strict';  module.exports  = {   // do something } 
Read More

Saturday, April 30, 2016

Atom HTML syntax highlight in template literals (for angular2)

Leave a Comment

How can I get HTML syntax highlight in template literals?

Something like this which I've wrote for sublime before:
Here is sublime version https://github.com/Microsoft/TypeScript-Sublime-Plugin/pull/189/files
How can I write the same thing for Atom?

enter image description here

1 Answers

Answers 1

I was able to achieve this, here is the gist for ts.cson file.
form atom typescript plugin on my system:
/Users/amin/.atom/packages/atom-typescript/grammars/ts.cson

https://gist.github.com/aminroosta/509476f48f05f4b56db2c0748fedc8fd

This is very useful for angular2 development,
here is an screenshot for atom with html and css highlights:

enter image description here

I couldn't find a better regex to match against template: and styles:[, if anyone can come up with a better regex i will accept their answers.

the important changes in ts.cson file are:

"template-html":   name: "meta.template.html.ts"   begin: "`<!---->"   beginCaptures:     "0":       name: "string.quoted.template.ts"   end:"`"   endCaptures:     "0":       name: "string.quoted.template.ts"   patterns: [     {       include: "text.html.basic"     }   ] "template-css":   name: "meta.template.css.ts"   begin: "`/\\*\\*/"   beginCaptures:     "0":       name: "string.quoted.template.ts"   end:"`"   endCaptures:     "0":       name: "string.quoted.template.ts"   patterns: [     {       include: "source.css"     }   ] 

update:

Found a solution:

  "template-html":     name: "meta.template.html.ts"     begin: "(?<=template\\:)\\s*`"     beginCaptures:     "0":       name: "string.quoted.template.ts"   end:"`"   endCaptures:     "0":       name: "string.quoted.template.ts"   patterns: [     {       include: "text.html.basic"     }   ] "template-css":   name: "meta.template.css.ts"   begin: "(?<=styles\\:)\\s*(\\[)\\s*(`)"   beginCaptures:     "2":       name: "string.quoted.template.ts"   end:"`"   endCaptures:     "0":       name: "string.quoted.template.ts"   patterns: [     {       include: "source.css"     }   ] 

Here is the updated screenshot:

enter image description here

Read More

Monday, April 25, 2016

Karma/Jasmine unit test with JSPM 404 on my JSPM packages

Leave a Comment

I am trying to make JSPM / Karma / Babel / Jasmine all work together. But I am getting the error when running karma start

15 04 2016 17:34:02.428:INFO [karma]: Karma v0.13.22 server started at http://localhost:9876/ 15 04 2016 17:34:02.434:INFO [launcher]: Starting browser Chrome 15 04 2016 17:34:03.353:INFO [Chrome 49.0.2623 (Mac OS X 10.11.3)]: Connected on socket /#BSCbuviA4_LADHmaAAAA with id 80043999 15 04 2016 17:34:04.212:WARN [web-server]: 404: /base/aurelia-dependency-injection.js 15 04 2016 17:34:04.213:WARN [web-server]: 404: /base/aurelia-router.js Chrome 49.0.2623 (Mac OS X 10.11.3) ERROR   Error: Error: XHR error (404 Not Found) loading /Users/allen/dev/work/Web/aurelia-dependency-injection.js     Error loading /Users/allen/dev/work/Web/wwwroot/src/app.js 

My Folder Structure:

> Web   karma.conf.js   -> node_modules   -> test     --> unit   -> wwwroot     --> src (all my js)     --> jspm_packages     config.js 

My Karam.conf.js:

module.exports = function(config) {   config.set({      // base path that will be used to resolve all patterns (eg. files, exclude)     basePath: '',      // frameworks to use     // available frameworks: https://npmjs.org/browse/keyword/karma-adapter     frameworks: ['jspm', 'jasmine'],      jspm: {       // Edit this to your needs       loadFiles: ['test/unit/setup.js', 'test/unit/**/*.js'],       serveFiles: ['wwwroot/src/**/*.js'],       paths: {         '*': '*',         'github:*': 'jspm_packages/github/*',         'npm:*': 'jspm_packages/npm/*',       },     },      // list of files / patterns to load in the browser     files: [],     proxies: {       '/base/jspm_packages/': '/base/wwwroot/jspm_packages/',     },      // list of files to exclude     exclude: [],      // preprocess matching files before serving them to the browser     // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor     preprocessors: {       'test/**/*.js': ['babel'],       'src/**/*.js': ['babel'],     },      babelPreprocessor: {       options: {         sourceMap: 'inline',         presets: ['es2015-loose', 'stage-1'],         plugins: [           'syntax-flow',           'transform-decorators-legacy',           'transform-flow-strip-types',         ],       },     },      // test results reporter to use     // possible values: 'dots', 'progress'     // available reporters: https://npmjs.org/browse/keyword/karma-reporter     reporters: ['progress'],      // web server port     port: 9876,      // enable / disable colors in the output (reporters and logs)     colors: true,      // level of logging     // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG     logLevel: config.LOG_INFO,      // enable / disable watching file and executing tests whenever any file changes     autoWatch: true,      // start these browsers     // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher     browsers: ['Chrome'],      // Continuous Integration mode     // if true, Karma captures browsers, runs the tests and exits     singleRun: false,   }); }; 

My app.js has these imports:

import { inject } from 'aurelia-dependency-injection'; import { Router } from 'aurelia-router'; import { Navscroll } from '../src/modules/scroll-anim.js' 

I am not sure if my proxy is setup right or not or what the problem is?

1 Answers

Answers 1

Error: Error: XHR error (404 Not Found) loading /Users/allen/dev/work/Web/aurelia-dependency-injection.js Error loading /Users/allen/dev/work/Web/wwwroot/src/app.js 

This is your first problem. It's not XHRing to your proxy. Instead it's trying to use a path url. This will definitely fail as an XHR can only do HTTP as far as I have ever seen. You need the protocol://host:port/path format.

Try going to http://localhost:9876/src/app.js and see what shows up in your browser. (Might not need to include /src/ app.js might be served from root.)

You must be loading the app.js file incorrectly somewhere. Please include the places you load app.js.

Read More

Wednesday, April 20, 2016

Proxies on regexps and boxed primitives

Leave a Comment

Let's say I have a regexp which I want to handle via a proxy (in order to trap property accesses etc.):

proxy = new Proxy(/x/, {}); 

But when I try to use the proxy as a regexp:

proxy.test('x') 

I get

Uncaught TypeError: Method RegExp.prototype.test called on incompatible receiver [object Object]

A similar error occurs with 'x'.match(proxy).

Or consider proxying a boxed primitive:

proxy = new Proxy(Object(5), {}); 

But when I try to use the proxy as part of an expression, expecting a value of 6:

proxy + 1 

I get

Uncaught TypeError: Number.prototype.valueOf is not generic(…)

So my questions are:

  1. Can I proxy a regexp in such a way that the proxy functions as the regexp does in constructions such as regexp.test?

  2. Can I proxy a boxed primitive in such a way that the valueOf behavior continues to work?

1 Answers

Answers 1

Built-in types / objects can have so called "internal slots" which carry state that is not accessible from outside. Some methods depend on this state and therefore can't operate if it's missing.

These internal slots are not accessible through standard means when an object is proxied. Looking at the specification you will often encounter "if X does not have a [[y]] internal slot throw a TypeError exception". That's why proxying built-in types often does not work as expected. For the same reason you cannot do something like Number.prototype.valueOf.call({}).

A workaround is to bind the function directly to the target of the proxy:

var proxy = new Proxy(/x/, {   get: function(target, key) {     if (typeof target[key] === 'function') {       return target[key].bind(target);       }      return target[key];  } }); 

This example creates a new function on every call. A more sophisticated solution would cache the functions and and create a new function only for problematic methods.

Read More

Thursday, April 14, 2016

ng-forward bootstrap function and/or babel transpilation not working on stock android browser

Leave a Comment

When I view my app on my stock Android browser all I see is a white screen. I've seen a few issues about the "white screen of death" in Ionic apps, but none of that seems to apply here. It's difficult to debug, since I don't know of any way to see JS errors on a mobile browser (other than Chrome and its remote debugging feature). I guess my hope is that there's something obviously wrong with my bootstrap function, my main application class or my router. I'm using Angular 1.5.0-rc.2 and ng-forward. Here's the relevant part of my index.html:

<!-- no Angular components are loaded in here on stock Android browser --> <myapp>     loading . . . </myapp>  <script src="/path/to/angular.js"></script> <script src="/path/to/angular-ui-router.js"></script> 

bootstrap.js

import 'reflect-metadata'; import { bootstrap } from 'ng-forward'; import { Application } from '../components/app/Application'; import config from './config/app.config';  bootstrap(Application, [     'ui.router',     config.name ]); 

app.config.js

export default angular.module('app.config', []) .config(['$locationProvider', '$urlRouterProvider', '$httpProvider', Config]);  function Config($locationProvider, $urlRouterProvider, $animateProvider, $httpProvider) {     $locationProvider.html5Mode({ enabled: true, requireBase: false });     $urlRouterProvider.otherwise('/'); } 

Routes.js

import { Home } from '../../components/home/Home';  class Routes {     static Config()     {         return [             {                 url: '/',                 name: 'home',                 component: Home,                 template: '<home></home>'             }         ]     } } export default Routes.Config() 

Application.js

import { Component, StateConfig, Inject } from 'ng-forward'; import Routes from '../../app/config/Routes';  @Component({     selector: 'myapp',     template: `         <h1>My App</h1>         <ng-outlet></ng-outlet>     ` }) @StateConfig(Routes) export class Application {     constructor()     {         console.log('Application component instantiated');     } } 

This works on every desktop browser I've tried, and also on mobile using Chrome, Safari and Firefox. On my stock Android browser, the <myapp></myapp> and <home></home> components are never populated.

update

It occurs to me that this might instead/also be a Babel transpilation issue. I've got 4 Angular apps, 1 works on stock android browser, 3 don't. The only unique difference between the one that works and the three that don't is those three are es6. So I thought I'd include my Babel setup here, too, in case that helps with diagnosis:

package.json

"dependencies": {     "babel-core": "^6.4.0",     "babel-polyfill": "^6.3.14",     "babel-runtime": "^6.3.19" }, "devDependencies": {     "babel-plugin-syntax-async-functions": "^6.3.13",     "babel-plugin-transform-async-to-generator": "^6.4.0",     "babel-plugin-transform-decorators-legacy": "^1.3.4",     "babel-plugin-transform-regenerator": "^6.3.26",     "babel-plugin-transform-runtime": "^6.4.0",     "babel-preset-es2015": "^6.3.13",     "babel-preset-stage-0": "^6.3.13",     "babel-preset-stage-3": "^6.3.13",     "babelify": "^7.2.0" }, "babel": {     "presets": [         "es2015",         "stage-0",         "stage-3"     ],     "plugins": [         "transform-runtime",         "transform-regenerator",         "syntax-async-functions",         "transform-async-to-generator",         "transform-decorators-legacy"     ] } 

babel.js (grunt)

module.exports = function(grunt) {     grunt.config.set('babel', {         options: {             sourceMap: true,             presets: ['es2015', 'stage-0', 'stage-3'],             plugins: ['transform-decorators-legacy']         },         client: {             files: [{                 expand: true,                 cwd: '<%= grunt.path.client %>',                 src: ['{app,components,services}/**/*.js'],                 dest: '<%= grunt.path.tmp %>'             }]         }     }); }; 

Update

I found about about Android's about:debug setting for the stock browser. You type that into the address bar and hit enter, and then you suddenly have a Debug setting in the browser settings, among which is a checkbox for "Show JavaScript Console". However, toggling that produces no effect whatsoever (even when I know there are JS errors). HTC was no help there. Still flummoxed.

1 Answers

Answers 1

I wrapped the transpiled code in a try/catch and got the error, ReferenceError: Set is not defined, which led me to the reflect-metatdata function, which was trying to create a polyfill. The solution appears to be simply importing babel-polyfill in my bootstrap file:

import 'reflect-metadata';  // Missing this appears to be the cause of the problem import 'babel-polyfill';  import { bootstrap } from 'ng-forward'; import { Application } from '../components/app/Application'; import config from './config/app.config';  bootstrap(Application, [     'ui.router',     config.name ]); 
Read More