Sequelize-typescript: [Help Wanted] How to define modelPath for transpiled with webpack ts code into single js file?

Created on 26 Feb 2019  路  6Comments  路  Source: RobinBuschmann/sequelize-typescript

I'm using a webpack to transpile my ts code into js because of some circumstances (for Angular Server Side Rendering) and because webpack transpile all models into single file I can't really define path to it from original file. And I have to define every single model by myself.

// ./api/service/Database.ts
import { Sequelize } from 'sequelize-typescript';

import { join } from 'path';

const sequelize =  new Sequelize({
  //configs
});

sequelize.addModels([join(__dirname, '../models')]);
...
// ./webpack.server.config.js
const path = require('path');
const webpack = require('webpack');
const nodeExternals = require('webpack-node-externals');

module.exports = {
  entry: {  server: './server.ts' },
  resolve: {
    extensions: ['.js', '.ts']
  },
  target: 'node',
  // this makes sure we include node_modules and other 3rd party libraries
  externals: [nodeExternals()],
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].js'
  },
  module: {
    rules: [
      { test: /\.ts$/, loader: 'ts-loader' }
    ]
  },
  plugins: [
    // Temporary Fix for issue: https://github.com/angular/angular/issues/11580
    // for "WARNING Critical dependency: the request of a dependency is an expression"
    new webpack.ContextReplacementPlugin(
      /(.+)?angular(\\|\/)core(.+)?/,
      path.join(__dirname, 'src'), // location of your src
      {} // a map of your routes
    ),
    new webpack.ContextReplacementPlugin(
      /(.+)?express(\\|\/)(.+)?/,
      path.join(__dirname, 'src'),
      {}
    )
  ],
  optimization: {
    // keep minimization off
    // workaround for https://github.com/angular/angular-cli/issues/10635
    minimize: false
  }
}

Expected Behavior

Expected that webpack transpile this line sequelize.addModels([join(__dirname, '../models')]); into something like this sequelize.addModels([Object(path__WEBPACK_IMPORTED_MODULE_1__["join"])(__dirname, './')]); and this transpiled function will add all models which looks like that

let User_User = class User extends external_sequelize_typescript_["Model"] {
};
external_tslib_["__decorate"]([
    Object(external_sequelize_typescript_["IsUUID"])(4),
    Object(external_sequelize_typescript_["Default"])(external_sequelize_typescript_["DataType"].UUIDV4),
    external_sequelize_typescript_["PrimaryKey"],
    Object(external_sequelize_typescript_["Column"])({
        type: external_sequelize_typescript_["DataType"].UUID
    }),
    external_tslib_["__metadata"]("design:type", String)
], User_User.prototype, "uuid", void 0);
external_tslib_["__decorate"]([
    Object(external_sequelize_typescript_["AllowNull"])(false),
    external_sequelize_typescript_["IsEmail"],
    external_sequelize_typescript_["Column"],
    external_tslib_["__metadata"]("design:type", String)
], User_User.prototype, "email", void 0);
external_tslib_["__decorate"]([
    Object(external_sequelize_typescript_["AllowNull"])(false),
    external_sequelize_typescript_["Column"],
    external_tslib_["__metadata"]("design:type", String)
], User_User.prototype, "name", void 0);
external_tslib_["__decorate"]([
    Object(external_sequelize_typescript_["AllowNull"])(false),
    Object(external_sequelize_typescript_["Is"])(/^\$(2[ayb]?)\$([0-9]{1,2})\$([A-Za-z0-9.\/]{53,54})$/) // is bcrypt hash
    ,
    Object(external_sequelize_typescript_["Column"])(external_sequelize_typescript_["DataType"].STRING(60)),
    external_tslib_["__metadata"]("design:type", String)
], User_User.prototype, "hash", void 0);
User_User = external_tslib_["__decorate"]([
    Object(external_sequelize_typescript_["Table"])({ tableName: 'user', modelName: 'user' })
], User_User);

Actual Behavior

Webpack transpile sequelize.addModels([join(__dirname, '../models')]) into sequelize.addModels([Object(path__WEBPACK_IMPORTED_MODULE_1__["join"])(__dirname, './models')]) and when application tries create a model, it throws the error

