Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ionic 4 mangles table names when using --prod #2164

Open
kunalgrover05 opened this issue May 17, 2018 · 23 comments
Open

Ionic 4 mangles table names when using --prod #2164

kunalgrover05 opened this issue May 17, 2018 · 23 comments

Comments

@kunalgrover05
Copy link

kunalgrover05 commented May 17, 2018

Issue type:

[ ] question
[x] bug report
[ ] feature request
[ ] documentation issue

Database system/driver:

[x] cordova
[ ] mongodb
[ ] mssql
[ ] mysql / mariadb
[ ] oracle
[ ] postgres
[ ] sqlite
[ ] sqljs
[ ] react-native

TypeORM version:

[x] latest
[x] @next
[ ] 0.x.x (or put your version here)

Steps to reproduce or a small repository showing the problem:
Can't make Ionic work using the --prod flag.
Everything works perfectly when using ionic cordova run android or ionic cordova run android --release but as soon as we add the --prod flag, things start to break.
My SQL queries show that all the Queries running look like FROM TABLE a irrespective of what model is being used.

I have tried the workaround suggested in Ionic example: https://github.com/typeorm/ionic-example

  • Using table name with Entity @Entity('user')
  • Getting the repository using the table name getRepository('user')
@pleerock
Copy link
Member

Using table name with Entity @Entity('user') must work.

@kunalgrover05
Copy link
Author

Doesn't :(
Can you suggest some way to debug what's wrong? This is kind of critical for me so I can put in some effort to find out a solution.

@pleerock
Copy link
Member

it must work. Are you sure its not your setup or any other issue? You have to provide a minimal reproduction code repo in the case if you can't find a resolution.

@kunalgrover05
Copy link
Author

Also confirmed with ionic-example repository that I am able to reproduce the same problem. Observations which are common across both my app and ionic-example.

  • The tables are used as "a" or "n" for all SELECT statements
query:  SELECT "n"."id" AS "n_id", "n"."name" AS "n_name" FROM "category" "n" WHERE (("n"."id" = ?) OR ("n"."id" = ?)) -- PARAMETERS: [1,2]
  • Error received when trying to save Post in the Ionic-example.
Uncaught (in promise): Error: Cyclic dependency: "n"
  • INSERTs work when the table does not have any foreign key. In the Ionic-example, if I try to save Category and Author separately they work, but whenever I try to save Post it fails.
query:  INSERT INTO "category"("name") VALUES (?) -- PARAMETERS: ["Programming"]

I believe what is happening is in some queries tables get renamed to "a" and it fails since there's a cyclic dependency between the Table we are creating data and the FK relation.

@pleerock
Copy link
Member

One of solutions is to disable mangling in your uglify options.

@cjackson234
Copy link

I'm getting the exact same error on save.

Error received when trying to save Post in the Ionic-example.
Uncaught (in promise): Error: Cyclic dependency: "n"

@kunalgrover05
Copy link
Author

@pleerock You are right, I was able to solve the issue by disabling mangling using custom uglify options.

Described here: https://ionicframework.com/docs/developer-resources/app-scripts/

@cjackson234
Copy link

It also works if you disable uglify altogether. But is there an option where mangle can stay enabled? If its the relationship, can we pass the entity name like you can for the table name in @entity?

@pleerock
Copy link
Member

@cjackson234 I don't know all issues you might face after magnification, so you might try that. Also disabling mangle practically doesn't affect your bundle size so much, so maybe its easier to simply disable it then keep maintaining names in your entities.

@cjackson234
Copy link

The reason I don't want to do that is that my application is electron based. I don't want my code to be easily read.

@pleerock
Copy link
Member

Just disabling mangling won't make it easily readable =)

@AmirTugi
Copy link
Contributor

@pleerock Is there a solution/ a tool for checking that cyclic dependency with the mangle option?
I still want to use the uglify ability.

@pleerock
Copy link
Member

But you do have uglify ability with even disabled mangle option, right? How much disabling mangle safes you? Few bytes?

@AmirTugi
Copy link
Contributor

AmirTugi commented Jul 11, 2018 via email

@dottodot
Copy link

Same applies for Nativescript, you have to disable mangle in the webpack config

@simmue
Copy link

simmue commented May 23, 2019

Same problem here. Is this still an open issue?
When saving an entity with relations, I get

Error: Cyclic dependency: "t"

This problem only occurs when building production.
Can anyone show me, where and how to disable the uglify / mingle options?

This is my package file, but it doesn't work:

var webpack = require("webpack");
var ionicWebpackFactory = require(process.env.IONIC_WEBPACK_FACTORY);

var ModuleConcatPlugin = require("webpack/lib/optimize/ModuleConcatenationPlugin");
var PurifyPlugin = require("@angular-devkit/build-optimizer").PurifyPlugin;
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");

