SyntaxError: Cannot use import statement outside a module

I have the following docker-compose file:

version: '3.9'

services:
  database:
    image: mongo:3.6
    restart: on-failure
    ports:
      - 27017:27017
    environment:
      MONGO_INITDB_ROOT_USERNAME: admin
      MONGO_INITDB_ROOT_PASSWORD: admin
    volumes:
      - mongo_data:/data/db

  server:
    restart: on-failure
    image: parseplatform/parse-server:5.2.3
    ports:
      - 1337:1337
      - 9229:9229
    environment:
      - PARSE_SERVER_APPLICATION_ID=$SERVER_APPLICATION_ID
      - PARSE_SERVER_APPLICATION_NAME=$SERVER_APPLICATION_NAME
      - PARSE_SERVER_MASTER_KEY=$SERVER_MASTER_KEY
      - PARSE_SERVER_DATABASE_URI=mongodb://admin:admin@mongo/parse_server?authSource=admin
      - PARSE_SERVER_MOUNT_GRAPHQL=true
      - PARSE_SERVER_CLOUD=/parse-server/cloud/main.js
      - PARSE_SERVER_GRAPH_QLSCHEMA=/parse-server/cloud/schema_2.graphql
    links:
      - database:mongo
    depends_on:
      - database
    entrypoint: "node --inspect=0.0.0.0:9229 /parse-server/bin/parse-server"
    volumes:
      - parse_server_cloud:/parse-server/cloud
      - ./parse-server/package.json:/parse-server/package.json
volumes:
  mongo_data:
  parse_server_cloud:
    driver: local
    driver_opts:
      type: none
      device: ./parse-server/cloud
      o: bind

Project structure:


 - docker
     - parse-server
         - cloud
              main.js
              generate_classes.js

My main.js:


import {createClassIfNotExists} from "./generate_classes";

createClassIfNotExists('SomeClassV10').then(r => console.log(r));

My generate_classes.js:

export const createClassIfNotExists = async (name) => {
    const schema = new Parse.Schema(name);
    schema.get().then(() => {
        console.log('Class exists!');
    }).catch(async (error) => {
        schema.addString('name', {required: true});
        schema.addNumber('age', {required: true});
        await schema.save();
        console.log('Class ' + name + ' was created');
    });
}

When I am trying to run this via:

docker-compose up -d server

I am getting the following error inside my container:

import {createClassIfNotExists} from "./generate_classes";
^^^^^^

SyntaxError: Cannot use import statement outside a module
 at compileFunction (<anonymous>)
 at Object.compileFunction (node:vm:352:18)
 at wrapSafe (node:internal/modules/cjs/loader:1033:15)
 at Module._compile (node:internal/modules/cjs/loader:1069:27)
 at Object.Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
 at Module.load (node:internal/modules/cjs/loader:981:32)
 at Function.Module._load (node:internal/modules/cjs/loader:822:12)
 at Module.require (node:internal/modules/cjs/loader:1005:19)
 at require (node:internal/modules/cjs/helpers:102:18)
 at new ParseServer (/parse-server/lib/ParseServer.js:158:9)

Is this a bug or I am missing something?

Usually such an error indicates that you use ES6 code in a common js file. So if you want to keep using “import” what you need to do is include type: "module" in your package-json and also probably rename your file from .js to .mjs.

Alternatively you can change your “import” to “require” i.e. import {createClassIfNotExists} from "./generate_classes" should become const {createGalssIfNotExists} = require("./generate_classes");

Finally you can also dynamically import your function like this.

async function dynamicImport() {
   const function = await import {createClassIfNotExists} from "./generate_classes";
   return function;
}

const createClassIfNotExists = dynamicImport();

I am not sure about the correctness of step 3 as I’m doing it from memory. You can research about it. I would personally go with method number 2 as parse server is built with commonJS.

Unfortunately is not going to be so easy in my case I guess… :frowning:

---------------------------- Option 1 ----------------------------
Regarding your first option, I’ve tried to do it but I couldn’t. I don’t have (or I don’t know how to get access to) package.json.

The following error is what I get when trying to add the package.json to the volume in docker via:

      - ./parse-server/package.json:/parse-server/package.json

And this is the error that I get when running docker afterwords.

    ERROR: for 043a399a1ce9_docker_server_1 Cannot start service server: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error mounting "PRJ_PATH/docker/parse-server/package.json" to rootfs at "/parse-server/package.json": mount PRJ_PATH/docker/parse-server/package.json:/parse-server/package.json (via /proc/self/fd/6), flags: 0x5000: not a directory: unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type

    ERROR: for server Cannot start service server: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error mounting "PRJ_PATH/docker/parse-server/package.json" to rootfs at "/parse-server/package.json": mount PRJ_PATH/docker/parse-server/package.json:/parse-server/package.json (via /proc/self/fd/6), flags: 0x5000: not a directory: unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type ERROR: Encountered errors while bringing up the project.

Also, I’ve found that the package.json is also read-only and I can not edit it in any way that I know of. Or am I missing something?

---------------------------- Option 2 ----------------------------
I’ve try to use this:

const {createClassIfNotExists} = require("./generate_classes");

createClassIfNotExists('SomeClassV10').then(r => console.log(r));

and my generate_classes looks like this:

export const createClassIfNotExists = async (name) => {
    const schema = new Parse.Schema(name);
    schema.get().then(() => {
        console.log('Class exists!');
    }).catch(async (error) => {
        schema.addString('name', {required: true});
        schema.addNumber('age', {required: true});
        await schema.save();
        console.log('Class ' + name + ' was created');
    });
}

I’ve also try to change it like this:

async function createClassIfNotExists(name) {
    const schema = new Parse.Schema(name);
    schema.get().then(() => {
        console.log('Class exists!');
    }).catch(async (error) => {
        schema.addString('name', {required: true});
        schema.addNumber('age', {required: true});
        await schema.save();
        console.log('Class ' + name + ' was created');
    });
}

In both cases I am getting the following error:

SyntaxError: Unexpected token 'export'

---------------------------- Option 3 ----------------------------
And the last option which you suggest I am getting errors from the function itself like this:

 const function = await import {createClassIfNotExists} from "./generate_classes";
       ^^^^^^^^
 SyntaxError: Unexpected token 'function'

Am I missing something or I did my docker environment wrong?

Your function is exported according to ES6 format. Try changing it to CJ as well like below. Notice I removed the word “export” and added the last line.

const createClassIfNotExists = async (name) => {
    const schema = new Parse.Schema(name);
    schema.get().then(() => {
        console.log('Class exists!');
    }).catch(async (error) => {
        schema.addString('name', {required: true});
        schema.addNumber('age', {required: true});
        await schema.save();
        console.log('Class ' + name + ' was created');
    });
}

module.exports = { createClassIfNotExists };

Then import it like this

const {createClassIfNotExists} = require("./generate_classes");

And hopefully it will work

As for the method #3 I accidentally used the reserved word “function”. You can try like this

async function dynamicImport() {
   const abc = await import {createClassIfNotExists} from "./generate_classes";
   return abc;
}

const createClassIfNotExists = dynamicImport();

But method #2 is better.

Thank you very much for your help, now everything works fine with both options :smiley:
I would vote for both of them with the solution checkmark but I cant :sweat_smile: