Search code examples
node.jstypescriptwebpacktypeormisomorphic-javascript

Isomoprhic application, problem with TypeORM && TypeScript && Express && Webpack setup


I am trying to make isomorphic JavaScript application.

Both server side code and client side code are compiled by Webpack.

When i am trying to run compiled server side bundle which contains typeorm connection i am getting such an error

Error

(node:324) UnhandledPromiseRejectionWarning: /var/www/server/database/entity/WasteGroup.ts:1
(function (exports, require, module, __filename, __dirname) { import {Entity,PrimaryGeneratedColumn, OneToMany} from "typeorm";
                                                                     ^

SyntaxError: Unexpected token {
    at new Script (vm.js:74:7)
    at createScript (vm.js:246:10)
    at Object.runInThisContext (vm.js:298:10)
    at Module._compile (internal/modules/cjs/loader.js:657:28)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)
    at Module.require (internal/modules/cjs/loader.js:637:17)

Precompiled Server.ts

// Set up ======================================================================
// get all the tools we need
import express from 'express';
import http from 'http';
import logger from 'morgan';
import path from 'path';
import {createConnection} from "typeorm";
import apiVersion1 from './api/api1';
import  renderRouterMiddleware from '../iso-middleware/renderRoute';

const init = () => {
  createConnection().then(() => {

    require('dotenv').config();
    // Configuration ===============================================================
    const app = express();

    app.set('port', process.env.PORT || 3000);
    app.use(logger('short'));


    // Request Handlers
    const buildPath = path.join(__dirname, '../', 'build');

    app.use('/', express.static(buildPath));
    app.use('/api', apiVersion1);

    app.get('*', renderRouterMiddleware);

    // launch ======================================================================
    // Starts the Express server on port 3001 and logs that it has started
    http.createServer(app).listen(app.get('port'), () => {
      console.log(`Express server started at: http://localhost:${app.get('port')}/`); // eslint-disable-line no-console
    }, );

  })
}

export {
  init
}

Webpack related configs

Common

const path = require('path')
const webpack = require('webpack')

module.exports = {
    mode: 'development',
    devtool: '#source-map',

    output: {
      path: path.resolve(__dirname, '..','build'),
      publicPath: '/',
      filename: '[name].js'
    },
    module: {
      rules: [
        {
          test: /\.(jsx?|tsx?)$/,
          exclude: /node_modules/,
          use: {
            loader: 'babel-loader',
            options: {
              presets: ['@babel/preset-env', "@babel/preset-react"],

            }
          }
        },
        {
          test: /\.tsx?$/,
          loader: 'awesome-typescript-loader',
          exclude: /node_modules/
        },
        {
          enforce: "pre",
          test: /\.js$/,
          exclude: /node_modules/,
          loader: "eslint-loader",
          options: {
            emitWarning: true,
            failOnError: false,
            failOnWarning: false,
            fix:true
          }
        },
        {
          test: /\.css$/,
          use: ['style-loader', 'css-loader']
        },
        {
          test: /\.(png|svg|jpg|gif)$/,
          use: ['file-loader']
        }
      ]
    },
    resolve: {
      alias: {
        Shared: path.resolve(__dirname, '../shared')
      },
      extensions: ['.js','.ts', '.tsx', '.jsx', '.css', '.es6'],
    },
    plugins: [
      // new webpack.NoEmitOnErrorsPlugin()
    ],
  }

Server

const path = require('path')
const webpack = require('webpack')
const nodeExternals = require('webpack-node-externals')
const merge = require('webpack-merge')
const commonDevConfig = require('./webpack.dev.common.js')

const server = {
  target: 'node',
  node: {
    // Need this when working with express, otherwise the build fails
    __dirname: false,   // if you don't put this is, __dirname
    __filename: false,  // and __filename return blank or /
  },
  externals: [nodeExternals()],
  entry: {
    server: './server/server.ts',
  },
  output:{
    libraryTarget:'commonjs2'
  }
}

module.exports = merge(commonDevConfig, server)

WasteGroup.ts

    import {Entity,PrimaryGeneratedColumn, OneToMany} from "typeorm";
    import {WasteType} from './WasteType'
    @Entity()
    export class WasteGroup {
        @PrimaryGeneratedColumn()
        id: number;

        @OneToMany(type => WasteType, WasteType => WasteType.wasteGroup)
    types:WasteType;

}

ormconfig.json

{
    "type": "mysql",
    "host": "mysql",
    "port": 3306,
    "username": "nodedock",
    "password": "nodedock",
    "database": "wietlin_osada_db",
    "entities": ["server/database/entity/*.ts"],
    "migrations":[
      "server/database/migration/*.ts"
    ],
    "cli":{
      "migrationsDir":"server/database/migration",
      "entitiesDir": "server/database/entity"
    },
    "logging": true,
    "synchronize": false
  }

tsconfig.json

{
    "compilerOptions": {
        "module":"es6",
        "target":"es6",
        "moduleResolution":"node",
        "noImplicitAny": false,
        "esModuleInterop": true,
        "allowSyntheticDefaultImports":true,
        "removeComments": true,
        "preserveConstEnums": true,
        "experimentalDecorators":true,
        "emitDecoratorMetadata":true,
        // "noEmit":true,
        "jsx":"react",
        "sourceMap":true
    },
    "include": [
        "server/*"
    ],
    "exclude": [
        "node_modules",
        "**/*.spec.ts"
    ]
}

Im running application after webpack compilation with such npm script

"runNodeServerApp":"node -e 'require(\"./build/server.js\").init()'"

When im running application without TypeORM connection it does work without an error.

Is this issue with TypeORM or with my setup?

This is my project Tree if its going to help anyone.

├── build
│   ├── main.js
│   ├── main.js.map
│   ├── server.js
│   └── server.js.map
├── client
│   └── main.js
├── configs
│   ├── webpack.dev.client.js
│   ├── webpack.dev.common.js
│   └── webpack.dev.server.js
├── iso-middleware
│   └── renderRoute.js
├── ormconfig.json
├── package.json
├── package-lock.json
├── README.md
├── server
│   ├── api
│   │   └── api1.ts
│   ├── controller
│   │   └── WastePickupController.ts
│   ├── database
│   │   ├── entity
│   │   │   ├── WasteGroup.ts
│   │   │   ├── WastePickupEvent.ts
│   │   │   └── WasteType.ts
│   │   ├── migration
│   │   │   └── 1567256869205-Init.ts
│   │   └── repositories
│   │       └── TestRepository
│   │           └── index.js
│   └── server.ts
├── shared
│   ├── App.js
│   ├── components
│   │   ├── HTML.js
│   │   ├── icons
│   │   │   └── DumpTruck
│   │   │       └── index.js
│   │   ├── Main.js
│   │   ├── NotFound.js
│   │   ├── pages
│   │   │   └── Home
│   │   │       ├── components
│   │   │       │   ├── MainAppBar
│   │   │       │   │   └── index.js
│   │   │       │   ├── WasteScheduleCard
│   │   │       │   │   ├── DumpTruck
│   │   │       │   │   │   └── index.js
│   │   │       │   │   ├── index.js
│   │   │       │   │   └── WasteScheduleLegendOpener
│   │   │       │   │       └── index.js
│   │   │       │   ├── WeatherCard
│   │   │       │   │   └── index.js
│   │   │       │   └── WeatherWidget
│   │   │       │       └── index.js
│   │   │       └── index.js
│   │   └── Root.js
│   ├── renderFullApp.js
│   ├── routes.js
│   └── theme
│       └── index.js
└── tsconfig.json

Solution

  • The problem here is that you are referencing TypeScript files in your ormconfig.json and your node server can't handle TypeScript. You need to transpile them and reference the JavaScript files instead. See also this post.