var useDefaultConfig = require("@ionic/app-scripts/config/webpack.config.js");

useDefaultConfig.dev.plugins = [
  ionicWebpackFactory.getIonicEnvironmentPlugin(),
  ionicWebpackFactory.getCommonChunksPlugin(),
  new webpack.NormalModuleReplacementPlugin(/typeorm$/, function(result) {
    result.request = result.request.replace(/typeorm/, "typeorm/browser");
  }),
  new webpack.ProvidePlugin({
    "window.SQL": "sql.js/js/sql.js"
  })
];

useDefaultConfig.prod.plugins = [
  ionicWebpackFactory.getIonicEnvironmentPlugin(),
  ionicWebpackFactory.getCommonChunksPlugin(),
  new ModuleConcatPlugin(),
  new PurifyPlugin(),
  new webpack.NormalModuleReplacementPlugin(/typeorm$/, function(result) {
    result.request = result.request.replace(/typeorm/, "typeorm/browser");
  })
];

useDefaultConfig.optimization = function() {
  return {
    minimizer: [
      new UglifyJsPlugin({
        uglifyOptions: {
          mangle: false
        }
      })
    ]
  };
};

module.exports = function() {
  return useDefaultConfig;
};

Ionic 3 with TypeORM 0.2.17

@simmue
Copy link

simmue commented May 23, 2019

@pleerock You are right, I was able to solve the issue by disabling mangling using custom uglify options.

Described here: https://ionicframework.com/docs/developer-resources/app-scripts/

I found the solution by disabling the mangling. The link above is invalid. Use this one instead:
https://ionicframework.com/docs/v3/developer-resources/app-scripts/

  1. Create a new file under ./config/uglifyjs.config
  2. Copy paste the following content
module.exports = {
  /**
   * mangle: uglify 2's mangle option
   */
  mangle: false,

  /**
   * compress: uglify 2's compress option
   */
  compress: {
    toplevel: true,
    pure_getters: true
  }
};
  1. Add the path to the file under package.json like this:
....
 "config": {
    "ionic_uglifyjs": "./config/uglifyjs.config.js"
  },
...

@ikosta
Copy link

ikosta commented Jan 16, 2020

You can also put the class names of the entities to the mangle reserved option. So you don't have to get completely rid of the mangle stuff.

module.exports = {
  /**
   * mangle: uglify 2's mangle option
   */
  mangle: {
    reserved: ["Contact", "ContactList"]
  },

  /**
   * compress: uglify 2's compress option
   */
  compress: {
    toplevel: true,
    pure_getters: true
  }
};

@meddario
Copy link

meddario commented Jan 2, 2021

Hi all,

If someone happens to have the same problem on a Ionic 5 project with vue.js, i managed to solve this adding this to vue.config.js (create it if you don't have it, it wasn't there by default):

module.exports = {
  chainWebpack: config => {
    if (process.env.NODE_ENV === 'production') {
      config.optimization.minimizer('terser').tap((args) => {
        // see https://cli.vuejs.org/guide/webpack.html#chaining-advanced
        // https://cli.vuejs.org/migrating-from-v3/#vue-cli-service
        //   => chainWebpack for a chain override example
        // https://github.com/terser/terser#minify-options for terser options
        const terserOptions = args[0].terserOptions
        // Avoid to mangle entities (leads to query errors)
        terserOptions["keep_classnames"] = true
        terserOptions["keep_fnames"] = true
        // console.log(JSON.stringify(args[0], null, 2))
        return args
      })
    }
  },
  // ...rest of your vue.config.js...
}

(I left in the code some comments with useful links for the options.)

The solutions with config_*, like the one in the previous comment #2164 (comment) don't seem to work for Ionic 5 - vue.js.

Cheers.

@imnotjames
Copy link
Contributor

I can't replicate with the ionic example

When opening an issue, people will be better able to provide help if you provide code that they can easily understand and use to reproduce the problem. This boils down to ensuring your code that reproduces the problem follows the following guidelines:

  • Minimal – Use as little code as possible that still produces the same problem
  • Complete – Provide all parts someone else needs to reproduce your problem in the question itself
  • Reproducible – Test the code you're about to provide to make sure it reproduces the problem

Minimal

The more code there is to go through, the less likely people can find your problem. Streamline your example in one of two ways:

  1. Restart from scratch. Create a new program, adding in only what is needed to see the problem. Use simple, descriptive names for functions and variables – don’t copy the names you’re using in your existing code.
  2. Divide and conquer. If you’re not sure what the source of the problem is, start removing code a bit at a time until the problem disappears – then add the last part back.

