Babel-node ignores or misbehaves when I add ignore option to babel.config.js - node.js

am using the command
npx babel-node --ignore=' ' --extensions='.ts,.tsx,.js,.jsx,.es6,.es' test.js
to compile the script named test.js .
test.js imports import template from 'lodash-es/template'; and I would like it to be compiled too.
Adding ignore or include or exclude options regex at babel.config.js doesn't work.
How do i add an inline --ignore option ({ ignore: [/node_modules\/(?!lodash-es)/] }) like babel.config.js?
Why does { ignore: [/node_modules\/(?!lodash-es)/] } work with #babel/register and not with babel.config.js ?
Below is test.js:
import fs from 'fs';
import template from 'lodash-es/template';
console.log(template);
export default function () {
};
package.json:
"#babel/cli": "^7.7.7",
"#babel/core": "^7.7.7",
"#babel/node": "^7.8.4",
Problem seems to be similar to https://github.com/facebook/jest/issues/6229

I resolved the issue with: --ignore="/node_modules\/(?\!lodash-es)/"
npx babel-node --config-file="./babel.config.js" --ignore="/node_modules\/(?\!lodash-es)/" --extensions='.ts,.tsx,.js,.jsx,.es6,.es' test.js
using --ignore=' ' will also work, but you may start getting
[BABEL] Note: The code generator has deoptimised the styling of {filename} as it exceeds the max of 500KB.
because Babel will compile all imported node_modues, which is quite expensive.

Related

My React App Unit Tests Jest is breaking: function(module,exports,require,__dirname,__filename,jest) Cannot use import statement outside a module

I'm facing a problem when trying to run the Jest tests (NextJs app) with my component library.
My React library
I'm using this command to build the React library:
"build-esm": "tsc --project tsconfig.build.json",
"build-cjs": "tsc --project tsconfig.build.json --module commonjs --outDir lib/cjs",
"build": "rm -fr lib/ && npm run build-esm && npm run build-cjs"
Will generate it:
package.json:
(...)
"main": "./lib/cjs/index.js",
"module": "./lib/esm/index.js",
"types": "./lib/esm/index.d.ts",
(...)
My "Nextjs client project" (that will use the lib as a dependency):
jest.config.js
// jest.config.js
const nextJest = require('next/jest');
const createJestConfig = nextJest({
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
dir: './'
});
// Add any custom config to be passed to Jest
/** #type {import('jest').Config} */
const customJestConfig = {
// Add more setup options before each test is run
setupFilesAfterEnv: ['./jest.setup.js'],
// if using TypeScript with a baseUrl set to the root directory then you need the below for alias' to work
moduleDirectories: ['node_modules'],
testEnvironment: 'jest-environment-jsdom',
transformIgnorePatterns: ['<rootDir>/node_modules/']
};
// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
module.exports = createJestConfig(customJestConfig);
console error:
(...)/node_modules/nanoid/index.browser.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import { urlAlphabet } from './url-alphabet/index.js'
^^^^^^
SyntaxError: Cannot use import statement outside a module
8 | var react_window_1 = require("react-window");
9 | var react_window_infinite_loader_1 = __importDefault(require("react-window-infinite-loader"));
> 10 | var nanoid_1 = require("nanoid");
I appreciate any support

import is not working nodeJs application React SSR