ERROR: Cannot read property 'createdAt' of undefined
  TypeError: Cannot read property 'createdAt' of undefined
    at User._initValues (/node_modules/sequelize/lib/model.js:3123:49)
    at new Model (/node_modules/sequelize/lib/model.js:3097:10)
    at new Model (/node_modules/sequelize-typescript/lib/models/v4/Model.js:8:9)
    at new User (/dist/server.js:2025:17)
    at /dist/server.js:2140:16
    at Generator.next (<anonymous>)
    at /node_modules/tslib/tslib.js:107:75
    at new ZoneAwarePromise (/node_modules/zone.js/dist/zone-node.js:891:29)
    at Object.__awaiter (/node_modules/tslib/tslib.js:103:16)
    at router.get.asyncHandler (/dist/server.js:2138:90)
    at /dist/server.js:2083:18
    at Layer.handle [as handle_request] (/node_modules/express/lib/router/layer.js:95:5)
    at next (/node_modules/express/lib/router/route.js:137:13)
    at Route.dispatch (/node_modules/express/lib/router/route.js:112:3)
    at Layer.handle [as handle_request] (/node_modules/express/lib/router/layer.js:95:5)
    at /node_modules/express/lib/router/index.js:281:22
    at param (/node_modules/express/lib/router/index.js:354:14)
    at param (/node_modules/express/lib/router/index.js:365:14)
    at Function.process_params (/node_modules/express/lib/router/index.js:410:3)
    at next (/node_modules/express/lib/router/index.js:275:10)
    at Function.handle (/node_modules/express/lib/router/index.js:174:3)
    at router (/node_modules/express/lib/router/index.js:47:12)

Even set transpiled part of the path to (__dirname, './') manually doesn't actually do anything.

Can anyone advice how to achieve this feature?

Most helpful comment

I'm running into the same error. I'm solving it by using require.context. The following code is working for my project.

const REG_CATCH_NAME = /([^\/\.]+)\.tsx?$/;

function getModelNameByPath(path: string) {
    const groups = REG_CATCH_NAME.exec(path);
    if (!groups || groups.length < 2) {
        console.error('Sequelize: Error in parsing model path: ', path);
        return null;
    }
    return groups[1];
}

// webpack require context
// @ts-ignore
const req = require.context('./models', true, /\.tsx?$/);
const models = req
    .keys()
    .map(key => {
        const modelName = getModelNameByPath(key);
        if (modelName) {
            console.log('Sequelize: Load model: ', modelName);
            return req(key)[modelName];
        }
        return null;
    })
    .filter(each => !!each);

sequelize.addModels(models);

All 6 comments

Hey @someApprentice, I'm not much experienced in webpack. But I think, unless there isn't already a plugin, you need to write your own for that. Or instead of using paths for loading the models, use references like so: sequelize.addModels([YourModelA, YourModelB, ...])

@RobinBuschmann Okay, I guess issue can keep open until someone suggest solution or I'm not found it by myself.

I'm running into the same error. I'm solving it by using require.context. The following code is working for my project.

const REG_CATCH_NAME = /([^\/\.]+)\.tsx?$/;

function getModelNameByPath(path: string) {
    const groups = REG_CATCH_NAME.exec(path);
    if (!groups || groups.length < 2) {
        console.error('Sequelize: Error in parsing model path: ', path);
        return null;
    }
    return groups[1];
}

// webpack require context
// @ts-ignore
const req = require.context('./models', true, /\.tsx?$/);
const models = req
    .keys()
    .map(key => {
        const modelName = getModelNameByPath(key);
        if (modelName) {
            console.log('Sequelize: Load model: ', modelName);
            return req(key)[modelName];
        }
        return null;
    })
    .filter(each => !!each);

sequelize.addModels(models);

@someApprentice Can you confirm that @gogoout's solution works?

Closing this due to inactivity

@someApprentice Can you confirm that @gogoout's solution works?

Not OP, but this solution worked for me, with a slight change.

Since I'm exporting my modules as default export, I need to change the line
return req(key)[modelName];
to
return req(key).default;

Was this page helpful?
0 / 5 - 0 ratings

Related issues

samanmohamadi picture samanmohamadi  路  5Comments

lverledens picture lverledens  路  4Comments

thestrayed picture thestrayed  路  5Comments

CampaUTN picture CampaUTN  路  4Comments

YaroslavOsetrov picture YaroslavOsetrov  路  3Comments