{"id":7565,"date":"2015-10-14T09:01:06","date_gmt":"2015-10-14T16:01:06","guid":{"rendered":"http:\/\/blog.mozilla.org\/addons\/?p=7565"},"modified":"2015-11-03T07:01:42","modified_gmt":"2015-11-03T15:01:42","slug":"breaking-changes-let-const-firefox-nightly-44","status":"publish","type":"post","link":"https:\/\/blog.mozilla.org\/addons\/2015\/10\/14\/breaking-changes-let-const-firefox-nightly-44\/","title":{"rendered":"Breaking changes in let and const in Firefox Nightly 44"},"content":{"rendered":"<h3>TL;DR<\/h3>\n<p>Many add-ons are currently broken on Nightly (Firefox 44) due to some changes that were done in the way <code>let<\/code> and <code>const<\/code> behave. These changes were introduced to make Firefox compliant with the final ES6 standard. These changes can lead to JS errors that break your code entirely, so we suggest you test your add-ons extensively to make sure they continue to work.<\/p>\n<p>All add-ons built with JPM (except the latest version) are currently affected by this. We plan to <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=1213102\">automatically repack all affected JPM add-ons on AMO<\/a>, but encourage you to repackage the add-on yourself and save some time. Pre-JPM versions of the SDK aren&#8217;t affected.<\/p>\n<p><strong>Update: <\/strong>additionally, with the change in <a href=\"https:\/\/bugzilla.mozilla.org\/show_bug.cgi?id=1167029\">bug 1167029<\/a>, let blocks (like <code>let (x = 42) { use(x); }<\/code> ) will also stop working.<\/p>\n<p>Please read on for the details of this change, written by <a href=\"https:\/\/twitter.com\/_shu\">Shu-yu Guo<\/a>. It&#8217;s an interesting read even if your add-on isn&#8217;t affected.<\/p>\n<hr \/>\n<p>SpiderMonkey has had non-standard <code>let<\/code> and <code>const<\/code> bindings for years. Recently we updated the semantics of <code>let<\/code> and <code>const<\/code> bindings for the global level to be compliant with ES6 semantics. ES6 semantics is <em>not<\/em> compatible with SpiderMonkey&#8217;s legacy semantics. (For an introduction to ES6 semantics, please refer to <a href=\"https:\/\/hacks.mozilla.org\/2015\/07\/es6-in-depth-let-and-const\/\">Jason Orendorff&#8217;s post<\/a>.)<\/p>\n<p>Did this update break your add-on? This post will help you diagnose and fix issues it caused.<\/p>\n<h3>Legacy Semantics<\/h3>\n<p>At the global level, legacy <code>let<\/code> was equivalent to <code>var<\/code>. Inside the parser, it was in fact parsed as if the token were <code>var<\/code>.<\/p>\n<p>Global-level legacy <code>const<\/code> was like <code>var<\/code>, except that the property it introduced was read-only.<\/p>\n<h3>ES6 global lexical bindings are not properties<\/h3>\n<p>The biggest incompatibility is that ES6 <code>let<\/code> and <code>const<\/code> bindings, unlike their legacy counterparts, are no longer properties on the global object. Instead, they are bindings in the global lexical scope directly below the global object.<\/p>\n<p>For example,<\/p>\n<pre lang=\"javascript\">const x = 42;\r\n\/\/ Prints false for ES6, true for legacy\r\ndump('x' in this);<\/pre>\n<p>Many add-ons have the expectation that global <code>let<\/code> and <code>const<\/code> introduce properties. For instance, a legacy JSM might define constants and globals:<\/p>\n<pre lang=\"javascript\">\/\/ Foo.jsm\r\nconst MY_CONSTANT = 42;\r\nlet gFoo = \"foo\";\r\n\r\n\/\/ addon.js\r\nvar FooModule = Cu.import(\"Foo.jsm\", {});\r\ndump(FooModule.MY_CONSTANT);\r\ndump(FooModule.gFoo);<\/pre>\n<p>With ES6 <code>const<\/code>, <code>FooModule.MY_CONSTANT<\/code> and <code>FooModule.gFoo<\/code> are both <code>undefined<\/code>, because their bindings are in a separate scope and not properties on the global object. This makes bugs caused by these errors particularly elusive.<\/p>\n<p>For uses of global legacy <code>let<\/code> bindings that need to be accessed as properties, I recommend declaring them with <code>var<\/code>.<\/p>\n<p>Unfortunately, there is no ES6 syntax with the same semantics as legacy <code>const<\/code>. If the read-only aspect of the property is necessary, I recommend manually defining a property on the global object:<\/p>\n<pre lang=\"javascript\">Object.defineProperty(globalObject, \"MY_CONSTANT\", {\r\n  value: 42,\r\n  enumerable: true,\r\n  writable: false\r\n});<\/pre>\n<p>If your add-on imports <code>XPCOMUtils<\/code>, <code>XPCOMUtils.defineConstant(obj, key, value)<\/code> does exactly that.<\/p>\n<h3>ES6 global lexical bindings may not be redeclared<\/h3>\n<p>In ES6, global lexical bindings may not be redeclared in any way: not by <code>let<\/code>, <code>const<\/code>, nor <code>var<\/code>. For example, if the global level has <code>let foo<\/code> or <code>const foo<\/code>, any subsequent occurrences of <code>let foo<\/code>, <code>const foo<\/code>, or <code>var foo<\/code> will throw.<\/p>\n<p>Redeclaration errors are easy to fix: rename the variable or remove the declarator and assign to the already-declared variable directly.<\/p>\n<h3>ES6 global lexical bindings have TDZ<\/h3>\n<p>In ES6, no lexical binding may be used before its declaration is reached. For example, the following throws:<\/p>\n<pre lang=\"javascript\">dump(x);\r\nlet x;<\/pre>\n<p>This has long been regarded as poor style in the community, and fortunately, such errors in existing code are rare. If such an error is encountered, it is very likely a bug in the code.<\/p>\n<h3>Global lexical scope and <code>JSSubScriptLoader<\/code><\/h3>\n<p>The subscript loader may load new scripts into the global scope. This interacts with the ES6 global lexical scope. The pitfall is that since lexical bindings may not be redeclared, loading multiple scripts that redeclare globals with <code>let<\/code> or <code>const<\/code> now result in error. For example,<\/p>\n<pre lang=\"javascript\">\/\/ foo.js\r\nlet gFoo;\r\n\r\n\/\/ bar.js\r\nlet gFoo;\r\n\r\n\/\/ addon.js\r\nloader.loadSubScript(\"foo.js\");\r\nloader.loadSubScript(\"bar.js\"); \/\/ throws due to redeclaration of gFoo<\/pre>\n<h3>Global lexical scope and the component loader<\/h3>\n<p>When loading components, such as via <code>Cu.import<\/code>, each component has its own global scope and global lexical scope, so cross-script redeclaration issues do not arise.<\/p>\n<p><code>Cu.import<\/code> returns the global object of the imported component, so the main pitfall is using <code>let<\/code> and <code>const<\/code>-declared bindings as properties on that scope.<\/p>\n<h3>Global lexical scope and custom scopes<\/h3>\n<p>Both the subscript and component loaders let users load scripts whose global variables and properties are stored in a user-provided scope object. For example, suppose we had foo.js:<\/p>\n<pre lang=\"javascript\">\/\/ foo.js\r\nvar gVar;\r\nlet gLet;\r\nconst gConst;<\/pre>\n<p>Calling <code>loader.loadSubScript(\"foo.js\", myScope)<\/code> would result in parsing foo.js with the following scope chain, from outermost to innermost:<\/p>\n<pre>     Global object\r\n           |\r\n  Global lexical scope\r\n           |\r\n        myScope\r\n           |\r\n          ...\r\n<\/pre>\n<p>Without user-passed scopes, <code>var<\/code> bindings go on the global object. Lexical <code>let<\/code> and <code>const<\/code> bindings go on the global lexical scope.<\/p>\n<p>From the point of view of <code>var<\/code> bindings, <code>myScope<\/code> behaves like the global object: they capture <code>var<\/code> bindings as properties. That is, <code>gVar<\/code> is a property on <code>myScope<\/code>, not the global object.<\/p>\n<p>Global lexical <code>let<\/code> and <code>const<\/code> bindings shadow global properties: <code>gLet<\/code> would hide a property reachable via <code>this.gLet<\/code>. Since <code>myScope<\/code> captures <code>var<\/code> bindings, consistency requires <code>myScope<\/code> to have its own lexical scope that captures <code>let<\/code> and <code>const<\/code> bindings:<\/p>\n<pre>     Global object\r\n           |\r\n  Global lexical scope\r\n           |\r\n        myScope\r\n           |\r\n  myScope's lexical scope<\/pre>\n<p>In the example, <code>gLet<\/code> and <code>gConst<\/code> are bindings in <code>myScope<\/code>&#8216;s lexical scope. Multiple scripts loaded into <code>myScope<\/code> would get the same lexical scope. Scripts loaded into <code>myOtherScope<\/code> would get <code>myOtherScope<\/code>&#8216;s lexical scope, an entirely different scope.<\/p>\n<p>Note that lexical bindings are still not properties on the non-syntactic scope. If your add-on uses custom scopes, you may run into the problems described in &#8220;ES6 global lexical bindings are not properties&#8221; above.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>TL;DR Many add-ons are currently broken on Nightly (Firefox 44) due to some changes that were done in the way let and const behave. These changes were introduced to make &hellip; <a class=\"go\" href=\"https:\/\/blog.mozilla.org\/addons\/2015\/10\/14\/breaking-changes-let-const-firefox-nightly-44\/\">Read more<\/a><\/p>\n","protected":false},"author":173,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[388,44,295],"tags":[278877,278873,4870,278883,128],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v22.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Breaking changes in let and const in Firefox Nightly 44 - Mozilla Add-ons Community Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blog.mozilla.org\/addons\/2015\/10\/14\/breaking-changes-let-const-firefox-nightly-44\/\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jorge Villalobos\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/blog.mozilla.org\/addons\/2015\/10\/14\/breaking-changes-let-const-firefox-nightly-44\/\",\"url\":\"https:\/\/blog.mozilla.org\/addons\/2015\/10\/14\/breaking-changes-let-const-firefox-nightly-44\/\",\"name\":\"Breaking changes in let and const in Firefox Nightly 44 - Mozilla Add-ons Community Blog\",\"isPartOf\":{\"@id\":\"https:\/\/blog.mozilla.org\/addons\/#website\"},\"datePublished\":\"2015-10-14T16:01:06+00:00\",\"dateModified\":\"2015-11-03T15:01:42+00:00\",\"author\":{\"@id\":\"https:\/\/blog.mozilla.org\/addons\/#\/schema\/person\/a098261b4b5510d408ff31f492606925\"},\"breadcrumb\":{\"@id\":\"https:\/\/blog.mozilla.org\/addons\/2015\/10\/14\/breaking-changes-let-const-firefox-nightly-44\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/blog.mozilla.org\/addons\/2015\/10\/14\/breaking-changes-let-const-firefox-nightly-44\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/blog.mozilla.org\/addons\/2015\/10\/14\/breaking-changes-let-const-firefox-nightly-44\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/blog.mozilla.org\/addons\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Breaking changes in let and const in Firefox Nightly 44\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/blog.mozilla.org\/addons\/#website\",\"url\":\"https:\/\/blog.mozilla.org\/addons\/\",\"name\":\"Mozilla Add-ons Community Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/blog.mozilla.org\/addons\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/blog.mozilla.org\/addons\/#\/schema\/person\/a098261b4b5510d408ff31f492606925\",\"name\":\"Jorge Villalobos\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/blog.mozilla.org\/addons\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/6d1966118f16e4b99a6e3ad07883be33?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/6d1966118f16e4b99a6e3ad07883be33?s=96&d=mm&r=g\",\"caption\":\"Jorge Villalobos\"},\"description\":\"Jorge is the Product Manager for addons.mozilla.org\",\"url\":\"https:\/\/blog.mozilla.org\/addons\/author\/jvillalobosmozilla-com\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Breaking changes in let and const in Firefox Nightly 44 - Mozilla Add-ons Community Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blog.mozilla.org\/addons\/2015\/10\/14\/breaking-changes-let-const-firefox-nightly-44\/","twitter_misc":{"Written by":"Jorge Villalobos","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/blog.mozilla.org\/addons\/2015\/10\/14\/breaking-changes-let-const-firefox-nightly-44\/","url":"https:\/\/blog.mozilla.org\/addons\/2015\/10\/14\/breaking-changes-let-const-firefox-nightly-44\/","name":"Breaking changes in let and const in Firefox Nightly 44 - Mozilla Add-ons Community Blog","isPartOf":{"@id":"https:\/\/blog.mozilla.org\/addons\/#website"},"datePublished":"2015-10-14T16:01:06+00:00","dateModified":"2015-11-03T15:01:42+00:00","author":{"@id":"https:\/\/blog.mozilla.org\/addons\/#\/schema\/person\/a098261b4b5510d408ff31f492606925"},"breadcrumb":{"@id":"https:\/\/blog.mozilla.org\/addons\/2015\/10\/14\/breaking-changes-let-const-firefox-nightly-44\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blog.mozilla.org\/addons\/2015\/10\/14\/breaking-changes-let-const-firefox-nightly-44\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/blog.mozilla.org\/addons\/2015\/10\/14\/breaking-changes-let-const-firefox-nightly-44\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/blog.mozilla.org\/addons\/"},{"@type":"ListItem","position":2,"name":"Breaking changes in let and const in Firefox Nightly 44"}]},{"@type":"WebSite","@id":"https:\/\/blog.mozilla.org\/addons\/#website","url":"https:\/\/blog.mozilla.org\/addons\/","name":"Mozilla Add-ons Community Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blog.mozilla.org\/addons\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/blog.mozilla.org\/addons\/#\/schema\/person\/a098261b4b5510d408ff31f492606925","name":"Jorge Villalobos","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/blog.mozilla.org\/addons\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/6d1966118f16e4b99a6e3ad07883be33?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/6d1966118f16e4b99a6e3ad07883be33?s=96&d=mm&r=g","caption":"Jorge Villalobos"},"description":"Jorge is the Product Manager for addons.mozilla.org","url":"https:\/\/blog.mozilla.org\/addons\/author\/jvillalobosmozilla-com\/"}]}},"_links":{"self":[{"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/posts\/7565"}],"collection":[{"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/users\/173"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/comments?post=7565"}],"version-history":[{"count":0,"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/posts\/7565\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/media?parent=7565"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/categories?post=7565"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.mozilla.org\/addons\/wp-json\/wp\/v2\/tags?post=7565"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}