I'm trying to implement SSR for a React application I started with creating a server directory that contains 3 files (bootstrap, index, renderer)
bootstrap.js contains babel configs to transpile to es5
index.js create an express application and express Router
renderer.js is responsible for rendering React application to string and send it as html to client.
bootstap.js =>
require('ignore-styles');
require('#babel/register')({
ignore: [
function (filePath) {
return !filePath.includes('node_modules');
}
],
presets: [
[
"#babel/preset-env",
{
"modules": false
}
],
'#babel/preset-react',
'#babel/flow'
],
plugins: [
[
"#babel/plugin-transform-runtime",
{
"regenerator": true
}
],
"#babel/plugin-proposal-object-rest-spread",
"#babel/plugin-syntax-dynamic-import",
"react-loadable/babel",
"#babel/plugin-proposal-class-properties",
"dynamic-import-node"
]
});
require('./index');
index.js =>
import dotenv from 'dotenv';
import cookieParser from 'cookie-parser';
dotenv.config();
const express = require('express');
const serverRenderer = require('./middleware/renderer');
const PORT = process.NODE_ENV === 'development' ? 3000 : 7160;
const path = require('path');
const app = express();
app.use(cookieParser());
const router = express.Router();
const routes = require('../src/router/appRoutes').default;
router.use(express.static(
path.resolve(__dirname, '..', 'build'),
{ maxAge: '30d' },
));
routes.map(path => app.get(path, serverRenderer));
app.use(router);
app.listen(PORT, (error) => {
if (error) {
return console.log('something bad happened', error);
}
console.log("listening on " + PORT + "...");
});
but when I run
NODE_ENV=production node server/bootstrap.js
this command to start server side application I get this error
import dotenv from 'dotenv';
^^^^^^
SyntaxError: Unexpected identifier
at Module._compile (internal/modules/cjs/loader.js:723:23)
at Module._compile (/Users/amirtahani/projects/uneed/node_modules/pirates/lib/index.js:99:24)
at Module._extensions..js (internal/modules/cjs/loader.js:789:10)
at Object.newLoader [as .js] (/Users/amirtahani/projects/uneed/node_modules/pirates/lib/index.js:104:7)
at Module.load (internal/modules/cjs/loader.js:653:32)
at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
at Function.Module._load (internal/modules/cjs/loader.js:585:3)
at Module.require (internal/modules/cjs/loader.js:692:17)
at require (internal/modules/cjs/helpers.js:25:18)
at Object.<anonymous> (/Users/amirtahani/projects/uneed/server/bootstrap.js:34:1)
and the weird thing is the same code is working on another project.
and here is my devDependencies
"devDependencies": {
"#babel/core": "7.6.4",
"#babel/plugin-proposal-class-properties": "7.5.5",
"#babel/plugin-proposal-object-rest-spread": "7.6.2",
"#babel/plugin-syntax-dynamic-import": "7.2.0",
"#babel/plugin-transform-classes": "7.5.5",
"#babel/plugin-transform-modules-commonjs": "7.6.0",
"#babel/plugin-transform-runtime": "7.6.2",
"#babel/preset-env": "7.6.3",
"#babel/preset-flow": "7.0.0",
"#babel/preset-react": "7.6.3",
"#babel/register": "7.6.2",
"babel-cli": "6.26.0",
"babel-plugin-dynamic-import-node": "2.3.0",
"babel-plugin-transform-es2015-modules-commonjs": "6.26.2",
"flow-bin": "0.102.0",
"ignore-styles": "5.0.1"
}
any ideas?
"import --from --" is ES15 syntax, however node.js uses commonJS module syntax. So you need to install and configure webpack. Babel just trans-piles the new generation javascript into the old javascript code. However webpack is going to bundle your application code into a single file and your server file will be executed through that bundle.js.
For server-side rendering you need 2 bundle.js. one for client and another one for server. HTML files without javascript have no functionality.
if we start from server, this is how we write our code into the index.js.
const renderToString=require("react-dom/server").renderToString //specifically created for server
const Home=require("./components/Home").default //home component
const React=require("react")
const express=require("express")
const app=express()
app.get("/",(req,res)=>{
const content =renderToString(<Home/>)
res.send(content)
})
This is how we render our code to the browser for "/" route. there are 2 flaws here. First one, we are sending file without javascript code. Any functionality in Home component will not work. For example, if you had button inside Home component with click event, that click event will not work. Because server is not shipping down any javascript code. Second flaw is we used jsx here:
const content =renderToString(<Home/>). so when node executes this file, it will not recognize this syntax and will give error.
to fix those 2 issues, we need webpack. webpack will transform index.js into a file which we specify the name and its location. In server-side, we usually name the file bundle.js inside public folder. So when we start the server with node or nodemon, we will execute public/bundle.js NOT the index.js file.
So we need to reorganize the code inside index.js and this time since webpack will transform the code, we can use "import" syntax.
import React from "react";
import { renderToString } from "react-dom/server";
import Home from "./components/Home"
import React from "react"
import express from "express";
const app=express()
app.use(express.static("public")) //This will make public folder publicly available so we can ship it down to the browser.
app.get("/",(req,res)=>{
const content=renderToString(<Home/>)
//I used template strings ``
const html= `
<html>
<head></head>
<body>
<div id="root">${content}</div>
<script src="bundle.js"> </script>
//since we are sending a file, express will look for bundle.js inside the public folder. So we do not need to write relative path or absolute path.
</body></html> `
res.send(html)
})
Now we need a file to configure webpack. We name it webpack.config.js in the root of the app.
const path=require("path")
module.exports={
//in server side we keep client and server logic inside src folder
entry:"./src/index.js", //relative path
mode:"development",
output:{filename:bundle.js,
path:path.resolve(__dirname,"build")},
//absolute path. that is why we use native node module path. also you do not need to create build folder. webpack will create automatically
module:{rules:[{test:/\.js$/,
loader:"babel-loader",
exclude:/node_modules/,
options:{presets:["#babel/preset-env","#babel/preset-react"]}}]}
}
lastly in package.json
"scripts": {
"dev:server": "nodemon --watch build --exec \"node build/bundle.js\"",
"dev:build-server": "webpack --config webpack.server.js --watch",
"dev:build-client": "webpack --config webpack.client.js --watch"
},
in dev:server we watch "build" folder for changes.(build folder is in the root of app.) then we execute "bundle.js" file inside the build directory.
so to give an answer to your question, this is the basic of server-side part of isomorphic javascript app.
I installed node LTS (v12.13.0) but got the same error when used import instead of require. It seems that es6 imports are still an experimental feature, even in the latest node version.
If you want to test this feature, you need to do these steps:
Add "type": "module" in your package.json
Run your server with this flag: --experimental-modules. e.g. NODE_ENV=production node --experimental-modules server/bootstrap.js
import and export syntax is still experimental in node js latest versions, but there is a work around to this issue.
try to add "type": "module" in your package.json file and change your .js bundle extension to .mjs in your webpack config and run your generated file with this command:
NODE_ENV=production node --experimental-modules server/bootstrap.mjs
also i recommend you to read this page.
First check if the dotenv package is installed or not. If not, you can install it in the following command -
npm i --save dotenv
In order to use dotenv, you don't need to import it and then configure it.
Instead use the following syntax -
require('dotenv').config()

