vercel / ncc

Compile a Node.js project into a single file. Supports TypeScript, binary addons, dynamic requires.
https://npmjs.com/@vercel/ncc
MIT License
9.1k stars 288 forks source link

Typeorm Decorators cause Module parse failed: Unexpected character '�' #776

Open sinamics opened 2 years ago

sinamics commented 2 years ago

Im trying to build a node typescript app, but it fails with the bellow output. Seems like it fails in typeorm decorator.

ERROR in ./index 1:0
Module parse failed: Unexpected character '' (1:0)
File was processed with these loaders:
 * ../../../../AppData/Roaming/npm/node_modules/@vercel/ncc/dist/ncc/loaders/shebang-loader.js
You may need an additional loader to handle the result of these loaders.
(Source code omitted for this binary file)
 @ ./node_modules/typeorm/decorator/Unique.js 3:14-33
 @ ./node_modules/typeorm/index.js 54:21-50
 @ ./src/entity/Camera.ts 13:18-36
 @ ./src/resolvers/CameraResolver.ts 30:17-44
 @ ./src/index.ts 40:25-62

running ncc as: ncc build -w src/index.ts -o ./build

styfle commented 2 years ago

Can you share the contents of src/index.ts and tsconfig.json?

sinamics commented 2 years ago

@styfle Sure, see bellow:

index.ts

import 'reflect-metadata';
import path from 'path';
import http from 'http';
import express from 'express';
import session from 'express-session';
import connectSqlite3 from 'connect-sqlite3';
import { ApolloServer } from 'apollo-server-express';
import { buildSchema } from 'type-graphql';
import compression from 'compression';
import dotv from 'dotenv';
import cors from 'cors';
import Log from './logger/winstonLogger';
import { PubSub } from 'apollo-server-express';
import { CameraResolver } from './resolvers/CameraResolver';
import ValidateLicenseKey from './license';
import { createTypeormConn } from './createTypeormCon';
import { getCoreTempinfo } from './logger/temperature';
import { getNetworkinfo } from './logger/network';
import { getCpuInfo } from './logger/cpu';

const pubsub = new PubSub();
dotv.config();
const SQLiteStore = connectSqlite3(session);

const server = async () => {
  createTypeormConn().then(() => {
    new ValidateLicenseKey().timer();
  });

  const app = express();
  app.use(cors());

  app.use(
    session({
      store: new SQLiteStore({
        db: 'database.db',
        dir: 'usr/local/database',
        concurrentDB: true,
      }),
      name: 'uavid',
      secret: process.env.ACCESS_TOKEN_SECRET || '',
      resave: false,
      saveUninitialized: false,
      cookie: {
        httpOnly: true,
        secure: process.env.NODE_ENV === 'production',
        maxAge: 1000 * 60 * 60 * 24 * 100, 
      },
    })
  );

  if (process.env.NODE_ENV === 'production') {
    console.log('Running Production Server');
    app.use(compression());
    app.use(express.static(path.join(__dirname, '../../frontend/build')));

    // Route all requests to index
    app.get('/*', function (_, res) {
      res.sendFile(path.join(__dirname, '../../frontend/build/index.html'), function (err) {
        if (err) {
          res.status(500).send(err);
        }
      });
    });
  }

  const apolloServer = new ApolloServer({
    schema: await buildSchema({
      resolvers: [CameraResolver],
      validate: false,
    }),
    subscriptions: {
      path: '/subscriptions',
    },
    context: ({ req, res }) => ({ req, res, pubsub }),
    playground: {
      settings: {
        'request.credentials': 'include',
      },
    },
  });
  apolloServer.applyMiddleware({ app, cors: false });
  const httpServer = http.createServer(app);

  apolloServer.installSubscriptionHandlers(httpServer);

  const port = process.env.SERVER_PORT || 4000;
  httpServer.listen(port, () => {
    Log.server(`started at http://localhost:${port}/graphql`);
  });
};

server();

tsconfig.json

{
  "compilerOptions": {
    "target": "es6",
    "allowJs": true,
    "module": "commonjs",
    "lib": [
      "dom",
      "es6",
      "es2017",
      "esnext.asynciterable"
    ],
    "sourceMap": true,
    "outDir": "./dist",
    "moduleResolution": "node",
    "removeComments": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "noImplicitThis": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "resolveJsonModule": true,
    "baseUrl": "."
  },
  "include": [
    "src/**/*.tsx",
    "src/**/*.ts",
    "src/**/*.js",
  ]
}
orefalo commented 2 years ago

Hi, love this idea of this project.

Same issue with mikro-orm and type-graphql annotations

rethab commented 2 years ago

Having similar issues with decorators. The change seems to be between 0.30.0 and 0.31.0. Unfortunately, I didn't have enough time to really isolate it into a reproducible example, but here's roughly what I have:

class Foo {
  @test('value') readonly att: string = '';
}

The decorator test just assigns the passed value to the attribute.

With 0.30.0 the generated code looks something like this:

class Foo {
  constructor() {
    this.att = '';
  }
}

but with 0.31.0 it changes to:

class Foo {
  att = '';
}

The way the decorators are generated didn't change in the output.

The effect in this case is that the att is undefined with 0.31.0 whereas with 0.30.0 the decorator would assign the value.

Versions:

Running ncc like so: npx @vercel/ncc@0.31.0 build .

rethab commented 2 years ago

I have identified why things were not working for me.

In my tsconfig.json, I use extends: my-base-config, where I define target: "es2019" as part of the compile options.

This project uses tsconfig-paths to resolve tsconfig, but that project has an issue which means it could never correctly resolve my tsconfig. It would just silently not load the parent. I have logged an issue about that here: https://github.com/dividab/tsconfig-paths/issues/182

Something seems to have changed with ncc version 0.31.0 which changed the default target and that now generates code that breaks my decorators. Looking at the changelog, I suspect this PR: https://github.com/vercel/ncc/pull/766

Eventually, I could reference the base config like so extends: my-base-config/tsconfig.json and that made it resolve correctly :)