0

I am using socket.IO running in Express to distribute data among clients. To gain that data I need to use a function from another file. Now if I understand it correctly Node + Express doesn't natively support import / export key words, which I am using in the client (React) side of the app. Because of that I have used "require" inside the server file:

server.js

const initialStateFunctions  = require("../components/functions/InitialStateFunctions");
const playerStates = initialStateFunctions.getInitialPlayerStates();

InitialStateFunctions.js

import {shuffleArray} from "./CardManipulationFuntions";
import {ARTIFACTS, CARD_STATE, CARD_TYPE, GUARDIANS, ITEMS} from "../../data/cards";
import {GLOBAL_VARS} from "../../App";
import {LOCATION_LEVEL, LOCATION_STATE, LOCATIONS} from "../../data/locations";

/* INITIAL PLAYER STATE */
export function getInitialPlayerStates() {

However now Express doesn't load because of this error:

> lore_hunters@0.1.0 start C:\Projects\lore_hunters
> node src/server/server.js

C:\Projects\lore_hunters\src\components\functions\InitialStateFunctions.js:1
import {shuffleArray} from "./CardManipulationFuntions";
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at wrapSafe (internal/modules/cjs/loader.js:1063:16)
    at Module._compile (internal/modules/cjs/loader.js:1111:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1167:10)
    at Module.load (internal/modules/cjs/loader.js:996:32)
    at Function.Module._load (internal/modules/cjs/loader.js:896:14)
    at Module.require (internal/modules/cjs/loader.js:1036:19)
    at require (internal/modules/cjs/helpers.js:72:18)
    at Object.<anonymous> (C:\Projects\lore_hunters\src\server\server.js:11:32)
    at Module._compile (internal/modules/cjs/loader.js:1147:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1167:10)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! lore_hunters@0.1.0 start: `node src/server/server.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the lore_hunters@0.1.0 start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

I would like to retain using import / export modules in InitialStatesFunction - how then should I import the getInitialPlayerState function into the server.js application? Do I need to somehow turn server.js to a module? (" Cannot use import statement outside a module")

EDIT: I understand that Node doesn't natively use import and the require is to be used. The problem is that the loaded module than returned the error I have listed in my question.

EDIT2: When using "type": "module" option for the newer version of Node, I can rewrite the server.js file to use imports instead of requires:

import express from "express";
import http from "http"
import socketIO from "socket.io"
import path from "path"
import {getInitialPlayerStates} from "../components/functions/InitialStateFunctions";

const port = process.env.PORT || 4001;
const app = express();
// server instance
const server = http.createServer(app);

const playerStates = getInitialPlayerStates();

However this thows following error:

(node:12816) ExperimentalWarning: The ESM module loader is experimental.
internal/modules/esm/resolve.js:61
  let url = moduleWrapResolve(specifier, parentURL);
            ^

Error: Cannot find module C:\Projects\lore_hunters\src\components\functions\InitialStateFunctions imported from C:\Projects\lore_hunters\src\server\server.js
    at Loader.defaultResolve [as _resolve] (internal/modules/esm/resolve.js:61:13)
    at Loader.resolve (internal/modules/esm/loader.js:85:40)
    at Loader.getModuleJob (internal/modules/esm/loader.js:191:28)
    at ModuleWrap.<anonymous> (internal/modules/esm/module_job.js:42:40)
    at link (internal/modules/esm/module_job.js:41:36) {
  code: 'ERR_MODULE_NOT_FOUND'
}

The path shown in the output seemes to be correct. The folder structure follows:

project file structure

EDIT: it seems that imports have to have file extension specified (https://medium.com/@nodejs/announcing-core-node-js-support-for-ecmascript-modules-c5d6dc29b663) - that was easy to fix, however then the server has problem with JSX:

        effectsText: <Coin/>,
                     ^
SyntaxError: Unexpected token '<'
Faire
  • 706
  • 1
  • 9
  • 31
  • You need webpack configuration that will transpile your code into simple javascript. And then you can able to use import in your code base. – Qubaish Bhatti Mar 23 '20 at 09:15
  • 1
    Have a look: https://www.freecodecamp.org/news/how-to-enable-es6-and-beyond-syntax-with-node-and-express-68d3e11fe1ab/ – Qubaish Bhatti Mar 23 '20 at 09:18
  • 1
    Does this answer your question? [Node.js - SyntaxError: Unexpected token import](https://stackoverflow.com/questions/39436322/node-js-syntaxerror-unexpected-token-import) –  Mar 23 '20 at 09:28
  • @Qubaish Bhatti: thanks for you reference, it is an interesting article - a bit too advanced for me at this point though. – Faire Mar 23 '20 at 09:46
  • @ChrisG: I have seen that question beforehand, but the solution still left me with another error I have described in an answer below. – Faire Mar 23 '20 at 09:47
  • That seems to be a path issue; can you put the folder structure and actual import code in the question? –  Mar 23 '20 at 10:08
  • @ChrisG: I have added the information to the original question. – Faire Mar 23 '20 at 10:55
  • There shouldn't be any JSX in server-side code. If you have shared files with JSX, you need to reorganize them so all JSX is in client-only files. –  Mar 26 '20 at 09:28
  • I know now... I had to refactor a lot of the code but in the end it worked out well. Code for server and front-end have to be quite strictly separated file-wise, because even in ES module mode server still has problem with some imports that work well in React. – Faire Mar 26 '20 at 14:28

1 Answers1

1

Add "type": "module" to package.json in server project if you need to use es6 modules in node. with this, all .js and .mjs files are interpreted as ES modules. You can interpret individual files as CommonJS by using the .cjs extension.

EDIT: beware that it is not possible to mix imports with require - if the file is recognized as a module, all requires must be changed to imports. Also file extension must be specified and __dirname cannot be used - see https://medium.com/@nodejs/announcing-core-node-js-support-for-ecmascript-modules-c5d6dc29b663.

Faire
  • 706
  • 1
  • 9
  • 31
SFernando
  • 1,074
  • 10
  • 35
  • I think this is the right way - I had to rewrite the "require" keywords to "import", though. Still there is one unresolved error: Error: Cannot find module C:\Projects\lore_hunters\src\components\functions\InitialStateFunctions imported from C:\Projects\lore_hunters\src\server\server.js code: 'ERR_MODULE_NOT_FOUND' Why is that? The paths seem to be correct. – Faire Mar 23 '20 at 09:30
  • try to add experimental-modules as well in your script 'node --experimental-modules src/server/server.js' – SFernando Mar 23 '20 at 09:36
  • I am afraid that was a bit too consice for me, could you explain it in a bit more details? Also my npm version is v13.11.0, doesn't that mean that the functionality is no longer experimental? – Faire Mar 23 '20 at 09:45