Unexpected token => in Javascript for chrome v41 and ie11 - javascript

What is the quick way to fix the error
Unexpected token => .
I wrote below code and it only runs in higher version of chrome but not on lower version and ie11.
var result = aIndice.filter(obj => {
return obj.Type === "E"
})

You are using an arrow function obj => { } which will not work in Internet Explorer 11. You need to either use tools like Babel to compile your ES6 code to ES5, or simply avoid using any modern features.
You can also write your function like this:
var result = aIndice.filter(function(obj) {
return obj.Type === "E"
})

Arrow functions are an es2015 feature, therefore they will not run on older browsers.
Some features can be implemented by using different polyfills like modernizr, but arrow functions are a language expression and thus can't be polyfilled.
You can tell what features are available in what browsers by using caniuse.
The solution to this problem is transpiling the code with a tool like babel.
To transpile your script with babel, you will need to install npm and node.js, and then initiate an npm project:
$ npm init
And install the dependencies we need, the babel-cli and a preset for it to use babel-preset-env.
$ npm install --save-dev babel-cli babel-preset-env
Now you need a settings file for babel, you can define your target browsers there using browserlist, so create a file named ".babelrc" and in it write:
{
"presets": [
["env", {
"targets": {
"ie": "11",
"chrome": 41
}
}]
]
}
Add a new npm script to package.json (created by calling npm init)
"script.js" is the source script, and "script-transpiled.js" is the output script.
"scripts": {
"transpile": "babel script.js --o script-transpiled.js"
}
And call
npm run transpile
Now your script will be transpiled into a new file script-transpiled.js and you can run it the targeted browsers.
To work with a large scale project it is recommended to use babel-loader with webpack.

Related

I want Babel to transpile JSX but not async/await

I am following the instructions in this React Doc.
https://reactjs.org/docs/add-react-to-a-website.html#run-jsx-preprocessor
I have installed the dependencies as instructed:
npm install babel-cli#6 babel-preset-react-app#3
And to watch / transpile my source I use:
npx babel --watch src --out-dir dist --presets react-app/prod
This works great BUT, it not only transpiles JSX but also aysnc/await. Which all browsers I support (December 2020) already support async/await and therefore I would like to not transpile it. Is there another preset I should be using that would transpile JSX but not Async/Await?
What's causing async/await to be transformed is plugin-transform-regenerator.
You can enable/disable it in this REPL to demonstrate its effects. On the sidebar, scroll all the way down to plugins and click the x next to plugin-transform-regenerator.
You'd have to remove that preset and manually add all of the plugins and presets inherited from that preset to a babel config. I'm afraid it isn't possible to disable a specific plugin from a preset at the moment, as far as I know.
You can find all of the plugins and presets that preset is using here, under dependencies:
https://github.com/facebook/create-react-app/blob/master/packages/babel-preset-react-app/package.json
Here's documentation on putting together a babel config: https://babeljs.io/docs/en/configuration
I think you're able to achieve your role by using 2 common babel presets: #babel/preset-env & #babel/preset-react with latest version.
The key thing you might need to change to keep async/await (a2) is the target option of preset-env. As long as you set a browser to support (a2) such as chrome: 80, babel would keep them for you. Of course #babel/preset-react is all about for transform jsx.
Here's a step you need to do:
Install deps:
npm i -D #babel/core #babel/cli #babel/preset-env #babel/preset-react
Create a babel.config.js:
const presets = [
[
"#babel/preset-env",
{
"targets": {
"chrome": 80, // this version to support `async/await`
},
// "modules": false, // you might want it to native support esm in browser
}
],
"#babel/preset-react"
];
module.exports = { presets };
Finally, run your test code:
npx babel --watch src --out-dir dist
NOTE: No need to specify presets here since it's configured via the file

Typescript transpile es6 .js dependency to es5

