Reuse parts of a nextjs app on the console using node command - node.js

I created a problem repository here:
https://github.com/tippfelher/so-nextjs-console
Problem description:
Using yarn next dev starts the development server which successfully outputs the model Example on the index-Page.
However, I cannot reuse the same model in a console application.
Running node .\console-app produces the error
import Example from "../models/Example";
^^^^^^
SyntaxError: Cannot use import statement outside a module
Attempts to solve this problem:
Add { "type": "module" } to root package.json and change next.config.js contents to
const config = {
reactStrictMode: true,
}
export default config;
triggers error:
Error: require() of ES Module <PATH>\demo\nextjs-node\app\.next\server\pages\_document.js from <PATH>\demo\nextjs-node\app\node_modules\next\dist\server\require.js not supported.
Edit
node --version
v16.13.1

You do not specify the node version but that error looks like the version of node requires enabling the then experimental es6 module support. In package.json add
"type": "module",
In new NodeJS builds looks like import statements are supported.
Since this is posted around Next, you may get into other compatibility issues, the yarn next dev invokes a cli which does a build and packages compatible modules to be executed by node.
If you are curious, checkout the cli build - https://github.com/vercel/next.js/tree/canary/packages/next/cli

Related

Import TypeScript module without NPM 'build' script

I need to import a package that has this configuration:
package.json
{
"name": "com.matheusdiasdesouzads.js.language-objects",
"main": "src/index.ts"
}
I'm importing this package from an outer package via:
my-outer-package/src/index.ts
import {Language} from 'com.matheusdiasdesouzads.js.language-objects';
Is it possible to keep my dependency configuration above as is and run ts-node src/index.ts? I've a project similiarly structured that runs fine in ts-node. Somehow my current project fails with this:
> ts-node src/index.ts # my-outer-package
< my-outer-package\node_modules\com.matheusdiasdesouzads.js.language-objects\src\index.ts:1
import Language, {Direction} from './language';
^^^^^^
SyntaxError: Cannot use import statement outside a module
Also note that running ts-node com.matheusdiasdesouzads.js.language-objects/src/index.ts doesn't produce this module-related error.
Here are the full sources:
language-objects
message-locator (imports language-objects from NPM registry)
I tried everything in this question: Ts-node : SyntaxError: Cannot use import statement outside a module
Set compilerOptions.module to "CommonJS".
Set compilerOptions.target to "ES2017".
Set compilerOptions.esModuleInterop to true.
Set type to "module" in package.json.
It is a bug probably on ts-node. When the dependency is on the file system, that is, when I replace:
"com.matheusdiasdesouzads.js.language-objects": "^1.1.0"
by:
"com.matheusdiasdesouzads.js.language-objects": "file:../language-objects-js"
My code compiles successfully (it creates a shortcut). I've commited an issue on their GitHub repository.

issues with imports on modularized apollo server

