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

Sequelize with Sequelize-typescript decorators does not work after upgrading Vite from 2.4.4 to v2.5.1 #4727

Closed
7 tasks done
pixelspark opened this issue Aug 25, 2021 · 3 comments · Fixed by #4749
Closed
7 tasks done
Labels
documentation Improvements or additions to documentation

Comments

@pixelspark
Copy link

pixelspark commented Aug 25, 2021

Describe the bug

After upgrading vite from 2.4.4 to 2.5.1, Sequelize (an ORM) will not properly hydrate objects retrieved from the database. This is while using sequelize-typescript, which is a package that allows to define ORM mappings using decorators/annotations, like so:

/** A user account - an account can be logged in through using a credential (see below). */
@Table({ modelName: "account", tableName: "account", timestamps: true, underscored: true, version: true })
export class Account extends Model {
	@Column({ primaryKey: true, autoIncrement: true, type: DataType.BIGINT })
	public id: string | null = null;

As these decorators are kind of non-standard, my gut feeling is something changed here that causes sequelize to fail. However, looking at the generated source code (after turning minification off) there seems to be little change to how my code is compiled. Below shows main.js produced by vite without minification:

diff ~/Desktop/main_v244.js ~/Desktop/main_v251.js 
20a21,24
> var __publicField = (obj, key, value) => {
>   __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
>   return value;
> };
29,30c33,34
< var vendor = require("./assets/vendor.0e6570d6.js");
< var blueprints = require("./assets/blueprints.150599a6.js");
---
> var vendor = require("./assets/vendor.d9351f9c.js");
> var blueprints = require("./assets/blueprints.5a1245c5.js");
102a107,111
>   constructor() {
>     super(...arguments);
>     __publicField(this, "document");
>     __publicField(this, "hostname");
>   }
170,178c179,187
<     this.documentID = null;
<     this.title = "";
<     this.expandedByDefault = false;
<     this.expanded = false;
<     this.fill = ItemFill.None;
<     this.showNavigation = true;
<     this.children = [];
<     this.childrenNavigationType = NavigationType.List;
<     this.nestNavigation = false;
---
>     __publicField(this, "documentID", null);
>     __publicField(this, "title", "");
>     __publicField(this, "expandedByDefault", false);
>     __publicField(this, "expanded", false);
>     __publicField(this, "fill", ItemFill.None);
>     __publicField(this, "showNavigation", true);
>     __publicField(this, "children", []);
>     __publicField(this, "childrenNavigationType", NavigationType.List);
>     __publicField(this, "nestNavigation", false);
215,230c224,239
<     this.items = [];
<     this.backgroundColor = _Dashboard.defaults.backgroundColor;
<     this.navigationBackgroundColor = _Dashboard.defaults.navigationBackgroundColor;
<     this.navigationSelectedColor = _Dashboard.defaults.navigationSelectedColor;
<     this.navigationSiblingSelectedColor = _Dashboard.defaults.navigationSiblingSelectedColor;
<     this.navigationSelectedTextColor = _Dashboard.defaults.navigationSelectedTextColor;
<     this.navigationTextColor = _Dashboard.defaults.navigationTextColor;
<     this.themeColors = JSON.parse(JSON.stringify(_Dashboard.defaults.themeColors));
<     this.navigationFontSizes = _Dashboard.defaults.navigationFontSizes;
<     this.headerType = _Dashboard.defaults.headerType;
<     this.fixedWidth = _Dashboard.defaults.fixedWidth;
<     this.hideHeaderInDesignMode = _Dashboard.defaults.hideHeaderInDesignMode;
<     this.favIcon = _Dashboard.defaults.favIcon;
<     this.navigationFilled = false;
<     this.headerDocumentID = null;
<     this.headerHeight = _Dashboard.defaults.headerHeight;
---
>     __publicField(this, "items", []);
>     __publicField(this, "backgroundColor", _Dashboard.defaults.backgroundColor);
>     __publicField(this, "navigationBackgroundColor", _Dashboard.defaults.navigationBackgroundColor);
>     __publicField(this, "navigationSelectedColor", _Dashboard.defaults.navigationSelectedColor);
>     __publicField(this, "navigationSiblingSelectedColor", _Dashboard.defaults.navigationSiblingSelectedColor);
>     __publicField(this, "navigationSelectedTextColor", _Dashboard.defaults.navigationSelectedTextColor);
>     __publicField(this, "navigationTextColor", _Dashboard.defaults.navigationTextColor);
>     __publicField(this, "themeColors", JSON.parse(JSON.stringify(_Dashboard.defaults.themeColors)));
>     __publicField(this, "navigationFontSizes", _Dashboard.defaults.navigationFontSizes);
>     __publicField(this, "headerType", _Dashboard.defaults.headerType);
>     __publicField(this, "fixedWidth", _Dashboard.defaults.fixedWidth);
>     __publicField(this, "hideHeaderInDesignMode", _Dashboard.defaults.hideHeaderInDesignMode);
>     __publicField(this, "favIcon", _Dashboard.defaults.favIcon);
>     __publicField(this, "navigationFilled", false);
>     __publicField(this, "headerDocumentID", null);
>     __publicField(this, "headerHeight", _Dashboard.defaults.headerHeight);
368c377
< Dashboard.defaults = {
---
> __publicField(Dashboard, "defaults", {
389c398
< };
---
> });
628c637
<     this.data = { metadata: { title: "", type: defaultMimeType } };
---
>     __publicField(this, "data", { metadata: { title: "", type: defaultMimeType } });
746c755
< Migrator.migrations = {
---
> __publicField(Migrator, "migrations", {
830c839
< };
---
> });
875a885
>     __publicField(this, "sessionID");
932a943
>     __publicField(this, "userInfoRequests", {});
934d944
<     this.userInfoRequests = {};
1829,1830c1839,1840
<     this.segments = [];
<     this.stack = [];
---
>     __publicField(this, "segments", []);
>     __publicField(this, "stack", []);
2049a2060,2064
>     __publicField(this, "highchartsExportServerURL");
>     __publicField(this, "gen");
>     __publicField(this, "widthInInches");
>     __publicField(this, "heightInInches");
>     __publicField(this, "expressionContext");
3947a3963,3973
>     __publicField(this, "info");
>     __publicField(this, "gossip", null);
>     __publicField(this, "documentSession");
>     __publicField(this, "body");
>     __publicField(this, "sessionContext");
>     __publicField(this, "isEditing");
>     __publicField(this, "messageQueue", []);
>     __publicField(this, "documentWasDeleted", false);
>     __publicField(this, "documentWasModifiedByUser", false);
>     __publicField(this, "state", InteractionState.New);
>     __publicField(this, "interactionID");
3949,3953d3974
<     this.gossip = null;
<     this.messageQueue = [];
<     this.documentWasDeleted = false;
<     this.documentWasModifiedByUser = false;
<     this.state = InteractionState.New;
4251c4272
< Interaction.interactionCounter = 0;
---
> __publicField(Interaction, "interactionCounter", 0);
4253a4275,4278
>     __publicField(this, "isClosed", false);
>     __publicField(this, "onCloseHandler", null);
>     __publicField(this, "onMessageHandler", null);
>     __publicField(this, "queuedMessages", []);
4256,4259d4280
<     this.isClosed = false;
<     this.onCloseHandler = null;
<     this.onMessageHandler = null;
<     this.queuedMessages = [];
4307a4329,4333
>     __publicField(this, "channels", new Map());
>     __publicField(this, "usedChannelNumbers", new Set());
>     __publicField(this, "session");
>     __publicField(this, "pingInterval", null);
>     __publicField(this, "lastPong", null);
4310,4313d4335
<     this.channels = new Map();
<     this.usedChannelNumbers = new Set();
<     this.pingInterval = null;
<     this.lastPong = null;

If the problem is not in the changes above, then the issue might be with compiling the sequelize/sequelize-typescript packages...

Reproduction

Use sequelize-typescript and build with Vite 2.5.1. Models will not hydrate.

Then, revert back to Vite 2.4.1 (npm install [email protected]). Verify that ESbuild is still the most recent version:

Verify only vite was changed by looking at package-lock.json diff:

diff --git a/package-lock.json b/package-lock.json
index 30f039cd95f8c572bced0c56f6ebe23268bc7230..e38468dcfec9282d7cdf103f5ed2ba98ed790f93 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5886,12 +5886,12 @@
 			}
 		},
 		"vite": {
-			"version": "2.5.1",
-			"resolved": "https://registry.npmjs.org/vite/-/vite-2.5.1.tgz",
-			"integrity": "sha512-FwmLbbz8MB1pBs9dKoRDgpiqoijif8hSK1+NNUYc12/cnf+pM2UFhhQ1rcpXgbMhm/5c2USZdVAf0FSkSxaFDA==",
+			"version": "2.4.4",
+			"resolved": "https://registry.npmjs.org/vite/-/vite-2.4.4.tgz",
+			"integrity": "sha512-m1wK6pFJKmaYA6AeZIUXyiAgUAAJzVXhIMYCdZUpCaFMGps0v0IlNJtbmPvkUhVEyautalajmnW5X6NboUPsnw==",
 			"dev": true,
 			"requires": {
-				"esbuild": "^0.12.17",
+				"esbuild": "^0.12.8",
 				"fsevents": "~2.3.2",
 				"postcss": "^8.3.6",
 				"resolve": "^1.20.0",

Build again, problem disappears!

my tsconfig.json:

{
	"compilerOptions": {
		"target": "esnext",
		"module": "esnext",
		"moduleResolution": "node",
		"strict": true,
		"jsx": "preserve",
		"sourceMap": true,
		"lib": ["esnext", "dom"],
		"types": ["vite/client"],
		"plugins": [{ "name": "@vuedx/typescript-plugin-vue" }],
		"noImplicitAny": true,
		"allowJs": true,
		"strictNullChecks": true,
		"forceConsistentCasingInFileNames": true,
		"noImplicitReturns": true,
		"noUnusedLocals": true,
		"experimentalDecorators": true,
		"emitDecoratorMetadata": true,
		"resolveJsonModule": true,
		"allowSyntheticDefaultImports": true,
		"esModuleInterop": true,
		"skipLibCheck": true
	},
	"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "tests/**/*.ts"],
	"exclude": ["node_modules"]
}

Vite config:

import { defineConfig } from "vite";
import { resolve } from "path";
import vue from "@vitejs/plugin-vue";

const serverSideDeps = [
	"archiver", "canvas", "cookie", "express", "form-data", "jsdom", "ip",
	"mustache-express", "mysql", "mysql2", "node-fetch", "node-sql-parser", "pptxgenjs", "redis",
	"reflect-metadata", "sequelize", "sequelize-typescript", "body-parser", "ajv", "base-58",
	"cardinal", "https", "pg-hstore", "tedious", "url", "mariadb", "gradient-parser", "ws",
	"pngjs", "pixelmatch", "sqlstring", "nodemailer", "canvg", "xmldom"
];

export default defineConfig({
	plugins: [vue()],
	assetsInclude: [/\.csv$/],
	publicDir: "public/server",

	build: {
		sourcemap: true,
		brotliSize: false,
		outDir: "dist/server",
		assetsInlineLimit: 0,
		cssCodeSplit: false,

		/* Set to "esbuild" because it is faster (also consistent with client, see client config) 
		See https://github.com/vitejs/vite/issues/3363 */
		minify: false,
		chunkSizeWarningLimit: 2048,
		rollupOptions: {
			output: {
				format: "cjs",
				entryFileNames: '[name].js'
			},

			input: {
				"main": resolve(__dirname, "src/server/main.ts"),
				"test": resolve(__dirname, "tests/main.ts")
			},

			// Several server-only dependencies or node-internal packages that should not be bundled
			external: [ "fs", "pg-native", "os", "path", "dns",
				"crypto", "cluster", "http", "vega-lite", "vega", "highcharts", "vue", "topojson-client", "vue-i18n",
				"fast-json-patch", ...serverSideDeps]
		},

		terserOptions: {
			mangle: false,
			compress: false
		}
	},

	optimizeDeps: {
		exclude: [
			"@dialogic/merlion",

			// Server-side dependencies can be left out
			...serverSideDeps
		],
		include: [
			"parse-color", "parsimmon", "gradient-parser" // Merlion dependencies
		]
	}
});

Setting up a minimal test case is a bit of work, but please let me know if that's necessary, will be happy to provide a test case.

System Info

With Vite 2.4.4 (working):

  System:
    OS: macOS 11.5.2
    CPU: (8) x64 Intel(R) Core(TM) i7-4980HQ CPU @ 2.80GHz
    Memory: 1001.20 MB / 16.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 14.16.1 - /usr/local/bin/node
    npm: 6.14.12 - /usr/local/bin/npm
  Browsers:
    Chrome: 92.0.4515.159
    Edge: 92.0.902.73
    Firefox: 92.0
    Firefox Nightly: 58.0a1
    Safari: 14.1.2
    Safari Technology Preview: 15.0
  npmPackages:
    @vitejs/plugin-vue: ^1.6.0 => 1.6.0 
    vite: 2.4.4 => 2.4.4 

With vite 2.5.1 (not working):

  System:
    OS: macOS 11.5.2
    CPU: (8) x64 Intel(R) Core(TM) i7-4980HQ CPU @ 2.80GHz
    Memory: 817.62 MB / 16.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 14.16.1 - /usr/local/bin/node
    npm: 6.14.12 - /usr/local/bin/npm
  Browsers:
    Chrome: 92.0.4515.159
    Edge: 92.0.902.73
    Firefox: 92.0
    Firefox Nightly: 58.0a1
    Safari: 14.1.2
    Safari Technology Preview: 15.0
  npmPackages:
    @vitejs/plugin-vue: ^1.6.0 => 1.6.0 
    vite: ^2.5.1 => 2.5.1 

Used Package Manager

npm

Logs

Vite build works fine. The Sequelize symptoms show up in my application as follows as follows:

Executing (default): SELECT `id`, `display_name` AS `displayName`, `locale`, `is_verified` AS `isVerified`, `interface_style` AS `interfaceStyle`, `created_at` AS `createdAt`, `updated_at` AS `updatedAt`, `version`, `created_by_account_id`, `default_group_id` FROM `account` AS `account` WHERE `account`.`id` = 1;
{
  storedAccount: account {
    dataValues: {
      id: 1,
      displayName: '(redacted)',
      locale: 'nl',
      isVerified: false,
      interfaceStyle: 'light',
      createdAt: 2020-12-31T14:47:59.000Z,
      updatedAt: 2021-06-22T15:08:48.000Z,
      version: 96,
      created_by_account_id: null,
      default_group_id: null
    },
    _previousDataValues: {
      id: 1,
      displayName: '(redacted)',
      locale: 'nl',
      isVerified: false,
      interfaceStyle: 'light',
      createdAt: 2020-12-31T14:47:59.000Z,
      updatedAt: 2021-06-22T15:08:48.000Z,
      version: 96,
      created_by_account_id: null,
      default_group_id: null
    },
    _changed: Set(0) {},
    _options: {
      isNewRecord: false,
      _schema: null,
      _schemaDelimiter: '',
      raw: true,
      attributes: [Array]
    },
    isNewRecord: false,
    id: null,
    displayName: undefined,
    locale: undefined,
    isVerified: undefined,
    interfaceStyle: undefined,
    credentials: undefined,
    createdBy: undefined,
    memberOfGroups: undefined,
    defaultGroup: undefined
  }
}

Notice in the above that the fields (e.g. displayName) are undefined whereas Sequelize does manage to fetch the data (in dataValues) from the database.

Validations

@haoqunjiang
Copy link
Member

Try adding "useDefineForClassFields": false to compilerOptions in tsconfig.json.

@pixelspark
Copy link
Author

"useDefineForClassFields": false

Brilliant, that appears to fix it!

Now of course the question becomes, is this expected behaviour or not?

@haoqunjiang
Copy link
Member

It's an expected change, but poorly documented. I'm gonna submit a documentation PR tomorrow to address this.

@haoqunjiang haoqunjiang added documentation Improvements or additions to documentation and removed pending triage labels Aug 25, 2021
haoqunjiang added a commit to haoqunjiang/vite that referenced this issue Aug 26, 2021
@github-actions github-actions bot locked and limited conversation to collaborators Sep 10, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants