0

Have been wrestling with this for a couple days now... Writing a TypeScript, React, Express, Node, Webpack and Babel project. First, I was getting the SyntaxError: Cannot use import statement outside a module error trying to use import syntax in my src/server/index.ts file and serving it with node src/server/index.ts in my start script.

but this works: nodemon src/server/index.ts as a start script.

Can anyone explain to me why nodemon works but node and ts-node do not?

tsconfig.json

{
  "ts-node": { /* EDIT: these ts-node options apparently are very important... */
    "compilerOptions": { /* if i remove these lines, even _with_ nodemon, I get the first error: */
      "module": "commonjs" /* `SyntaxError: Cannot use import statement outside a module` */
    }
  },
  "compilerOptions": {
    "target": "ES5",
    "module": "ESNext",
    "moduleResolution": "nodenext",
    "lib": [
      "DOM",
      "ESNext"
    ],
    "jsx": "react-jsx",
    "noEmit": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    "strict": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "allowJs": true
  },
  "include": [
    "src/client/**/*"
  ]
}

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');

const paths = {
  DIST: path.resolve(__dirname, 'dist'),
  SRC_ENTRY: path.resolve(__dirname, 'src', 'client', 'Index.tsx'),
  HTML_TEMPLATE: path.resolve(__dirname, 'src', 'client', 'index.html'),
};

module.exports = {
  mode: 'development',
  entry: paths.SRC_ENTRY,
  resolve: {
    extensions: ['.tsx', '.ts', '.js'],
  },
  output: {
    filename: 'bundle.js',
    path: paths.DIST,
  },
  module: {
    rules: [
      {
        test: /\.(ts|js)x?$/,
        exclude: /node_modules/,
        use:
        {
          loader: 'babel-loader',
        },
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({ template: paths.HTML_TEMPLATE }),
    new ForkTsCheckerWebpackPlugin(),
  ],
};

src/server/index.ts

import express, { Express } from 'express'; /* <-- this is the first import where the error is thrown */
import path from 'path';

export const app: Express = express();
/* ... */

Tried many different fixes including the outdated and popular "add "type": "module" to your package.json file, as well as changing around my "target", "moduleResolution", "module", "allowJS" and basically any other relevant property in my tsconfig.json...

I have provided my code above, but for the tl;dr, npm i --save-dev nodemon if you don't already have it globally installed and change your "start" script in your package.json to nodemon your/path/to/file.ts and you can use import syntax in your server file to serve.

To reiterate.. this problem was fixed by adding the ts-node options to my tsconfig.json and installing and implementing nodemon instead of node. I just don't understand why that fixes it and was hoping someone would help me out with that...

here is the outdated but classic SO solution with "type": "module" in package.json: ol' faithful as well as an "updated" solution from 2022 that also did not work for me: most recent

  • Its good to be curious and learn stuff. However, I think you are using some outdated material to learn. Webpack and especially express are not really used for greenfield projects. Perhaps look at the [vite react starter](https://vitejs.dev/guide/), that lets you focus on coding instead of wrestling with wepack and ts. In some cases (SPA), you also dont want to serve the react app from the backend. You can serve statics by simplier and more efficient means, i.e. nginx or blob storage. – The Fool Mar 20 '23 at 02:26

0 Answers0