Don't sacrifice clarity for brevity when creating a minimal example. Use consistent naming and indentation, and include code comments if needed. Use your code editor’s shortcut for formatting code.

Don't include any passwords or credentials that must be kept secret.

Complete

Make sure all information necessary to reproduce the problem is included in the issue itself.

If the problem requires some code as well as some XML-based configuration, include code for both. The problem might not be in the code that you think it is in.

Use individual code blocks for each file or snippet you include. Provide a description for the purpose of each block.

DO NOT use images of code. Copy the actual text from your code editor, paste it into the issus, then format it as code. This helps others more easily read and test your code.

Reproducible

To help you solve your problem, others will need to verify that it exists.

Describe the problem. "It doesn't work" isn't descriptive enough to help people understand your problem. Instead, tell other readers what the expected behavior should be. Tell other readers what the exact wording of the error message is, and which line of code is producing it. Use a brief but descriptive summary of your problem as the title of your question.

Eliminate any issues that aren't relevant to the problem. If your question isn’t about a compiler error, ensure that there are no compile-time errors.

Double-check that your example reproduces the problem! If you inadvertently fixed the problem while composing the example but didn't test it again, you'd want to know that before asking someone else to help.

@nirajhinge
Copy link

Hi all,

If someone happens to have the same problem on a Ionic 5 project with vue.js, i managed to solve this adding this to vue.config.js (create it if you don't have it, it wasn't there by default):

module.exports = {
  chainWebpack: config => {
    if (process.env.NODE_ENV === 'production') {
      config.optimization.minimizer('terser').tap((args) => {
        // see https://cli.vuejs.org/guide/webpack.html#chaining-advanced
        // https://cli.vuejs.org/migrating-from-v3/#vue-cli-service
        //   => chainWebpack for a chain override example
        // https://github.com/terser/terser#minify-options for terser options
        const terserOptions = args[0].terserOptions
        // Avoid to mangle entities (leads to query errors)
        terserOptions["keep_classnames"] = true
        terserOptions["keep_fnames"] = true
        // console.log(JSON.stringify(args[0], null, 2))
        return args
      })
    }
  },
  // ...rest of your vue.config.js...
}

(I left in the code some comments with useful links for the options.)

The solutions with config_*, like the one in the previous comment #2164 (comment) don't seem to work for Ionic 5 - vue.js.

Cheers.

I finally got the migration after adding this in the root as well. Thank you!

@guilherme-gm
Copy link

guilherme-gm commented Aug 11, 2021

Not related to Ionic, but may help someone as I ended up here while looking for a solution for my case:

I had the same issue in a project using Vue/Electron and couldn't figure out a way to solve the mangling issue, after several hours, I ended up with this hacky (and quite unsafe type-wise) solution, but so far it is working:

Migration:

// @ts-nocheck
import { MigrationInterface, QueryRunner, Table } from 'typeorm';

export let classes = {}; // <- this and ts-nocheck is important
classes['CreatePersonTable1627234546000'] = class implements MigrationInterface {
}

Migration List:

// @ts-nocheck
import { classes as CreatePersonTable1627234546000 } from "./1627234546000_CreatePersonTable";

export const MigrationList = [
	CreatePersonTable1627234546000['CreatePersonTable1627234546000'],
];

I am not sure if my explanation is correct, it is a total guess, but:
by using classes as an empty object, TS can't infer its type, and so webpack or whatever is mangling can't tell for sure that this string may be mangled. The ts-nocheck is required because everything here is unsafe. The migration list will get the constructor as expected, but it is behind that index that is not known by TS, so we have to ts-nocheck it too.

@joecodecreations
Copy link

Hi all,

If someone happens to have the same problem on a Ionic 5 project with vue.js, i managed to solve this adding this to vue.config.js (create it if you don't have it, it wasn't there by default):

module.exports = {
  chainWebpack: config => {
    if (process.env.NODE_ENV === 'production') {
      config.optimization.minimizer('terser').tap((args) => {
        // see https://cli.vuejs.org/guide/webpack.html#chaining-advanced
        // https://cli.vuejs.org/migrating-from-v3/#vue-cli-service
        //   => chainWebpack for a chain override example
        // https://github.com/terser/terser#minify-options for terser options
        const terserOptions = args[0].terserOptions
        // Avoid to mangle entities (leads to query errors)
        terserOptions["keep_classnames"] = true
        terserOptions["keep_fnames"] = true
        // console.log(JSON.stringify(args[0], null, 2))
        return args
      })
    }
  },
  // ...rest of your vue.config.js...
}

(I left in the code some comments with useful links for the options.)

The solutions with config_*, like the one in the previous comment #2164 (comment) don't seem to work for Ionic 5 - vue.js.

Cheers.

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests