We are in the midst of updating our API, and Henry Zhu from Babel alerted me to this preset called babel-preset-env to replace need for babel-preset-es2015 and babel-preset-es2018.
Now, I am encountering difficulty understanding the simplest way to handle everything.
Our API uses node v8.x and async/await, native promises
I want spread operator
I want pipeline operator
I want import/export syntax
I want to support Jest
I like how babel-node transpiles the API into memory
This will be easier if I just show you the current position of our config:
.babelrc
{
"presets": [
"env",
{
"targets": {
"node": "current"
}
},
"jest"
]
}
package.json
{
"scripts": {
"test": "node --harmony-async-await node_modules/jest/bin/jest.js",
"start:local": "NODE_ENV=localhost npm run babel-node -- warpcore/server.js",
"start": "npm run babel-node -- warpcore/server.js",
"babel-node": "babel-node --presets=es2015,stage-2"
},
"dependencies": {
"babel-polyfill": "^6.23.0"
},
"devDependencies": {
"babel-cli": "^6.24.1",
"babel-core": "^6.25.0",
"babel-eslint": "^7.2.3",
"babel-jest": "^20.0.3",
"babel-preset-env": "^1.6.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-es2018": "^1.0.0",
"babel-preset-stage-2": "^6.24.1",
"jest": "^20.0.4"
},
"jest": {
"testURL": "http://localhost:8080",
"testEnvironment": "node"
}
}
I am uncertain how these things need to be organized to best achieve my bullet list above.
What changes should I make?
I think the babel-node script needs to change
I suspect I can remove some of these packages
I suspect the .babelrc file isn't optimal
If you want to use babel-preset-env as a replacement for babel-preset-es2015 (which is deprecated) with Jest, then you have to make sure that the "modules" property in your "env" configuration is set to "commonjs".
Here is an exemplary configuration:
.babelrc
{
"env": {
"test": {
"plugins": [
"transform-class-properties",
"transform-object-rest-spread"
],
"presets": [
"jest",
"react",
[
"env",
{
"debug": false,
"modules": "commonjs",
"targets": {
"node": "current"
},
"useBuiltIns": true
}
]
]
}
}
}
You can see in env.test, that the preset env (which is the "babel-preset-env" configuration) has "modules" set to "commonjs". That's important, otherwise you will get "SyntaxError: Unexpected token import".
For completeness, here is a simple test:
ExampleButton.test.jsx
import ExampleButton from './ExampleButton';
import React from 'react';
import renderer from 'react-test-renderer';
test('Example Test', () => {
const component = renderer.create(<ExampleButton />);
const json = component.toJSON();
expect(json.type).toBe('button');
});
ExampleButton.jsx
import React from 'react';
class ExampleButton extends React.Component {
render() {
return (
<button onClick={this.props.onClick}>
{this.props.text}
</button>
)
}
}
export default ExampleButton;
For my Babel setup, I have used the following dependencies:
"babel-core": "6.26.0",
"babel-jest": "21.2.0",
"babel-plugin-transform-class-properties": "6.24.1",
"babel-plugin-transform-object-rest-spread": "6.26.0",
"babel-preset-env": "1.6.1",
"babel-preset-react": "6.24.1",
"jest": "21.2.1",
"react-test-renderer": "16.1.1",
I think I got it working. Here is the solution:
.babelrc
The one posted in the question has a syntax error because the env preset needs to be wrapped in brackets[] (from: http://babeljs.io/docs/plugins/preset-env/)
Correct:
{
"presets": [
["env",
{
"targets": {
"node": "current"
}
}],
"jest"
]
}
package.json
The one posted in the question has a few things that can be removed:
{
"scripts": {
"test": "jest --verbose",
"start:local": "cross-env NODE_ENV=localhost babel-node -- app.js",
"babel-node": "babel-node --presets=env"
},
"dependencies": {
"babel-cli": "^6.24.1",
"babel-preset-env": "^1.6.0"
},
"devDependencies": {
"babel-eslint": "^7.2.3",
"babel-jest": "^20.0.3",
"jest": "^20.0.4"
},
"jest": {
"testURL": "http://localhost:8080",
"testEnvironment": "node"
}
}
Much cleaner in my opinion. You can modulate the presets from the .babelrc file if you want to explicitly include or exclude any, or specify which browsers to support.
This is the solution I found:
{
"presets": ["#babel/env", "#babel/react"]
}
Related
I'm writing an Electron app with React and Typescript, using Webpack, Babel and ESLint but I'm having trouble setting:
mainWindow = new BrowserWindow({
title: "Biomech",
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
enableRemoteModule: false,
sandbox: true,
preload: path.join(__dirname, "./preload.js"),
nativeWindowOpen: true,
},
});
which I want as a security measure.
The reason being that, if I set the webPreferences as specified above, I need to use contextBridge and a preload script that binds the functions that are using IPC to the window. And the problem is that contextBridge is not being properly imported in my preload.ts:
import { contextBridge, ipcRenderer } from "electron";
import { readFileSync } from 'fs';
import { History } from 'history';
import { LIST_DRIVE_FILES_CHANNEL, LOAD_PREV_TEST_RESULTS_CHANNEL, OAUTH2_ACCESS_TOKEN_REQUEST_CHANNEL } from "../src/constants/ipcChannels";
import { VISUALIZE_RESULTS_PATH } from "../src/constants/urls";
// Expose protected methods that allow the renderer process to use
// the ipcRenderer without exposing the entire object
contextBridge.exposeInMainWorld(
"api", {
exchangeCodeForAccessToken: (code: string) => {
ipcRenderer.invoke(OAUTH2_ACCESS_TOKEN_REQUEST_CHANNEL, code);
},
listDriveFiles: (accessToken: string) => {
ipcRenderer.invoke(LIST_DRIVE_FILES_CHANNEL, accessToken);
},
openDirectoryDialog: (history: History) => {
ipcRenderer.invoke(LOAD_PREV_TEST_RESULTS_CHANNEL).then((dialog: any) => {
if (dialog.canceled) { // canceled with one l is correct
return;
} else {
const selectedDirectory = dialog.filePaths[0];
console.log(readFileSync(selectedDirectory + "/README.md", 'utf-8'));
history.push(VISUALIZE_RESULTS_PATH);
}
})
}
}
);
The way I see it it's properly used like the examples I've seen here in SO, or in the Electron docs. But when I run my main process script: npm run dev:electron which is specified in my package.json:
{
"name": "electron-react-ts-app",
"version": "1.0.0",
"description": "Electron + React + Typescript",
"main": "./dist/main.js",
"preload": "./dist/preload.js",
"scripts": {
"dev": "concurrently --success first \"npm run dev:electron\" \"npm run dev:react\" -k",
"dev:electron": "NODE_ENV=development webpack --config webpack.electron.config.js --mode development && electron .",
"dev:react": "NODE_ENV=development webpack serve --config webpack.react.config.js --mode development",
"build:electron": "NODE_ENV=production webpack --config webpack.electron.config.js --mode production",
"build:react": "NODE_ENV=production webpack --config webpack.react.config.js --mode production",
"build": "npm run build:electron && npm run build:react",
"pack": "electron-builder --dir",
"dist": "electron-builder",
"lint": "eslint .",
"format": "prettier --write \"**/*.+(js|jsx|json|yml|yaml|css|md|vue)\""
},
"keywords": [],
"license": "MIT",
"build": {
"files": [
"dist/",
"node_modules/",
"package.json"
],
"productName": "Example",
"appId": "com.example.app",
"directories": {
"output": "dist"
}
},
"devDependencies": {
"#babel/preset-env": "^7.9.5",
"#babel/preset-react": "^7.9.4",
"#babel/preset-typescript": "^7.9.0",
"#types/electron-devtools-installer": "^2.2.0",
"#types/react-router-dom": "^5.1.7",
"#types/regenerator-runtime": "^0.13.0",
"dpdm": "^3.6.0",
"electron": "^11.2.1",
"electron-builder": "^22.7.0",
"electron-devtools-installer": "^3.1.1",
"eslint": "^7.18.0",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^4.5.1",
"husky": "^4.3.8",
"lint-staged": "^10.5.3",
"prettier": "^2.2.1",
"react-router-dom": "^5.2.0",
"webpack": "^5.11.1",
"webpack-cli": "^4.3.1",
"webpack-dev-server": "^3.11.1"
},
"dependencies": {
"#babel/core": "^7.12.10",
"#popperjs/core": "^2.6.0",
"#types/node": "^14.14.22",
"#types/react": "^17.0.0",
"#types/react-dom": "^17.0.0",
"axios": "^0.21.1",
"babel-loader": "^8.2.2",
"bootstrap": "^4.5.3",
"chokidar": "^3.5.1",
"core-js": "^3.8.3",
"css-loader": "^5.0.1",
"electron-fetch": "^1.7.3",
"fsevents": "^2.3.1",
"ini": "^2.0.0",
"jquery": "^3.5.1",
"react": "^17.0.1",
"react-bootstrap": "^1.4.0",
"react-dom": "^17.0.1",
"react-google-login": "^5.2.2",
"style-loader": "^2.0.0"
},
"husky": {
"hooks": {
"pre-commit": "npm run lint && npm run format"
}
},
"lint-staged": {
"*.+(js|jsx)": "eslint --fix",
"*.+(json|css|md)": "prettier --write"
}
}
I get the following error: Cannot read property 'exposeInMainWorld' of undefined
webpack 5.19.0 compiled successfully in 1793 ms
App threw an error during load
TypeError: Cannot read property 'exposeInMainWorld' of undefined
at Object../electron/preload.ts (/Users/lucas_sg/Documents/ITBA/PF/pf-biomech/dist/preload.js:24:53)
at __webpack_require__ (/Users/lucas_sg/Documents/ITBA/PF/pf-biomech/dist/preload.js:128:41)
at /Users/lucas_sg/Documents/ITBA/PF/pf-biomech/dist/preload.js:252:11
at Object.<anonymous> (/Users/lucas_sg/Documents/ITBA/PF/pf-biomech/dist/preload.js:254:12)
at Module._compile (internal/modules/cjs/loader.js:1152:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1173:10)
at Module.load (internal/modules/cjs/loader.js:992:32)
at Module._load (internal/modules/cjs/loader.js:885:14)
at Function.f._load (electron/js2c/asar_bundle.js:5:12738)
at Module.require (internal/modules/cjs/loader.js:1032:19)
I've checked out this repo regarding Electron security and it doesn't look like he's doing things too different, at least at first glance, but I'm clearly messing something up.
Here's my webpack config (webpack.electron.config.js) in case it's useful:
const path = require("path");
module.exports = [
{
resolve: {
extensions: [".tsx", ".ts", ".js"],
},
devtool: "source-map",
entry: {
main: {
import: "./electron/main.ts",
dependOn: "preload"
},
preload: "./electron/preload.ts"
},
output: {
path: path.resolve(__dirname, "dist"),
filename: "[name].js",
},
target: "electron-main",
module: {
rules: [
{
test: /\.(js|ts|tsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
},
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
],
},
node: {
__dirname: false,
},
},
];
I think the issue resides in you webpack.config file:
entry: {
main: {
import: "./electron/main.ts",
dependOn: "preload"
},
preload: "./electron/preload.ts"
},
Might be that webpack tries to resolve all "preload.ts" dependency at compile time, plus tries to bundle it together with main.ts file. And in such case it will never get access to contextBridge. The preload.js file should only be run in a separate "context" - "Isolated World" as they refer in the docs.
What I would try is:
remove the dependOn: and preload: lines from you webpack config.
convert preload.ts file to JS (ie. to CommonJS format) - try doing that with TS CLI for now
Your preload.js file should look more or less like this:
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld(
'electron',
{
doThing: () => ipcRenderer.send('do-a-thing')
}
)
copy preload.js to a __dirname (in my case it was /dist)
run electron again
That was the only way I could access "contextBridge" object.
I am running through a React tutorial and have hit this problem when I run npm run on my project. The larger error code is:
ERROR in ./src/index.jsx
Module build failed (from ./node_modules/babel-loader/lib/index.js):
Error: Plugin/Preset files are not allowed to export objects, only functions. In /S8L27nodeproject/node_modules/babel-preset-react/lib/index.js
Looking at similar questions I thought my versions of Babel were not up-top-date, seeing as babel-loader is a different version to the others, but when I run npm outdated they appear fine.
My package.json file is:
{
"name": "s8l27nodeproject",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack -p",
"start": "node ./node_modules/webpack-dev-server/bin/webpack-dev-server.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"babel-core": "^6.26.3",
"babel-loader": "^8.0.4",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-1": "^6.24.1",
"react": "^16.6.0",
"react-dom": "^16.6.0",
"webpack": "^4.25.1",
"webpack-dev-server": "^3.1.10"
},
"devDependencies": {
"#babel/core": "^7.1.5",
"webpack-cli": "^3.1.2"
}
}
Whilst my webpack.config.js file is:
module.exports = {
entry: [
'./src/index.jsx'
],
output: {
filename: './bundle.js'
},
module: {
rules: [{
exclude: /node_modules/,
loader: 'babel-loader'
}]
}
}
Would anyone know what I could do to fix this problem?
I am trying to use http-hash module in order to construct an API for my application. I am using AVA as my test runner for my previous test. When I run the "npm test" command, I get this error in my console:
import { send } from 'micro'
^^^^^^
SyntaxError: Unexpected token import
I am using a linter and it doesn't send me any error. Here is my package.json, where you can see that I am using some babel plugins in order to transpile generators:
{
"name": "pos_lisa-api",
"version": "0.1.0",
"description": "LISA POS REST API",
"scripts": {
"lint": "standard",
"test": "npm run lint && ava"
},
"author": "Mauricio Cano Giraldo",
"license": "MIT",
"devDependencies": {
"ava": "^0.18.1",
"babel-eslint": "^7.1.1",
"babel-register": "^6.23.0",
"standard": "^8.6.0",
"test-listen": "^1.0.1"
},
"dependencies": {
"babel-plugin-transform-async-to-generator": "^6.22.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-es2015": "^6.22.0",
"babel-runtime": "^6.22.0",
"http-hash": "^2.0.0",
"micro": "^7.0.6",
"request": "^2.79.0",
"request-promise": "^4.1.1",
"uuid-base62": "^0.1.0"
},
"standard": {
"parser": "babel-eslint"
},
"babel": {
"presets": [
"es2015"
],
"plugins": [
"transform-runtime",
"transform-async-to-generator"
]
}
}
And here is my node file, where i get the error:
'use strict'
import { send } from 'micro'
import httpHash from 'http-hash'
const hash = httpHash()
hash.set('GET /:id', async function getCliente (req, res, params) {
send(res, 200, params)
})
export default async function main (req, res) {
let method = req.method
let url = req.url
let match = hash.get(`${method.toUpperCase()} ${url}`)
if (match.handler) {
try {
await match.handler(req, res, match.params)
} catch (e) {
send(res, 500, { error: e.message })
}
} else {
send(res, 404, { error: 'La ruta no fue encontrada' })
}
}
I am reading around the web and I don't find anything. Please, help me! I would appreciate it so much!
AVA only transpiles the test files you want to run, but not the modules you're importing in them. But you can tell AVA to also transpile the imported modules by requiring babel-register (https://github.com/avajs/ava#transpiling-imported-modules). And because you configured babel already you can also tell it to use your config. Add this to your package.json
"ava": {
"babel": "inherit",
"require": ["babel-register"]
}
If you'd like to use the babel config AVA uses, you can leave off the "babel": "inherit", or you can define an entirely different one if you wish. But usually it's best to just inherit your config.
Using a .babelrc instead may work.
I want to use async/await in mocha in order to make my tests. I have read many post, but I didn't find the solution. I have already install all the babel modules in order to transpiling the code, but it doesn't work.
Here is my code inside the "test" folder:
import test from 'mocha'
import 'babel-polyfill'
import { expect } from 'chai'
import { assert } from 'chai'
import utils from '../lib/utils'
describe('long number', function () {
it("Sample", mochaAsync(async () => {
var x = utils.longNums(0);
expect(x).to.equal(5000);
}))
})
Here is my package.json where I am using all the babel dependencies and plugins that I have read I have to install, and my test script where I suggest to mocha to use the babel transpiling
{
"name": "pos_lisa-test",
"version": "1.0.0",
"description": "pos lisa test",
"main": "index.js",
"scripts": {
"test": "mocha --compilers js:babel-core/register ./src/**/*.test.js"
},
"standard": {
"parser": "babel-eslint"
},
"babel": {
"presets": [
"es2015",
"react"
]
},
"keywords": [
"test"
],
"author": "Mauricio",
"license": "MIT",
"devDependencies": {
"babel-core": "^6.23.1",
"babel-eslint": "^7.1.1",
"babel-plugin-transform-async-to-generator": "^6.22.0",
"babel-preset-es2015": "^6.22.0",
"babel-preset-react": "^6.23.0",
"chai": "^3.5.0",
"mocha": "^3.2.0",
},
"plugins": [
"transform-async-to-generator"
],
"dependencies": {
"babel-polyfill": "^6.23.0"
}
}
And the error that I get is the following
it('should remove items that don\'t evaluate to true when passed to predicate function', async function () {
^^^^^
SyntaxError: missing ) after argument list
What I am doing wrong? In advance thanks a lot for your help
You have added "plugins": ["transform-async-to-generator"]" to the top level of your package.json, but it should be inside the "babel" section. Change it to:
"babel": {
"presets": [
"es2015",
"react"
],
"plugins": [
"transform-async-to-generator"
]
},
According to the Tao of Javascript, "Code flows in the moment, so knowledge is but a hint, like the map of a stream."
As of April, 2017, having the 'transform-async-to-generator' will actually cause problems.
As a more general note, every async function returns a promise, or casts its return value and exception to a promise. It is usually cleaner to test the promise and not have your test call await:
it('should have no drops left', () =>
ocean.listDrops().should.eventually.have.length(0));
I want to use ES2015 modules in Node.js with babel.js compiler, but it won't work. Here is what I have:
package.json
{
"name": "test",
"version": "0.0.1",
"private": true,
"scripts": {
},
"devDependencies": {
"babel-core": "^6.9.0",
"babel-plugin-transform-runtime": "^6.9.0",
"babel-preset-es2015": "^6.9.0",
"babel-preset-node5": "^11.1.0",
}
}
.babelrc
{
"presets": ["es2015"],
"plugins": [
"transform-runtime"
]
}
server/index.js
require('babel-core').transform('code', {
presets: ['node5'],
});
import { test } from './file1';
console.log(test);
server/file1.js
export const test = 'its working!';
But console throws error SyntaxError: Unexpected token import
Does ES2015 modules not working in node5, or I am doing something wrong here? Appreciate your help.
Please install babel-register npm module and require this in index.js
server/index.js
require('babel-register');
import { test } from './file1';
console.log(test);
package.json
{
"name": "test",
"version": "0.0.1",
"private": true,
"scripts": {
},
"devDependencies": {
"babel": "^6.5.2",
"babel-preset-es2015": "^6.6.0",
"babel-register": "^6.8.0"
}
}
.babelrc
{presets:[es2015]}
for me it works
Thanks