i have a fully working modularized apollo server on nextJS (based on this article https://www.apollographql.com/blog/modularizing-your-graphql-schema-code-d7f71d5ed5f2/ ) basically im doing an Array of my typedefs and merging the resolvers using the merge function from lodash... so far so good... this feed a function makeExecutableSchema and this schema is going to the server... and it works great...
the problem is im trying to move the server outside nextJS... and when i do try to create a new project and yarn init or npm init... install the dependencies, and try to copy paste all my schema files to the new npm init project ALL my imports are messed up, and i start getting all this errors like:
in nextJS i have (this one simply works in nextJS):
import { merge } from "lodash";
in the new node project it says merge couldnt be found in lodash...
or the module is commonJS and it cannot do named imports...
or if i do an import using require it says ReferenceError: require is not defined, i think this one should be due to node expecting to run this on a browser but i have no idea how to specify this wont run on a browser since it's simply a js file which intends to modularized the apollo schema...
i just dont understand why all the import sentences work just fine in Next but when im starting the apollo server in plain node every import is giving so many errors... i have fixed some by adding the extension at the end of the filename im importing (thing that was not necessary in nextJS) or by adding "/index" at the end of the package being imported...
Is there a way to make the imports behave like in Next??? but in a new nodeJS project?
Any help or orientation would be GREATLY appreciated
The answer was:
Use Babel, install with NPM or YARN
"#babel/core"
"#babel/node"
"#babel/preset-env"
add the .babelrc file to the root directory of the project:
{
"presets": ["#babel/preset-env"]
}
to run the main file use a script in package.json like:
"start": "nodemon --exec babel-node index.js"
and this will allow to execute modern JavaScript :D

VsCode clean Typescript project no auto import suggestions

When I create a new Node project using Typescript, VsCode auto import suggestions do not work at all.
Steps to reproduce:
Create a workspace directory.
Run npm init specifying main.ts as entrypoint file.
Import typescript cli npm i typescript
Create tsconfig.json .\node_modules\.bin\tsc --init
Create main.ts containing console.log('Running');
Transpile using .\node_modules\.bin\tsc -w
Run by clicking Debug in VsCode and using the default Nodejs launch config.
Import a library e.g. Rxjs Import typescript cli npm i rxjs
Result:
In main.ts attempting to use any Rxjs type Observable, BehaviourSubject, global operators from of sequenceEqual etc results in no import assistance whatsoever.
I've read the VsCode Typescript docs, there is no hint there of what is wrong. https://code.visualstudio.com/docs/languages/typescript
I've tried explicitly setting include and exclude directories in tsconfig.json which also has no effect.
Do I need to manually set some module resolution options in tsconfig or something.
I have no idea, I'm at a loss as to why this doesn't work.
UPDATE:
I managed to get VsCode auto import working by specifying
"typeRoots": [ "node_modules" ]
...in tsconfig.json
The results in a minor issue which is that tsc now reports the error
error TS2688: Cannot find type definition file for '.bin'.
It appears the tsc now tries to read the contents of node_modules.bin which is not helpful. I've tried setting
"exclude": [ "./node_modules/.bin"]
in tsconfig, but that has no effect.
Try giving main.js as your entrypoint not main.ts
Steps that I followed:
Create a workspace directory.
Run npm init specifying index.js as entry point file.
Install typescript cli: npm i typescript
Create tsconfig.json: .\node_modules\.bin\tsc --init
Create index.ts containing console.log('Running');
Transpile using .\node_modules\.bin\tsc -w
Run by clicking Debug in VSCode and using the default Nodejs launch config.
Install a library e.g. Rxjs: npm i rxjs
Now in index.ts file: import { observable, BehaviorSubject } from "rxjs";
I was able to get those IntelliSense(import assistance)

Get access to ES6 class in gulpfile.js [duplicate]

This question already has answers here:
Node.js - SyntaxError: Unexpected token import
(16 answers)
Closed 3 years ago.
I'm trying to get the hang of ES6 imports in Node.js and am trying to use the syntax provided in this example:
Cheatsheet Link
I'm looking through the support table, but I was not able to find what version supports the new import statements (I tried looking for the text import/require). I'm currently running Node.js 8.1.2 and also believe that since the cheatsheet is referring to .js files it should work with .js files.
As I run the code (taken from the cheatsheet's first example):
import { square, diag } from 'lib';
I get the error:
SyntaxError: Unexpected token import.
Reference to library I'm trying to import:
//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
What am I missing and how can I get node to recognize my import statement?
Node.js has included experimental support for ES6 support.
Read more about here: https://nodejs.org/docs/latest-v13.x/api/esm.html#esm_enabling.
TLDR;
Node.js >= v13
It's very simple in Node.js 13 and above. You need to either:
Save the file with .mjs extension, or
Add { "type": "module" } in the nearest package.json.
You only need to do one of the above to be able to use ECMAScript modules.
Node.js <= v12
If you are using Node.js version 9.6 - 12, save the file with ES6 modules with .mjs extension and run it like:
node --experimental-modules my-app.mjs
You can also use npm package called esm which allows you to use ES6 modules in Node.js. It needs no configuration. With esm you will be able to use export/import in your JavaScript files.
Run the following command on your terminal
yarn add esm
or
npm install esm
After that, you need to require this package when starting your server with node. For example if your node server runs index.js file, you would use the command
node -r esm index.js
You can also add it in your package.json file like this
{
"name": "My-app",
"version": "1.0.0",
"description": "Some Hack",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node -r esm index.js"
},
}
Then run this command from the terminal to start your node server
npm start
Check this link for more details.
I just wanted to use the import and export in JavaScript files.
Everyone says it's not possible. But, as of May 2018, it's possible to use above in plain Node.js, without any modules like Babel, etc.
Here is a simple way to do it.
Create the below files, run, and see the output for yourself.
Also don't forget to see Explanation below.
File myfile.mjs
function myFunc() {
console.log("Hello from myFunc")
}
export default myFunc;
File index.mjs
import myFunc from "./myfile.mjs" // Simply using "./myfile" may not work in all resolvers
myFunc();
Run
node --experimental-modules index.mjs
Output
(node:12020) ExperimentalWarning: The ESM module loader is experimental.
Hello from myFunc
Explanation:
Since it is experimental modules, .js files are named .mjs files
While running you will add --experimental-modules to the node index.mjs
While running with experimental modules in the output you will see: "(node:12020) ExperimentalWarning: The ESM module loader is experimental.
"
I have the current release of Node.js, so if I run node --version, it gives me "v10.3.0", though the LTE/stable/recommended version is 8.11.2 LTS.
Someday in the future, you could use .js instead of .mjs, as the features become stable instead of Experimental.
More on experimental features, see: https://nodejs.org/api/esm.html
Using Node.js v12.2.0, I can import all standard modules like this:
import * as Http from 'http'
import * as Fs from 'fs'
import * as Path from 'path'
import * as Readline from 'readline'
import * as Os from 'os'
Versus what I did before:
const
Http = require('http')
,Fs = require('fs')
,Path = require('path')
,Readline = require('readline')
,Os = require('os')
Any module that is an ECMAScript module can be imported without having to use an .mjs extension as long as it has this field in its package.json file:
"type": "module"
So make sure you put such a package.json file in the same folder as the module you're making.
And to import modules not updated with ECMAScript module support, you can do like this:
// Implement the old require function
import { createRequire } from 'module'
const require = createRequire(import.meta.url)
// Now you can require whatever
const
WebSocket = require('ws')
,Mime = require('mime-types')
,Chokidar = require('chokidar')
And of course, do not forget that this is needed to actually run a script using module imports (not needed after v13.2):
node --experimental-modules my-script-that-use-import.js
And that the parent folder needs this package.json file for that script to not complain about the import syntax:
{
"type": "module"
}
If the module you want to use has not been updated to support being imported using the import syntax then you have no other choice than using require (but with my solution above that is not a problem).
I also want to share this piece of code which implements the missing __filename and __dirname constants in modules:
import {fileURLToPath} from 'url'
import {dirname} from 'path'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
If you are using the modules system on the server side, you do not need to use Babel at all. To use modules in Node.js ensure that:
Use a version of node that supports the --experimental-modules flag
Your *.js files must then be renamed to *.mjs
That's it.
However and this is a big however, while your shinny pure ES6 code will run in an environment like Node.js (e.g., 9.5.0) you will still have the craziness of transpilling just to test. Also bear in mind that Ecma has stated that release cycles for JavaScript are going to be faster, with newer features delivered on a more regular basis. Whilst this will be no problems for single environments like Node.js, it's a slightly different proposition for browser environments. What is clear is that testing frameworks have a lot to do in catching up. You will still need to probably transpile for testing frameworks. I'd suggest using Jest.
Also be aware of bundling frameworks. You will be running into problems there.
Use:
"devDependencies": {
"#babel/core": "^7.2.0",
"#babel/preset-env": "^7.2.0",
"#babel/register": "^7.0.0"
}
File .babelrc
{
"presets": ["#babel/preset-env"]
}
Entry point for the Node.js application:
require("#babel/register")({})
// Import the rest of our application.
module.exports = require('./index.js')
See How To Enable ES6 Imports in Node.js
You may try esm.
Here is some introduction: esm
Using the .mjs extension (as suggested in the accepted answer) in order to enable ECMAScript modules works. However, with Node.js v12, you can also enable this feature globally in your package.json file.
The official documentation states:
import statements of .js and extensionless files are treated as ES modules if the nearest parent package.json contains "type": "module".
{
"type": "module",
"main": "./src/index.js"
}
(Of course you still have to provide the flag --experimental-modules when starting your application.)
Back to Jonathan002's original question about
"... what version supports the new ES6 import statements?"
based on the article by Dr. Axel Rauschmayer, there is a plan to have it supported by default (without the experimental command line flag) in Node.js 10.x LTS. According to node.js's release plan as it is on 3/29, 2018, it's likely to become available after Apr 2018, while LTS of it will begin on October 2018.
Solution
https://www.npmjs.com/package/babel-register
// This is to allow ES6 export syntax
// to be properly read and processed by node.js application
require('babel-register')({
presets: [
'env',
],
});
// After that, any line you add below that has typical ES6 export syntax
// will work just fine
const utils = require('../../utils.js');
const availableMixins = require('../../../src/lib/mixins/index.js');
Below is definition of file *mixins/index.js
export { default as FormValidationMixin } from './form-validation'; // eslint-disable-line import/prefer-default-export
That worked just fine inside my Node.js CLI application.
I don't know if this will work for your case, but I am running an Express.js server with this:
nodemon --inspect ./index.js --exec babel-node --presets es2015,stage-2
This gives me the ability to import and use spread operator even though I'm only using Node.js version 8.
You'll need to install babel-cli, babel-preset-es2015, and babel-preset-stage-2 to do what I'm doing.

How can I use an ES6 import in Node.js? [duplicate]

This question already has answers here:
Node.js - SyntaxError: Unexpected token import
(16 answers)
Closed 3 years ago.
I'm trying to get the hang of ES6 imports in Node.js and am trying to use the syntax provided in this example:
Cheatsheet Link
I'm looking through the support table, but I was not able to find what version supports the new import statements (I tried looking for the text import/require). I'm currently running Node.js 8.1.2 and also believe that since the cheatsheet is referring to .js files it should work with .js files.
As I run the code (taken from the cheatsheet's first example):
import { square, diag } from 'lib';
I get the error:
SyntaxError: Unexpected token import.
Reference to library I'm trying to import:
//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function diag(x, y) {
return sqrt(square(x) + square(y));
}
What am I missing and how can I get node to recognize my import statement?
Node.js has included experimental support for ES6 support.
Read more about here: https://nodejs.org/docs/latest-v13.x/api/esm.html#esm_enabling.
TLDR;
Node.js >= v13
It's very simple in Node.js 13 and above. You need to either:
Save the file with .mjs extension, or
Add { "type": "module" } in the nearest package.json.
You only need to do one of the above to be able to use ECMAScript modules.
Node.js <= v12
If you are using Node.js version 9.6 - 12, save the file with ES6 modules with .mjs extension and run it like:
node --experimental-modules my-app.mjs
You can also use npm package called esm which allows you to use ES6 modules in Node.js. It needs no configuration. With esm you will be able to use export/import in your JavaScript files.
Run the following command on your terminal
yarn add esm
or
npm install esm
After that, you need to require this package when starting your server with node. For example if your node server runs index.js file, you would use the command
node -r esm index.js
You can also add it in your package.json file like this
{
"name": "My-app",
"version": "1.0.0",
"description": "Some Hack",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node -r esm index.js"
},
}
Then run this command from the terminal to start your node server
npm start
Check this link for more details.
I just wanted to use the import and export in JavaScript files.
Everyone says it's not possible. But, as of May 2018, it's possible to use above in plain Node.js, without any modules like Babel, etc.
Here is a simple way to do it.
Create the below files, run, and see the output for yourself.
Also don't forget to see Explanation below.
File myfile.mjs
function myFunc() {
console.log("Hello from myFunc")
}
export default myFunc;
File index.mjs
import myFunc from "./myfile.mjs" // Simply using "./myfile" may not work in all resolvers
myFunc();
Run
node --experimental-modules index.mjs
Output
(node:12020) ExperimentalWarning: The ESM module loader is experimental.
Hello from myFunc
Explanation:
Since it is experimental modules, .js files are named .mjs files
While running you will add --experimental-modules to the node index.mjs
While running with experimental modules in the output you will see: "(node:12020) ExperimentalWarning: The ESM module loader is experimental.
"
I have the current release of Node.js, so if I run node --version, it gives me "v10.3.0", though the LTE/stable/recommended version is 8.11.2 LTS.
Someday in the future, you could use .js instead of .mjs, as the features become stable instead of Experimental.
More on experimental features, see: https://nodejs.org/api/esm.html
Using Node.js v12.2.0, I can import all standard modules like this:
import * as Http from 'http'
import * as Fs from 'fs'
import * as Path from 'path'
import * as Readline from 'readline'
import * as Os from 'os'
Versus what I did before:
const
Http = require('http')
,Fs = require('fs')
,Path = require('path')
,Readline = require('readline')
,Os = require('os')
Any module that is an ECMAScript module can be imported without having to use an .mjs extension as long as it has this field in its package.json file:
"type": "module"
So make sure you put such a package.json file in the same folder as the module you're making.
And to import modules not updated with ECMAScript module support, you can do like this:
// Implement the old require function
import { createRequire } from 'module'
const require = createRequire(import.meta.url)
// Now you can require whatever
const
WebSocket = require('ws')
,Mime = require('mime-types')
,Chokidar = require('chokidar')
And of course, do not forget that this is needed to actually run a script using module imports (not needed after v13.2):
node --experimental-modules my-script-that-use-import.js
And that the parent folder needs this package.json file for that script to not complain about the import syntax:
{
"type": "module"
}
If the module you want to use has not been updated to support being imported using the import syntax then you have no other choice than using require (but with my solution above that is not a problem).
I also want to share this piece of code which implements the missing __filename and __dirname constants in modules:
import {fileURLToPath} from 'url'
import {dirname} from 'path'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
If you are using the modules system on the server side, you do not need to use Babel at all. To use modules in Node.js ensure that:
Use a version of node that supports the --experimental-modules flag
Your *.js files must then be renamed to *.mjs
That's it.
However and this is a big however, while your shinny pure ES6 code will run in an environment like Node.js (e.g., 9.5.0) you will still have the craziness of transpilling just to test. Also bear in mind that Ecma has stated that release cycles for JavaScript are going to be faster, with newer features delivered on a more regular basis. Whilst this will be no problems for single environments like Node.js, it's a slightly different proposition for browser environments. What is clear is that testing frameworks have a lot to do in catching up. You will still need to probably transpile for testing frameworks. I'd suggest using Jest.
Also be aware of bundling frameworks. You will be running into problems there.
Use:
"devDependencies": {
"#babel/core": "^7.2.0",
"#babel/preset-env": "^7.2.0",
"#babel/register": "^7.0.0"
}
File .babelrc
{
"presets": ["#babel/preset-env"]
}
Entry point for the Node.js application:
require("#babel/register")({})
// Import the rest of our application.
module.exports = require('./index.js')
See How To Enable ES6 Imports in Node.js
You may try esm.
Here is some introduction: esm
Using the .mjs extension (as suggested in the accepted answer) in order to enable ECMAScript modules works. However, with Node.js v12, you can also enable this feature globally in your package.json file.
The official documentation states:
import statements of .js and extensionless files are treated as ES modules if the nearest parent package.json contains "type": "module".
{
"type": "module",
"main": "./src/index.js"
}
(Of course you still have to provide the flag --experimental-modules when starting your application.)
Back to Jonathan002's original question about
"... what version supports the new ES6 import statements?"
based on the article by Dr. Axel Rauschmayer, there is a plan to have it supported by default (without the experimental command line flag) in Node.js 10.x LTS. According to node.js's release plan as it is on 3/29, 2018, it's likely to become available after Apr 2018, while LTS of it will begin on October 2018.
Solution
https://www.npmjs.com/package/babel-register
// This is to allow ES6 export syntax
// to be properly read and processed by node.js application
require('babel-register')({
presets: [
'env',
],
});
// After that, any line you add below that has typical ES6 export syntax
// will work just fine
const utils = require('../../utils.js');
const availableMixins = require('../../../src/lib/mixins/index.js');
Below is definition of file *mixins/index.js
export { default as FormValidationMixin } from './form-validation'; // eslint-disable-line import/prefer-default-export
That worked just fine inside my Node.js CLI application.
I don't know if this will work for your case, but I am running an Express.js server with this:
nodemon --inspect ./index.js --exec babel-node --presets es2015,stage-2
This gives me the ability to import and use spread operator even though I'm only using Node.js version 8.
You'll need to install babel-cli, babel-preset-es2015, and babel-preset-stage-2 to do what I'm doing.

Resources