How to remove global "use strict" added by babel - javascript

I'm using function form of "use strict" and don't want global form which Babel adds after transpilation. The problem is I'm using some libraries that aren't using "use strict" mode and it might throw error after scripts are concatenated

As it has already been mentioned for Babel 6, it's the transform-es2015-modules-commonjs preset which adds strict mode.
In case you want to use the whole es2015 preset without module transformations, put this in your .babelrc file:
{
"presets": [
["es2015", { "modules": false }]
]
}
This will disable modules and strict mode, while keeping all other es2015 transformations enabled.

Babel 5
You'd blacklist "useStrict". For instance here's an example in a Gruntfile:
babel: {
options: {
blacklist: ["useStrict"],
// ...
},
// ...
}
Babel 6
Since Babel 6 is fully opt-in for plugins now, instead of blacklisting useStrict, you just don't include the strict-mode plugin. If you're using a preset that includes it, I think you'll have to create your own that includes all the others, but not that one.

There's now a babel plugin that you can add to your config that will remove strict mode: babel-plugin-transform-remove-strict-mode. It's a little ugly in that the "use strict" gets added and then removed, but it makes the config much nicer.
Docs are in the GitHub repo:
https://github.com/genify/babel-plugin-transform-remove-strict-mode
Your .babelrc ends up looking like this:
{
"presets": ["env"],
"plugins": ["transform-remove-strict-mode"]
}

I also came accross this rather ridiculous limitation that you cannot disable or overwrite settings from an existing preset, and have resorted to using this preset instead: https://www.npmjs.com/package/babel-preset-es2015-without-strict

plugins: [
[
require("#babel/plugin-transform-modules-commonjs"),
{
strictMode: false
}
],
]

You can tell babel that your code is a script with:
sourceType: "script"
in your babel config file. This will not add use strict. See sourceType option docs
Source: https://github.com/babel/babel/issues/7910#issuecomment-388517631

Babel 6 + es2015
We can disabled babel-plugin-transform-es2015-modules-commonjs to require babel-plugin-transform-strict-mode.
So comment the following code in node_modules/babel-plugin-transform-es2015-modules-commonjs/lib/index.js at 151 line
//inherits: require("babel-plugin-transform-strict-mode"),

just change .babelrc solution
if you don't want to change any npm modules, you can use .babelrc ignore like this
{
"presets": ["es2015"],
"ignore": [
"./src/js/directive/datePicker.js"
]
}
ignore that file, it works for me!
the ignored file that can't use 'use strict' is old code, and do not need to use babel to transform it!

Personally, I use the gulp-iife plugin and I wrap IIFEs around all my files. I noticed that the babel plugin (using preset es2015) adds a global "use strict" as well. I run my post babel code through the iife stream plugin again so it nullifies what babel did.
gulp.task("build-js-source-dev", function () {
return gulp.src(jsSourceGlob)
.pipe(iife())
.pipe(plumber())
.pipe(babel({ presets: ["es2015"] }))// compile ES6 to ES5
.pipe(plumber.stop())
.pipe(iife()) // because babel preset "es2015" adds a global "use strict"; which we dont want
.pipe(concat(jsDistFile)) // concat to single file
.pipe(gulp.dest("public_dist"))
});

This is not grammatically correct, but will basically work for both Babel 5 and 6 without having to install a module that removes another module.
code.replace(/^"use strict";$/, '')

Since babel 6 you can install firstly babel-cli (if you want to use Babel from the CLI ) or babel-core (to use the Node API). This package does not include modules.
npm install --global babel-cli
# or
npm install --save-dev babel-core
Then install modules that you need. So do not install module for 'strict mode' in your case.
npm install --save-dev babel-plugin-transform-es2015-arrow-functions
And add installed modules in .babelrc file like this:
{
"plugins": ["transform-es2015-arrow-functions"]
}
See details here: https://babeljs.io/blog/2015/10/31/setting-up-babel-6

