I have a lot of code in my currently project(my-project) that will be needed in a new one. This code has been written in ES6 and transpiled after with babel.
I've created a module called "my-module" with this shared code and linked it to "my-project" using npm link
The problem is that when I start the project, the code from "my-module" is not beening tranpiled and throws an error right at the import statement.
The code inside my-module will be edited a lot. How to make it works?
package.json
"scripts": {
"start": "nodemon bin/dev",
"clean": "rm -rf dist",
"build": "yarn run clean && mkdir dist && babel src -s -d dist",
"production": "yarn run build && node bin/production"
},
.babelrc
{
"presets": ["es2015", "stage-2"]
}
The linked project will not find your .babelrc file. You have a few options:
Place a .babelrc in my-project or a higher level directory. This will require the babel plugins to be installed in that module though (or globally)
If you're using a build tool (i.e. webpack, browserify, etc.) you can declare the babel config there.
This comment helped me out: https://github.com/babel/gulp-babel/issues/93#issuecomment-249172581
My project uses browserify, so declaring the same plugins in the build script that are in .babelrc and invoking require.resolve caused the npm linked project to be transpiled correctly.
return browserify.transform('babelify', {
sourceMaps: true,
global:true,
plugins: ['babel-preset-es2015'].map(require.resolve)
})
Related
I'm trying to import express into my project using ES6 syntax, but it keeps giving me the error:
import express from "express";
SyntaxError: Unexpected identifier
I have done a bit of research and found where people were saying to add:
"type":"module"
to my package.json file, which I have done:
...
"description": "Shopping list to learn the MERN stack",
"type": "module",
"main": "server.js",
"scripts": {
"start": "node server.js",
"server": "nodemon server.js"
},
...
But I'm still getting the same issue. I would prefer to use the import ES6 syntax rather than this syntax.
const express = require('express')
Solution:
For me the best, easiest and most compatible way to resolve (dated to September 2019) was to:
npm install esm
ensure that the script is run by node with the -r esm option.
Simple as that.
The Node way:
(according to the ECMAScript Modules Documentation)
Other than the "type": "module" property into package.json NodeJS requires the scripts to be run via node --experimental-modules <your_script.js>.
Code into either .mjs or .js extension files will be treated with the support for new ES6. Renaming that I find pretty inconvenient.
Note: "type": "module" is particularly important for supporting .js files. Read the linked documentation.
The solution provided by NodeJS with the --experimental-modules flag didn't work for me in all cases. 🤷♂️
Adding the esm packages is more maintainable; and reliable. And can be easily/quickly removed once the ESM support won't be experimental anymore.
Offtopic tip:
If you want to run tests on your ES6 import/export code, I suggest to rely on a solid/flexible framework, like Mocha.
You can follow this instructions to run Mocha tests supporting ES6.
Trying with Jest I wasn't able to run test successfully. Apparently they don't want to directly support the experimental ES6 and suggest to transpile the code (thing that I hate).
References:
https://alxgbsn.co.uk/2019/02/22/testing-native-es-modules-mocha-esm/
https://timonweb.com/tutorials/how-to-enable-ecmascript-6-imports-in-nodejs/
https://nodejs.org/api/esm.html#esm_ecmascript_modules
If you try to run Node js app with ES6 syntax, you will encounter this kind of error
SyntaxError: Cannot use import statement outside a module
let's fix that
install three main packages
npm install --save-dev #babel/core #babel/preset-env #babel/node
npm install --save-dev nodemon
add .babelrc file with this
{ "presets": ["#babel/preset-env"] }
and this in package.json
"start": "nodemon --exec babel-node app.js"
Ok, so, after doing even more research on the ES6 way, this is what worked for me. It's a combination of an answer above and the following:
package.json
node --experimental-modules server.mjs
server.mjs
import dotenv from 'dotenv'
dotenv.config()
const db = process.env.MONGO_URI
I've created a nodejs boilerplate supporting es6 module.
https://github.com/jasonjin220/es6-express-rest-api-boilerplate
You need Babel transpiler to do this, as Node.js doesn't support es6.
First add these packages to your project :
npm install --save-dev babel-cli babel-preset-es2015 rimraf
Then, create a .babelrc file , this is used by Babel transpiler to know some information during transpilation.
touch .babelrc
Then, add this line to .babelrc :
{
"presets": ["es2015"]
}
This tells your Babel to use es6 presets as per 2015 standard.
Then, modify the package.json and tell it to use transpiler.
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "rimraf dist/ && babel ./ --out-dir dist/ --ignore ./node_modules,./.babelrc,./package.json,./npm-debug.log --copy-files",
"start": "npm run build && node dist/index.js"
},
You have to add the following to script section, this line tells when you run npm run start , the transpiler will first convert the es6 syntax to minmal JavaScript one, later that is used.
Check your dependencies :
"dependencies": {
"express": "^4.15.2",
"morgan": "^1.8.1",
"rimraf": "^2.6.1"
}
And Dev dependencies :
"devDependencies": {
"babel-cli": "^6.24.0",
"babel-preset-es2015": "^6.24.0"
}
This should work, comment if there is any issue.
You need to use Babel,
npm install --save-dev #babel/plugin-proposal-class-properties
then for usage create a .babelrc file if you don't have it, with options:
{"plugins": ["#babel/plugin-proposal-class-properties"]}
then ad devDependencies in package.json
"#babel/plugin-proposal-class-properties": "^7.5.5",
that should do the job.
While i'am trying to run "npm run build":
"start": "npm run build && node ./dist/index.js",
"dev": "nodemon --exec babel-node ./index.js",
"debug": "node --inspect-brk ./dist/index.js",
"clean": "rm -rf build && mkdir build",
"build": "npm run clean && npm run build-babel ",
"build-babel": "babel src --out-dir ./dist --source-maps --ignore 'node_modules/**/*.js'",
"build-client": "cd client && npm install && npm run build"
I am getting error:
{ SyntaxError: /home/marcin/Pobrane/recipeapp-style/src/client/node_modules/#babel/helper-plugin-utils/src/index.js: Unexpected token, expected "," (93:5)
91 | version,
92 | range,
> 93 | }: any),
| ^
94 | );
95 | }
I've had nodejs project and nested project created in reactjs (CRA) in my project in "client" folder.
I've tried this - https://github.com/babel/babel/issues/8944
But it doesn't help me.
My folder structure looks like this
build
dist
node_modules
src
client (here is create-react-app)
....many less significant folders
.babelrc
index.js
package-lock.json
package.json
If you think this is something else, please let me know.
I would like to build my project an hosted it on heroku, but i have to build it using babel (because ES6).
I had the same problem and I realised that in my client module I have package.json file that is totally making babel freak out and lose its configuration from .babelrc. Adding .babelrc to that package won't help.
I would recommend you to remove package.json file from client app. Also remove node_modules from client too as babel will accidentially try to compile them too.
Of course remember to set correct presets in .babelrc.
Mine are:
{
"presets": [
"#babel/preset-env",
"#babel/preset-react", // JSX
"#babel/preset-flow" // static typing
]
}
I have no idea why is it happening this way.
Cheers.
I am creating a simple project-generator tool and I am using es6 imports in my main index.js file. I have a babel-node installed with a .babelrc at the root of my project.
To install the tool globally I have this in my package.json:
"bin": {
"generate": "./node_modules/.bin/babel-node ./index.js"
},
When I run npm link or npm install -g at the root of my project, I get the error:
ENOENT: no such file or directory, chmod '/usr/local/lib/node_modules/node-project-generator/node_modules/.bin/babel-node ./index.js'
I have also tried:
"bin": {
"generate": "babel-node ./index.js"
},
and
"bin": {
"generate": "npx babel-node ./index.js"
},
This tool is working just fine in the context of my project. So how do I add es6 support to install it globally?
Have you added babel-node as a dependency to your package?
Anyway, the more proper way of doing it is to compile your program with babel into some dist directory in advance so that it can be run without any additional pre-processor.
"bin": {
"generate": "./dist/index.js"
}
Less problematic and faster command execution.
I am trying to setup WebStorm with Flow typing for a Node.js project.
I have it all working fine with NPM scripts but would like to integrate with the IDE.
Here is the scripts portion of my package.json:
"scripts": {
"dev":
"watch --wait=1 'flow-remove-types src/ -d lib/ --all --pretty' ./src/ & nodemon ./lib/server.js",
"start": "npm run flow:build && node ./lib/",
"lint": "eslint src/**",
"test": "npm run flow:build && jest lib",
"coverage": "jest --collectCoverageFrom=src/**.js --coverage src",
"flow": "flow",
"flow:check": "flow check ./src/",
"flow:build": "flow-remove-types ./src/ -d ./lib/ --all --pretty",
"flow:deps": "flow-typed install",
"flow:watch": "flow-watch"
},
Now if I modify the run configuration for a test and:
change the src directory to lib
specify a before launch, run NPM script 'flow:build'
then I can run that configuration.
I still have two problems.
Debugging will not stop on a breakpoint
If I hit the arrow in the source code gutter to run the test, it creates a new config which runs against the flow source and fails
Does anyone have Node.js and flow working well together in WebStorm?
You can use --sourcemaps and -pretty flags:
flow-remove-types --pretty --sourcemaps --out-dir out/ in/
The -m or --sourcemaps flag adds sourcemaps files to your /out folder
The -p or --pretty flag removes the empty spaces in the files of your /out folder
flow-remove-types does not generate sourcemaps, so there is absolutely no way for debugger to map the generated file in lib to original files in src. You have to add breakpoints to the generated files located in lib folder if you like to debug your tests
no way - configuration is generated for the file you hit the arrow in. If you like to run individual tests from gutter, hit the arrow in generated file, not in the source one
You can use Babel flow preset instead of flow-remove-types:
npm install --save-dev babel-cli babel-preset-env babel-preset-flow
create a .babelrc file in your project root dir:
{
"presets": ["flow"]
}
And that's all you have to do - no precompiling, etc., running from gutter/debugging for source files will work out of the box
When testing locally I was previously running:
"build-live": "nodemon --exec ./node_modules/.bin/ts-node -r dotenv/config -- ./index.ts"
I then figured my Procfile should be something like:
web: ./node_modules/.bin/ts-node -- ./index.ts
But it says module 'typescript' not found, even when it is in package.json. I read in a few places that ts-node is not the way to go to deploy to Heroku, so I am not sure what to do.
UPDATE: I think I am supposed to compile it, so I tried:
web: ./node_modules/.bin/tsc --module commonjs --allowJs --outDir build/ --sourceMap --target es6 index.ts && node build/index.js
This succeeds, however when actually running it, a bunch of the libs I'm using get "Cannot find module '...'".
Alternatively you can have the TypeScript compile as a postinstall hook and run node build/index.js as the only Procfile command:
Your package.json should contain a postinstall hint that gets executed after npm install and before the node process launches:
"scripts": {
"start": "node build/index.js",
"build": "tsc",
"postinstall": "npm run build"
}
You can then leave your Procfile as is:
web: npm start
This 'build on deploy' approach is documented by Heroku here.
The command you've given Heroku is to launch the web "process" by compiling index.ts and dependencies and starting node at index.js. Depending on how things are timed, index.js might or might not exist at the time node starts.
You need to already have your sources compiled by the time you want to start your app. For example, web should just be web: node index.js or similar.
Each build process is different, so you need to figure that out for your own setup. But, suppose you have a classical setup where you push to git and then Heroku picks up that change and updates the app with the new slug. You could just compile things locally and include index.js and any other build output in the repository, for it to be available in the slug for Heroku to use.
A better approach is to use a build server which has an integration with Heroku. After you do the build there, configure it to send the build results to Heroku. Travis has a straighforward setup like this. This way you don't need to include build outputs in your repository, which is considered an anti-pattern.
On a sidenode, try using a tsconfig.json to keep the tsc configuration. It will save you from having to write such long command lines all over the place.
Fabian said that we could do something like:
"scripts": {
"start": "node build/index.js",
"build": "tsc",
"postinstall": "npm run build"
}
As of me writing this, I tested this and can state: postinstall is not required since build script is ran by Heroku. If you want to do it without build script, then you can use heroku-postbuild which will run after dependencies are installed there you run tsc to compile.
My problem was about missing Typescript npm modules. The Typescript compiler tsc was not found when deployed the app to Heroku.
The Heroku deploy process (rightly) does not install development dependencies, in my case the Typescript module was part of devDependencies and thus the tsc command was not running on the Heroku platform.
Solution 1
Add typescript to dependencies: npm i typescript -s
Solution 2
Open Heroku console:
Select console type:
Run the command npm i typescript && npm run tsc
Install typescript as a dev dependency (cf. https://www.typescriptlang.org/download). Once built, your app does not need typescript anymore!
npm install -D typescript
Then in your package.json:
{
"main": "index.js", // <- file will be generated at build time with `tsc`
"scripts": {
"build": "tsc",
"start": "node ."
"start:dev": "ts-node index.ts" // idem, install ts-node as a dev dependency
}
}
The key point here is "build": "tsc".
Why?
Heroku does install all dependencies during build and remove the dev dependencies before the app is deployed (source here).
Node.js deployments will automatically execute an app’s build script during build (since March 11. 2019 source here)
In package.json
"scripts": {
"tsc": "./node_modules/typescript/bin/tsc",
"postinstall": "npm run tsc"
},
Works for me for Heroku deployment.
Installing typescript npm install -D typescript and writing tsc in the build script "build": "tsc", does not work for me. Also, try to run npm i typescript && npm run tsc in the Heroku console which also does not work.
In my case, I remove some dependencies from "devDependencies" to "dependencies", so it goes like this:
"dependencies": {
// The other dependencies goes here, I don't touch them.
// But all TS dependencies I remove to here.
"ts-node": "^9.1.1",
"tsconfig-paths": "^3.9.0",
"typescript": "^4.2.3",
"ts-loader": "^8.0.18"
},