node throw error when use async/await syntax.but it works well with import/export syntax

nodemon throw the error when use async/await syntax:
**/node_modules/#babel/runtime/helpers/esm/asyncToGenerator.js:17
export default function _asyncToGenerator(fn) {
^^^^^^
SyntaxError: Unexpected token export
but it works well with import/export syntax.
package.json
{
"scripts": {
"dev": "nodemon --exec babel-node server/index.js",
}
"dependencies": {
"#babel/polyfill": "^7.2.5",
},
"devDependencies": {
"#babel/cli": "^7.2.3",
"#babel/core": "^7.2.2",
"#babel/node": "^7.2.2",
"#babel/preset-env": "^7.2.3",
}
}
.babelrc
{
"presets": [
"#babel/preset-env"
]
}
asyncToGenerator.js
function asyncGeneratorStep(...) { ... }
export default function _asyncToGenerator(fn) {
return function () {
var self = this,
args = arguments;
return new Promise(function (resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
But I think it probably goes wrong because of my babel setting.
BTW, when I use typeof, it throws the same error
**/node_modules/#babel/runtime/helpers/esm/typeof.js:3
export default function _typeof(obj) {
^^^^^^
SyntaxError: Unexpected token export
update 6/12, 2020:
structure:
src (vue app)
server (express app)
|---- src
|---- babel.config.js
|---- index.js
package.json
babel.config.js
In this project, I have two babel config, one is for the vue's app, and another is for the express. What I want is running these apps at the project's root path.
And in the beginning, my script about running express is
nodemon --exec babel-node server/index.js
It can run express, but it gets the wrong babel config(project/babel.config.js)
And the solution is just to point out the specific path which babel confg you want to use(project/server/babel.config.js). So the correct script to run the express is
nodemon --exec babel-node --config-file ./server/babel.config.js server/index.js",
answering your comment:
nodemon doesn't know about babelrc (and it shouldn't). And babel (AFAIK) doesn't allow you to select the babelrc file that you want to use.
I think that you should merge your babelrc files and set the env flag when running babel-node. Like this: babeljs.io/docs/en/6.26.3/babelrc#env-option
Another option would be to make a script that renames the babelrc file each time the app is reloaded, or something like that (I don't understand why you need 2 .babelrc files)
In an answer no longer visible (probably deleted by a moderator) I read that there are more .babelrc files in the project.
From babel docs it seems that the .babelrc needs to be in the same directory of the subpackage. I suggest you to read that doc, probably you can find the solution that better fits your requirements.
Sorry for the vague answer, but due to the lack of details in your question (server/index.js file content, directories structure, etc.) I can't do better.

How to configure .babelrc to support ES6 module imports and async/await?

Desired Behaviour
I am trying to import code from one file into another with:
lib.js
// generate unique id
export const guid = () => {
const s4 = () => {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
}
// get current date as ISO string
export const currentDateTimeISOString = () => {
var iso_string = new Date().toISOString();
return iso_string;
}
// convert boolean string to boolean
export const stringToBoolean = (val) => {
var a = {
'true': true,
'false': false
};
return a[val];
}
app_es6.js
import { guid, currentDateTimeISOString, stringToBoolean } from './src/js/lib';
Actual Behaviour
After build I get the error:
export const guid = () => {
^^^^^^
SyntaxError: Unexpected token export
What I've Tried
I've googled this error and come across various solutions.
The most up to date approach seems to be:
npm install babel-register babel-preset-env --save-dev
source
I currently have the following babel related dev dependencies in package.json:
"babel-cli": "^6.26.0",
"babel-core": "^6.26.3",
"babel-loader": "^7.1.4",
"babel-preset-env": "^1.7.0",
"babel-preset-stage-0": "^6.24.1",
And .babelrc is:
{
"presets": [
[
"env",
{
"targets":
{
"node": "current"
}
}
]
]
}
I recently changed .babelrc to the above in order to handle async/await usage, it used to be:
{
"presets": [
"env",
"stage-0"
]
}
My build script in package.json is:
"build-server-file": "babel app_es6.js --out-file app.js",
I'm concerned about implementing a solution that is outdated or breaks functionality with another part of the codebase (ie, if i revert to my previous version of .babelrc then async/await will throw errors). I've also read that stage-x is depreciated.
Question
What is the most up to date way to import/export modules in ES6 in a Node.js environment whilst still supporting the .babelrc requirements for async/await?
Notice that the SyntaxError is being thrown from within lib.js and not app.js --this is almost certainly the result of that file not being transformed.
The babel command you're using, babel app_es6.js --out-file app.js is processing app_es6.js; however, lib.js is untouched and that's likely why you still see ESM export syntax when require()ing the file.
I set up a minimal gist with updates to what I know about your current setup to make this work the way (I think) you intended: https://gist.github.com/knksmith57/a554defde2d3d7cf64c4f453565352a0
The trick is to process the entire source directory and not just your entrypoint file.
tl;dr:
process the entire source directory, not just the entrypoint
tell preset-env to use cjs (alias for commonjs) as the target module type
enable a plugin to transform async functions to generator functions (in babel 7.x, that's #babel/plugin-transform-async-to-generator)
look at that gist for a complete working example
If you run into trouble backporting my example to babel 6.x, let me know and I can make some time to follow up.
Hope this helps!
which version of node are you using?
you can easily update your node to version >= 10v to use official ES6 features support.
Actually, I had the same problem and I fix it by a babel plugin that name is transform-runtime, and my .babelrc the file became like below:
{
"presets": [
"es2015",
"es2016",
"es2017",
"react",
"env",
"stage-0"
],
"plugins": [
"transform-class-properties",
"transform-object-rest-spread",
[
"transform-runtime",
{
"helpers": true,
"polyfill": true,
"regenerator": true
}
]
],
"env": {
"development": {
"compact": false
}
}
}
For more information about this plugin read this link.
It looks like you're trying to run a node.js "server".
npm install --save-dev #babel/core #babel/cli #babel/preset-env #babel/node #babel/plugin-transform-async-to-generator
Using the #babel/ namespace will upgrade you from babel 6 to babel 7, the current latest version. The plugin does the async transformation
Setup a .babelrc or now with 7, especially if you're using node_modules with their own babel configurations, you can use a babel.config.js like this:
module.exports = {
presets: [ '#babel/preset-env'],
plugins: [
'#babel/plugin-transform-async-to-generator'
]
};
Update your package.json build scripts to something more like this:
"scripts": {
"build": "babel src --out-dir dist",
"start": "node dist/app_es6.js"
}
You want to compile your /lib/ folder into a /dist/ one. This is the most common pattern you'll see in the community.
As you are looking to make an es6 web-app, I would not recommend actually compiling everything to commonjs (cjs), as that will break webpack (via the babel-loader) from performing tree-shaking. It only works when you use import/exports and setting babel to cjs instead of the default ems will make everything require/module.exports.

Running tests located in a separate directory with mocha and ts-node?

I have source code and tests separated as follows:
`src/main/ts/hello.ts` //SOURCE FILES HERE
`src/test/ts/hello.spec.ts` //SPEC FILES HERE
The import statement in src/test/ts/hello.spec.ts looks like this:
import hello from 'hello';
The hello.ts source code looks like this:
export function hello() {
return 'Hello World!';
}
export default hello;
My tsconfig.json is setup such that the test files can import source modules without using relative paths like this:
{
"include": [
"src/main/ts/**/*.ts"
],
"exclude": [
"node_modules"
],
"compilerOptions": {
"experimentalDecorators": true,
"noImplicitAny": true,
"moduleResolution": "node",
"target": "es6",
"baseUrl": ".",
"paths": {
"*": [
"*", "src/main/ts/*"
]
}
}
}
This way the hello.spec.ts file can import hello using the statement import hello from 'hello';
I'm trying to run the tests with npm test configured to run mocha and tsnode like this (Based on this article):
"scripts": {
"test": "mocha -r ts-node/register src/test/ts"
},
However it does not look like ts-node is picking up on my tsconfig.json configuration as I get this error:
mocha -r ts-node/register src/test/ts
Error: Cannot find module 'hello'
at Function.Module._resolveFilename (module.js:336:15)
at Function.Module._load (module.js:286:25)
The module resolution that you set through paths in tsconfig.json is purely an compile-time thing. (See this ts-node issue report and this TypeScript issue report for details.) It does not affect how the code is emitted, which means that your test file is doing a require("hello"), which Node cannot resolve. The consequence of paths being a compile-time thing is that your module loader needs to be configured to also perform the same kind of resolution that you specify in tsconfig.json. If you were using RequireJS, for instance, you'd need to have a configuration for it that does the same thing paths in tsconfig.json does. You are using Node, however...
What you can do in Node is use tsconfig-paths, which will read the tsconfig.json, parse the paths setting and change the module resolution in Node so that it works.
Using your code, I modified hello.spec.ts to have at least one test for feedback:
import hello from "hello";
import "mocha";
it("q", () => {
if (hello() !== "Hello World!") {
throw new Error("unequal");
}
});
I installed tsconfig-paths and #types/mocha (so that import "mocha" does the right thing compilation-wise in the test file I show above) and invoked Mocha like this:
$ ./node_modules/.bin/mocha --compilers ts:ts-node/register -r tsconfig-paths/register 'src/test/ts/**/*.ts'
I got this output:
✓ q
1 passing (20ms)

Resources