For babel 6 instead of monkey patching the preset and/or forking it and publishing it, you can also just wrap the original plugin and set the strict option to false.
Something along those lines should do the trick:
const es2015preset = require('babel-preset-es2015');
const commonjsPlugin = require('babel-plugin-transform-es2015-modules-commonjs');
es2015preset.plugins.forEach(function(plugin) {
if (plugin.length && plugin[0] === commonjsPlugin) {
plugin[1].strict = false;
}
});
module.exports = es2015preset;

Please use "es2015-without-strict" instead of "es2015". Don't forget you need to have package "babel-preset-es2015-without-strict" installed. I know it's not expected default behavior of Babel, please take into account the project is not mature yet.

I just made a script that runs in the Node and removes "use strict"; in the selected file.
file: script.js:
let fs = require('fs');
let file = 'custom/path/index.js';
let data = fs.readFileSync(file, 'utf8');
let regex = new RegExp('"use\\s+strict";');
if (data.match(regex)){
let data2 = data.replace(regex, '');
fs.writeFileSync(file, data2);
console.log('use strict mode removed ...');
}
else {
console.log('use strict mode is missing .');
}
node ./script.js

if you are using https://babeljs.io/repl (v7.8.6 as of this writing), you can remove "use strict"; by selecting Source Type -> Module.