I have a hypothetical Typescript file in my project (simplified example).
Utils.ts:
import * as HelperFromNodeModules from 'helper-from-node-modules';
class Utils {
static foo() {
return HelperFromNodeModules.parse(...);
}
}
Importing helper-from-node-modules consists of a Javascript file.
helper-from-node-modules.js:
const dep = require('foo');
function parse(...) {
return bar.map((e) => {...});
}
And from #types/helper-from-node-modules index.d.ts:
export function parse(...);
The tsconfig.json among other things contains the following:
{
...
"target": "es5",
"lib": ["es2015.collection","es6", "dom"],
"sourceMap": true,
"allowJs": true,
...
}
So my problem is the Typescript compiler's output file is a giant concatenation of my compiled source code plus all of the decencies. Since helper-from-node-modules was always a .js file, the compiler seems to just append its contents to the output file. So, despite "target": "es5" the output file still contains es6 artifacts like const and (e) => {...}, resulting in errors with things later that expect strictly es5 javascript.
Is there is a way to tell the Typescript compiler/transpiler to output es5 on the javascript dependencies as well?
Context if you care:
I made the horrible mistake of using react-create-app-typescript and react-scripts-ts as the boilerplate for my React app. The webpack stack built in is very opinionated on where source code should come from and that the compiled source must be es5. The minifier/uglifier packaged will crash if attempting to minify any es6 artifacts. I know I can run npm run-script eject and modify the various config scripts but I am trying to avoid that mess. I would love to just get the source to compile to es6 and not mess with their webpack stack.
Unfortunately, there isn't a way to do convert dependencies from ES6 to ES5. That option in tsconfig.json only affects how TypeScript code is transpiled. What you should do is use an ES5 version of your helper-from-node-modules. For example, Angular is distributed with several packages, for ES5 (umd), ES5, ES6 ... Then, in the package.json of the library there are options to tell the packager (usually webpack) what version to use, depending on the target use for TypeScript.
If the library you're using does not support that, the only option you have is to transpile it to ES5 yourself, maybe using babel, or use an alternative.
Is is strange, however, for a library to be only distributed as ES6.
The only thing that comes to my mind is hooking into the compilation process and transforming your dependencies before they get processed by TypeScript. This requires TypeScript transformers.
A transformer is a function to which the AST of your program is exposed. A basic example:
import * as ts from 'typescript';
export default (program: ts.Program) => {
return (ctx: ts.TransformationContext) => {
return (sourceFile: ts.SourceFile) => {
function visitor(node: ts.Node): ts.Node {
/**
* If that's the kind of node you were looking for,
* do something with it and return it. Otherwise:
*/
return ts.visitEachChild(node, visitor, ctx);
}
return ts.visitEachChild(sourceFile, visitor, ctx);
};
};
}
If you are using Webpack, you could plug it into your build pipeline in your Webpack configuration file.
webpack.config.js
const transformer = require('./your-custom-transformer');
module.exports = {
/* ... */
module: {
rules: [
{
test: /\.ts$/,
loader: 'ts-loader', // (or 'awesome-typescript-loader')
options: {
getCustomTransformers: program => ({
before: [
transformer(program)
]
})
}
}
]
}
};
Came across this question because I needed to import some files into both Next.js and my CLI. (A common source file in two different builds.) Next.js has certain automated configuration, so I was trying to support all the things it supports so I didn't have many situations where Next.js worked and my CLI failed.
So the below solution is the Babel part. (I combined with https://github.com/vercel/next.js/tree/canary/examples/custom-server-typescript for the tsconfig part.)
Solution to transpile ES6 imports to ES5: (outside of nextjs)
from https://www.dotnetcurry.com/javascript/1293/transpile-es6-modules-es5-using-babel
npm install --save-dev #babel/cli #babel/preset-env
Create .babelrc:
{
presets: ["#babel/preset-env"]
}
add to your build script (i.e. you probably already have package.json script for npm run build to work)
for JSX to work (if you have any .tsx files or JSX syntax in .js files)
npm install --save-dev #babel/preset-react
and in .babelrc
{
"presets": [
"#babel/preset-env",
[
"#babel/preset-react",
{
"runtime": "automatic"
}
]
]
}
for Next.js _app had to add https://github.com/uiwjs/babel-plugin-transform-remove-imports to remove CSS imports

How to stop babel from transpiling 'this' to 'undefined' (and inserting "use strict")

EDIT: This is not about fat arrows. It's also not about passing this to an IIFE. It's a transpiler-related question.
So I've created a simple pub-sub for a little app I'm working on. I wrote it in ES6 to use spread/rest and save some headaches. I set it up with npm and gulp to transpile it but it's driving me crazy.
I made it a browser library but realized it could be used anywhere so I decided to make it Commonjs and AMD compatible.
Here's a trimmed down version of my code:
(function(root, factory) {
if(typeof define === 'function' && define.amd) {
define([], function() {
return (root.simplePubSub = factory())
});
} else if(typeof module === 'object' && module.exports) {
module.exports = (root.simplePubSub = factory())
} else {
root.simplePubSub = root.SPS = factory()
}
}(this, function() {
// return SimplePubSub
});
But no matter what I try (such as making this a variable and passing it) it sets it to undefined.
}(undefined, function() {
It probably has something to do with Babel not knowing what this will be and transpiling it away but is there any other approach I can take?
UPDATE: Passing }((window || module || {}), function() { instead of this seems to work. I'm not sure this is the best approach though.
For Babel >= 7.x
ES6 code has two processing modes:
"script" - When you load a file via a <script>, or any other standard ES5 way of loading a file
"module" - When a file is processed as an ES6 module
In Babel 7.x, files are parsed as "module" by default. The thing that is causing you trouble is that in an ES6 module, this is undefined, whereas in the "script" case, this varies depending on the environment, like window in a browser script or exports in CommonJS code. Similarly, "module" files are automatically strict, so Babel will insert "use strict";.
In Babel 7, you'll need to tell Babel what type your file is if you want to avoid this behavior. The simplest option would be to use the "sourceType" option to set sourceType: "unambiguous" in your Babel options, which essentially tells Babel to guess the type (scripts vs module), based on the presence of import and export statements. The primary downside there being that it's technically fine to have an ES6 module that doesn't use import or export, and those would be incorrectly treated as scripts. On the other hand, that's really not that common.
Alternatively, you can use Babel 7's "overrides" option to set specific files as scripts, e.g.
overrides: [{
test: "./vendor/something.umd.js",
sourceType: "script",
}],
Either approach allows Babel to know that some files are script types, and thus shouldn't have this converted to undefined.
For Babel < 7.x
ES6 code has two processing modes:
"script" - When you load a file via a <script>, or any other standard ES5 way of loading a file
"module" - When a file is processed as an ES6 module
When using Babel 6 and babel-preset-es2015 (or Babel 5), Babel by default assumes that files it processes are ES6 modules. The thing that is causing you trouble is that in an ES6 module, this is undefined and files are all strict, whereas in the "script" case, this varies depending on the environment, like window in a browser script or exports in CommonJS code.
If you are using Babel, the easiest option is to write your code without the UMD wrapper, and then bundle your file using something like Browserify to automatically add the UMD wrapper for you. Babel also provides a babel-plugin-transform-es2015-modules-umd. Both are geared toward simplicity, so if you want a customized UMD approach, they may not be for you.
Alternatively, you would need to explicitly list all of the Babel plugins in babel-preset-es2015, making sure to exclude the module-processing babel-plugin-transform-es2015-modules-commonjs plugin. Note, this will also stop the automatic addition of use strict since that is part of the ES6 spec too, you may want to add back babel-plugin-transform-strict-mode to keep your code strict automatically.
As of babel-core#6.13 presets are able to take options, so you can also do
{
"presets": [
[ "es2015", { "modules": false } ]
]
}
in your Babel config (.babelrc) to use babel-preset-es2015 with module processing disabled.
The "es2015" preset wraps the Babel output in a commonJs wrapper by default. Use the "babel-preset-es2015-script" (you must npm install --save babel-preset-es2015-script first) to output for "script" (no modules). This was wreaking havoc on other libraries I was wrapping up using Babel.
The preset: https://www.npmjs.com/package/babel-preset-es2015-script

How do I install the babel-polyfill library?

I just started to use Babel to compile my ES6 javascript code into ES5. When I start to use Promises it looks like it's not working. The Babel website states support for promises via polyfills.
Without any luck, I tried to add:
require("babel/polyfill");
or
import * as p from "babel/polyfill";
With that I'll get the following error on my app bootstrapping:
Cannot find module 'babel/polyfill'
I searched for the module but it seems I'm missing some fundamental thing here. I also tried to add the old and good bluebird NPM but it looks like it's not working.
How to use the polyfills from Babel?
This changed a bit in babel v6.
From the docs:
The polyfill will emulate a full ES6 environment. This polyfill is automatically loaded when using babel-node.
Installation:
$ npm install babel-polyfill
Usage in Node / Browserify / Webpack:
To include the polyfill you need to require it at the top of the entry point to your application.
require("babel-polyfill");
Usage in Browser:
Available from the dist/polyfill.js file within a babel-polyfill npm release. This needs to be included before all your compiled Babel code. You can either prepend it to your compiled code or include it in a <script> before it.
NOTE: Do not require this via browserify etc, use babel-polyfill.
The Babel docs describe this pretty concisely:
Babel includes a polyfill that includes a custom regenerator runtime
and core.js.
This will emulate a full ES6 environment. This polyfill is
automatically loaded when using babel-node and babel/register.
Make sure you require it at the entry-point to your application, before anything else is called. If you're using a tool like webpack, that becomes pretty simple (you can tell webpack to include it in the bundle).
If you're using a tool like gulp-babel or babel-loader, you need to also install the babel package itself to use the polyfill.
Also note that for modules that affect the global scope (polyfills and the like), you can use a terse import to avoid having unused variables in your module:
import 'babel/polyfill';
For Babel version 7, if your are using #babel/preset-env, to include polyfill all you have to do is add a flag 'useBuiltIns' with the value of 'usage' in your babel configuration. There is no need to require or import polyfill at the entry point of your App.
With this flag specified, babel#7 will optimize and only include the polyfills you needs.
To use this flag, after installation:
npm install --save-dev #babel/core #babel/cli #babel/preset-env
npm install --save #babel/polyfill
Simply add the flag:
useBuiltIns: "usage"
to your babel configuration file called "babel.config.js" (also new to Babel#7), under the "#babel/env" section:
// file: babel.config.js
module.exports = () => {
const presets = [
[
"#babel/env",
{
targets: { /* your targeted browser */ },
useBuiltIns: "usage" // <-----------------*** add this
}
]
];
return { presets };
};
Reference:
usage#polyfill
babel-polyfill#usage-in-node-browserify-webpack
babel-preset-env#usebuiltins
Update Aug 2019:
With the release of Babel 7.4.0 (March 19, 2019) #babel/polyfill is deprecated. Instead of installing #babe/polyfill, you will install core-js:
npm install --save core-js#3
A new entry corejs is added to your babel.config.js
// file: babel.config.js
module.exports = () => {
const presets = [
[
"#babel/env",
{
targets: { /* your targeted browser */ },
useBuiltIns: "usage",
corejs: 3 // <----- specify version of corejs used
}
]
];
return { presets };
};
see example: https://github.com/ApolloTang/stackoverflow-eg--babel-v7.4.0-polyfill-w-core-v3
Reference:
7.4.0 Released: core-js 3, static private methods and partial
application
core-js#3, babel and a look into the future
If your package.json looks something like the following:
...
"devDependencies": {
"babel": "^6.5.2",
"babel-eslint": "^6.0.4",
"babel-polyfill": "^6.8.0",
"babel-preset-es2015": "^6.6.0",
"babelify": "^7.3.0",
...
And you get the Cannot find module 'babel/polyfill' error message, then you probably just need to change your import statement FROM:
import "babel/polyfill";
TO:
import "babel-polyfill";
And make sure it comes before any other import statement (not necessarily at the entry point of your application).
Reference: https://babeljs.io/docs/usage/polyfill/
First off, the obvious answer that no one has provided, you need to install Babel into your application:
npm install babel --save
(or babel-core if you instead want to require('babel-core/polyfill')).
Aside from that, I have a grunt task to transpile my es6 and jsx as a build step (i.e. I don't want to use babel/register, which is why I am trying to use babel/polyfill directly in the first place), so I'd like to put more emphasis on this part of #ssube's answer:
Make sure you require it at the entry-point to your application,
before anything else is called
I ran into some weird issue where I was trying to require babel/polyfill from some shared environment startup file and I got the error the user referenced - I think it might have had something to do with how babel orders imports versus requires but I'm unable to reproduce now. Anyway, moving import 'babel/polyfill' as the first line in both my client and server startup scripts fixed the problem.
Note that if you instead want to use require('babel/polyfill') I would make sure all your other module loader statements are also requires and not use imports - avoid mixing the two. In other words, if you have any import statements in your startup script, make import babel/polyfill the first line in your script rather than require('babel/polyfill').
babel-polyfill allows you to use the full set of ES6 features beyond
syntax changes. This includes features such as new built-in objects
like Promises and WeakMap, as well as new static methods like
Array.from or Object.assign.
Without babel-polyfill, babel only allows you to use features like
arrow functions, destructuring, default arguments, and other
syntax-specific features introduced in ES6.
https://www.quora.com/What-does-babel-polyfill-do
https://hackernoon.com/polyfills-everything-you-ever-wanted-to-know-or-maybe-a-bit-less-7c8de164e423
Like Babel says in the docs, for Babel > 7.4.0 the module #babel/polyfill is deprecated, so it's recommended to use directly core-js and regenerator-runtime libraries that before were included in #babel/polyfill.
So this worked for me:
npm install --save core-js#3.6.5
npm install regenerator-runtime
then add to the very top of your initial js file:
import 'core-js/stable';
import 'regenerator-runtime/runtime';

Using chrome extension apis in typescript

I'm building a chrome extension written in TypeScript. I'm using WebStorm and I added the chrome-DefiniteltyTyped library in my project.
However, when I write this in my typescript code : chrome.extension.getURL
I got an error : cannot find name 'chrome'.
Because of this, my javascript file is not generated and I cannot use it in my extension.
Do you guys have any solution?
As of typescript 2 (or 2.x, not sure), you should import the chrome types from #types.
in package.json:
"devDependencies": {
...
"#types/chrome": "0.0.35", // or just npm install --save-dev #types/chrome
And in tsconfig:
"types": [
//(various types, e.g. jquery, core-js),
"chrome"
]
That should work fine : https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/chrome/index.d.ts
TIP: make sure you have a reference tag added:
/// <reference path="pathTo/chrome.d.ts"/>
Types Across Chrome and Firefox
Since the extension API is basically the same across Chrome and Firefox now, you can use #types/chrome for both situations.
1. install
yarn add #types/chrome --dev
2. update tsconfig
{
"compilerOptions": {
....
"types": ["chrome"]
}
}
3. Get browser api function
export function getBrowserInstance(): typeof chrome {
// Get extension api Chrome or Firefox
const browserInstance = window.chrome || (window as any)['browser'];
return browserInstance;
}
You just need to install Type definition to make it work, let's install it:
yarn add #types/chrome --dev
or NPM
npm install #types/chrome --save-dev
now use free of error!
I just ran into the below error when trying to develop a Chrome extension using TypeScript in VS Code and all I had to do was simply run:
npm install --save-dev #types/chrome
This will enter "#types/chrome": "0.0.120" under "devDependencies" in your package.json file.
Fixed error:
[tsl] ERROR in C:\Users\my_user\Documents\my_chrome_extension\src\content.ts(28,3)
TS2304: Cannot find name 'chrome'.
What did work:
Have typescript ignore the offending code by adding a comment like this above it.
// #ts-ignore: saying 'chrome' is not found
What didn't work:
I had #types/chrome installed when I ran into this issue.
In the tsconfig.json, adding "chrome" under types and specifying the
typesroot.
Adding a reference path comment and all sorts of ways to
import "chrome".
try these before you add the #ts-ignore comment.
Background:
I am working on a chrome extension using Angular 11. I need to access chrome.runtime.sendMessage to send information to a background worker.
Make sure you have #types/chrome installed. I don't think you need to update the types and the typeroots of tsconfig. Then use the type definitions from chrome by accessing the chrome type which will be globally available, for example:
type getUrl = typeof chrome.runtime.getURL;
A bit more context in this GitHub issue

Categories

Resources