Using plugins or disabling modules and strict mode as suggested in the #rcode's answer didn't work for me.
But, changing the target from es2015|es6 to es5 in tsconfig.json file as suggested by #andrefarzart in this GitHub answer fixed the issue.
// tsconfig.json file
{
// ...
"compilerOptions": {
// ...
"target": "es5", // instead of "es2015"
}

Related

Module parse failed: Unexpected token ? Optional chaining not recognised in threejs svgloader.js [duplicate]

Project setup:
Vuejs 3
Webpack 4
Babel
TS
We created the project using vue-cli and add the dependency to the library.
We then imported a project (Vue Currency Input v2.0.0) that uses optional chaining. But we get the following error while executing the serve script:
error in ./node_modules/vue-currency-input/dist/index.esm.js
Module parse failed: Unexpected token (265:36)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| getMinValue() {
| let min = this.toFloat(-Number.MAX_SAFE_INTEGER);
> if (this.options.valueRange?.min !== undefined) {
| min = Math.max(this.options.valueRange?.min, this.toFloat(-Number.MAX_SAFE_INTEGER));
| }
I read that Webpack 4 doesn't support optional chaining by default. So, we added the Babel plugin for optional chaining. This is our babel.config.js file:
module.exports = {
presets: ["#vue/cli-plugin-babel/preset"],
plugins: ["#babel/plugin-proposal-optional-chaining"],
};
(But, if I am correct, this plugin is now enable by default in the babel-preset. So this modification might be useless ^^)
One thing that I don't understand is that we can use optional chaining in the .vue files.
I created a SandBox with all the files: SandBox
How could I solve this error?
I was able to overcome this issue using #babel/plugin-proposal-optional-chaining, but for me the only way I could get Webpack to use the Babel plugin was to shove the babel-loader configuration through the Webpack options in vue.config.js. Here is a minimal vue.config.js:
const path = require('path');
module.exports = {
chainWebpack: config => {
config.module
.rule('supportChaining')
.test(/\.js$/)
.include
.add(path.resolve('node_modules/PROBLEM_MODULE'))
.end()
.use('babel-loader')
.loader('babel-loader')
.tap(options => ({ ...options,
plugins : ['#babel/plugin-proposal-optional-chaining']
}))
.end()
}
};
NB replace "PROBLEM_MODULE" in the above with the module where you have the problem.
Surprisingly I did not need to install #babel/plugin-proposal-optional-chaining with NPM. I did a go/no-go test with an app scaffolded with #vue/cli 4.5.13, in my case without typescript. I imported the NPM module that has been causing my grief (#vime/vue-next 5.0.31 BTW), ran the serve script and got the Unexpected token error on a line containing optional chaining. I then plunked the above vue.config.js into the project root and ran the serve script again, this time with no errors.
My point is it appears this problem can be addressed without polluting one's development environment very much.
The Vue forums are in denial about this problem, claiming Vue 3 supports optional chaining. Apparently not, however, in node modules. A post in this thread by atflick on 2/26/2021 was a big help.
Had same issue with Vue 2 without typescript.
To fix this you need to force babel preset to include optional chaining rule:
presets: [
[
'#vue/cli-plugin-babel/preset',
{
include: ['#babel/plugin-proposal-optional-chaining'],
},
],
],
Can also be achieved by setting old browser target in browserslist config.
Most importantly, you need to add your failing module to transpileDependencies in vue.config.js:
module.exports = {
...
transpileDependencies: ['vue-currency-input],
}
This is required, because babel by default will exclude all node_modules from transpilation (mentioned in vue cli docs), thus no configured plugins will be applied.
I had a similar problem. I'm using nuxt but my .babelrc file looks like the below, and got it working for me.
{
"presets": [
["#babel/preset-env"]
],
"plugins":[
["#babel/plugin-transform-runtime",
{
"regenerator": true
}
]
],
"env": {
"test": {
"plugins": [
["transform-regenerator", {
"regenerator": true
}],
"#babel/plugin-transform-runtime"
],
"presets": [
["#babel/preset-env", {
"useBuiltIns": false
}]
]
}
}
}
I managed to fix the solution by adding these lines to package.json:
...
"scripts": {
"preinstall": "npx npm-force-resolutions",
...
},
"resolutions": {
"acorn": "8.0.1"
},
...

What is best practice for `#babel/preset-env` + `useBuiltIns` + `#babel/runtime` + `browserslistrc`

I get different output for different configurations of #babel/preset-env with useBuiltIns used in combination with #babel/transform-runtime. I've read the documentation, but haven't been able to figure out what the best practice should be.
For example, #babel/preset-env with useBuiltIns will add a polyfill for string.replace when my targeted list of browsers includes Edge 18.
But when I use #babel/transform-runtime instead, that polyfill doesn't get added.
So, starting out with this question:
Does `string.replace` need to be polyfilled for Edge 18?
I checked caniuse.com which shows it as fully supported - which would mean no polyfills are required.
However, according to Manuel Beaudru's blog post core-js#3, babel and a look into the future
caniuse, mdn and compat-table are good educational resources but
aren't really meant to be used as data sources for developer tools:
only the compat-table contains a good set of ES-related data and it
is used by #babel/preset-env, but it has some limitations
And further:
For this reason, I created the core-js-compat package: it provides
data about the necessity of core-js modules for different target
engines. When using core-js#3, #babel/preset-env will use that new
package instead of compat-table.
So I passed my target browsers to core-js-compat and it output all the polfills required. As you can see in the image below, quite a few string methods need to be polyfilled, mostly to support Edge 18.
So far, so good. It looks like string.replace does need to be polyfilled for Edge 18.
Babel config
First approach: #babel/preset-env and useBuiltIns: 'usage'
When I use useBuiltIns: 'usage' to bring in per-file polyfills from core-js:
// babel.config.js
presets: [
[
'#babel/preset-env',
{
debug: false,
bugfixes: true,
useBuiltIns: 'usage',
corejs: { version: "3.6", proposals: true }
}
],
'#babel/preset-flow',
'#babel/preset-react'
],
When debug: true, Babel says it will add the following polyfills to my PriceColumn.js file:
// Console output
[/price-column/PriceColumn.js] Added following core-js polyfills:
es.string.replace { "edge":"17", "firefox":"71", "ios":"12", "safari":"12" }
es.string.split { "edge":"17" }
web.dom-collections.iterator { "edge":"17", "ios":"12", "safari":"12" }
One difference is that it says es.string.replace is to target edge: 17, not edge: 18 as we see in the output from core-js-compat above - might be something I've done, but that's fine for now.
The additions that Babel adds to the top of the transpiled PriceColumn.js file:
// PriceColumn.js
"use strict";
require("core-js/modules/es.string.replace");
require("core-js/modules/es.string.split");
require("core-js/modules/web.dom-collections.iterator");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
Again, so far so good.
Second approach: #babel/runtime and #babel/transform-runtime
According to the core-js documentation:
#babel/runtime with corejs: 3 option simplifies work with
core-js-pure. It automatically replaces usage of modern features
from JS standard library to imports from the version of core-js
without global namespace pollution
Sounds great - let's try it out!
Commenting out useBuiltIns and adding #babel/transform-runtime plugin config:
// babel.config.js
presets: [
[
'#babel/preset-env',
{
debug: true,
// bugfixes: true,
// useBuiltIns: 'usage',
// corejs: { version: '3.6', proposals: true }
}
],
'#babel/preset-flow',
'#babel/preset-react'
],
plugins: [
[
'#babel/transform-runtime',
{
corejs: { version: 3, proposals: true },
version: '^7.8.3'
}
]
],
In the console output, I see:
Using polyfills: No polyfills were added, since the `useBuiltIns` option was not set.
Checking what was added to the top of the file:
// PriceColumn.js
"use strict";
var _interopRequireDefault = require("#babel/runtime-corejs3/helpers/interopRequireDefault");
var _Object$defineProperty = require("#babel/runtime-corejs3/core-js/object/define-property");
_Object$defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _objectSpread2 = _interopRequireDefault(require("#babel/runtime-corejs3/helpers/objectSpread2"));
var _map = _interopRequireDefault(require("#babel/runtime-corejs3/core-js/instance/map"));
So, different helpers were added - but no sign of the es.string.* polyfills. Are they no longer required? Are they already brought in by the 'helpers'? It doesn't look like object spread and array map would have anything to do with polyfilling string instance methods, so I think not.
Finally
My last attempt was to combine both approaches - and to follow the recommendations:
a) Set corejs for #babel/preset-env:
// babel.config.js
presets: [
[
'#babel/preset-env',
{
debug: true,
// bugfixes: true,
useBuiltIns: 'usage',
corejs: { version: '3.6', proposals: true }
}
],
'#babel/preset-flow',
'#babel/preset-react'
],
plugins: [
[
'#babel/transform-runtime',
{
// corejs: { version: 3, proposals: true },
version: '^7.8.3'
}
]
]
and this is the output:
// PriceColumn.js
"use strict";
var _interopRequireDefault = require("#babel/runtime/helpers/interopRequireDefault");
require("core-js/modules/es.string.replace");
require("core-js/modules/es.string.split");
require("core-js/modules/web.dom-collections.iterator");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _objectSpread2 = _interopRequireDefault(require("#babel/runtime/helpers/objectSpread2"));
b) Set corejs for #babel/transform-runtime:
same as second approach (see above)
Comparing the output for the different approaches
Using just useBuiltIns:
Brings in the required string polyfills, but pollutes the global namespace.
Using just #babel/runtime-transform:
Doesn't bring in any string polyfills, but brings in other helpers/polyfills ??, for Array map and Object spread
Using combination of both useBuiltIns and #babel/transform-runtime:
Brings in the required string polyfills, but pollutes the global namespace.
Also brings in Object spread polyfill (but not the Array map polyfill)
Imports from #babel/runtime/helpers/objectSpread2, not #babel/runtime-corejs3/helpers/objectSpread2 (runtime vs runtime-corejs3) - could be the reason that Array map polyfill was not brought in??)
Question
Which - if any - of these is the correct approach?
I'm guessing the #babel/preset-env with useBuiltIns is the best because it brings in the polyfills.
What are the drawbacks to polluting the global namespace? Is this an issue for libraries only?
In combination with #babel/transform-runtime, we also get a polyfill for object spread (even though #babel-preset-env has corejs: { version: '3.6', proposals: true } which should polyfill proposals, so I'm not sure why it doesn't get brought in there without having to use the #babel/transform-runtime plugin too)
Do we need the Array#map polyfill?
Suggested by https://www.jmarkoski.com/understanding-babel-preset-env-and-transform-runtime:
App: If you are authoring an app, use import 'core-js at the top of your app with useBuiltIns set to entry and #babel/transform-runtime only for helpers (#babel/runtime as dependency). This way you pollute the global environment but you don't care, its your app. You will have the benefit of helpers aliased to #babel/runtime and polyfills included at the top of your app. This way you also don't need to process node_modules (except when a dependency uses a syntax that has to be transpiled) because if some dependency used a feature that needs a polyfill, you already included that polyfill at the top of your app.
Library: If you are authoring a library, use only #babel/transform-runtime with corejs option plus #babel/runtime-corejs3 as dependency, and #babel/preset-env for syntax transpilation with useBuiltIns: false. Also I would transpile packages I would use from node_modules. For this you will need to set the absoluteRuntime option (https://babeljs.io/docs/en/babel-plugin-transform-runtime#absoluteruntime) to resolve the runtime dependency from a single place, because #babel/transform-runtime imports from #babel/runtime-corejs3 directly, but that only works if #babel/runtime-corejs3 is in the node_modules of the file that is being compiled.
More Info:
https://github.com/zloirock/core-js/issues/848
https://github.com/zloirock/core-js/issues/833
https://babeljs.io/docs/en/babel-plugin-transform-runtime

Can I use Babel to transpile to ES5 but keep import/export instead of commonjs?

I want to create an npm library that delivers modules using ES import/export instead of commonjs (like for example lodash-es does). If I'm not mistaken, the delivered code must be ES5 and has import/export.
I can't figure out how to configure Babel to do that. I expect that the option targets.esmodules should do the trick.
When I have the following code in calc.js:
// calc.js
export function add (a, b) {
const result = a + b
return result
}
and babel configuration .babelrc:
{
"presets": [
[
"#babel/preset-env",
{
"targets": {
"esmodules": true
}
}
]
]
}
When running babel:
babel calc.js
The output is:
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.add = add;
function add(a, b) {
var result = a + b;
return result;
}
Which is commonjs (exports.add). The option targets.esmodules seems to have no effect. How can I get Babel to generate an es module (export function add)? Or am I misunderstanding the idea of delivering ES modules on npm?
It looks like based on the Rollup docs that you should indeed transpile a version that has only import/export, but has transpiled out all of the other non-ES5 syntax. The Webpack docs say something similar. This format assumes that your users are using tools like Rollup or Webpack, which natively support import/export statements, but then presumably transpile them to an ES5 compatible syntax without needing to run your library through Babel.
And it looks like Redux in particular pulls this off by using the Rollup format option and then in their .babelrc file they use the "modules": false option to tell Babel not to transpile module statements. It's not clear to me how Lodash manages it, since looking over their source code I don't see any build scripts anywhere in the repo.

`.babelrc` file can't find presets in a nested node_modules folder

I have a directory structure like this:
> build
> node_modules
> webpack.config.js
> .babelrc
> .gitignore
My .babelrc looks like this:
{
"presets": ["es2015", "stage-0", "react"]
}
Currently I'm getting the following error...
Module build failed: Error: Couldn't find preset "es2015" relative to directory
Are there any options within the .babelrc file that will allow me to specify the path to node_modules? Or any other way to fix this issue?
Unfortunately there is no way to move the node_modules out to the root.
Unfortunately there is currently no option in .babelrc to control the way Babel loads modules. But there are a few workarounds to solve the problem in various situations.
Babel actually accepts both strings and (module) objects as presets and plugins, so you can pass either the module's name (in which case Babel will try to resolve and load it using its own mechanism), or you can load the module yourself and pass it directly to Babel.
The problem is that if you use .babelrc, as it's JSON, you can obviously only pass the module's name, which subjects you to Babel's built-in module-loading mechanism.
If you use webpack, you can abandon .babelrc altogether and directly pass options to Babel in webpack config, like this:
query: {
presets: [
'babel-preset-es2015',
'babel-preset-react',
'babel-preset-stage-0',
].map(require.resolve),
}
See: How to set resolve for babel-loader presets
If you use Babel directly, in your own code, then you can still use .babelrc, but change the code that reads it, to load the presets and plugins yourself.
for example, if you have the following code to read .babelrc:
var fs = require('fs');
var babelrc = fs.readFileSync('./.babelrc');
var config = JSON.parse(babelrc);
require('babel-core/register')(config);
You can change it to something like:
var fs = require('fs');
var babelrc = fs.readFileSync('./.babelrc');
var config = JSON.parse(babelrc);
config.presets = config.presets.map(function(preset) {
return require.resolve('babel-preset-' + preset);
});
config.plugins = config.plugins.map(function(plugin) {
return require.resolve('babel-plugin-' + plugin);
});
require('babel-core/register')(config);
You're looking for the resolve property in webpack.
resolve lets you set the source location for your modules:
resolve: {
modulesDirectories: ['build/node_modules']
},

How to ignore a particular directory or file for tslint?

The IDE being used is WebStorm 11.0.3, the tslint is configured and works, but, it hangs because it tries to parse large *.d.ts library files.
Is there a way to ignore a particular file or directory?
Update for tslint v5.8.0
As mentioned by Saugat Acharya, you can now update tslint.json CLI Options:
{
"extends": "tslint:latest",
"linterOptions": {
"exclude": [
"bin",
"lib/*generated.js"
]
}
}
More information in this pull request.
This feature has been introduced with tslint 3.6
tslint \"src/**/*.ts\" -e \"**/__test__/**\"
You can now add --exclude (or -e) see PR here.
CLI
usage: tslint [options] file ...
Options:
-c, --config configuration file
--force return status code 0 even if there are lint errors
-h, --help display detailed help
-i, --init generate a tslint.json config file in the current working directory
-o, --out output file
-r, --rules-dir rules directory
-s, --formatters-dir formatters directory
-e, --exclude exclude globs from path expansion
-t, --format output format (prose, json, verbose, pmd, msbuild, checkstyle) [default: "prose"]
--test test that tslint produces the correct output for the specified directory
-v, --version current version
you are looking at using
-e, --exclude exclude globs from path expansion
Currently using Visual Studio Code and the command to disable tslint is
/* tslint:disable */
Something to note. The disable above disables ALL tslint rules on that page. If you want to disable a specific rule you can specify one/multiple rules.
/* tslint:disable comment-format */
/* tslint:disable:rule1 rule2 rule3 etc.. */
Or enable a rule
/* tslint:enable comment-format */
More in depth on TSLint rule flags
In addition to Michael's answer, consider a second way: adding linterOptions.exclude to tslint.json
For example, you may have tslint.json with following lines:
{
"linterOptions": {
"exclude": [
"someDirectory/*.d.ts"
]
}
}
Starting from tslint v5.8.0 you can set an exclude property under your linterOptions key in your tslint.json file:
{
"extends": "tslint:latest",
"linterOptions": {
"exclude": [
"bin",
"**/__test__",
"lib/*generated.js"
]
}
}
More information on this here.
I had to use the **/* syntax to exclude the files in a folder:
"linterOptions": {
"exclude": [
"src/auto-generated/**/*",
"src/app/auto-generated/**/*"
]
},
As an addition
To disable all rules for the next line // tslint:disable-next-line
To disable specific rules for the next line: // tslint:disable-next-line:rule1 rule2...
To disable all rules for the current line: someCode(); // tslint:disable-line
To disable specific rules for the current line: someCode(); // tslint:disable-line:rule1
There are others who encountered the problem. Unfortunately, there is only an open issue for excluding files: https://github.com/palantir/tslint/issues/73
So I'm afraid the answer is no.
linterOptions is currently only handled by the CLI.
If you're not using CLI then depending on the code base you're using you'll need to set the ignore somewhere else. webpack, tsconfig, etc
Can confirm that on version tslint 5.11.0 it works by modifying lint script in package.json by defining exclude argument:
"lint": "ng lint --exclude src/models/** --exclude package.json"
Cheers!!
add the section in your code example
"linterOptions": {
"exclude": [
"node_modules/**/*.",
"db/**/*.",
"integrations/**/*."
]
},

Categories